0

I wrote a function in Inno Setup Compiler 5.5.9a to try and change the TCP/IP port that MSSQL Server listens on.

function SetSqlTcpPort(port: Integer): Boolean;
var
  WbemLocator: Variant;
  WbemServices: Variant;
  WQLQuery: string;
  WbemObjectSet: Variant;
  i: Integer;
  tcpProperty: Variant;
  tcpNewValue: String;
begin
  result := false;

  WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  WbemServices := WbemLocator.ConnectServer('localhost', 'root\CIMV2');

  WQLQuery := 'SELECT * FROM ServerNetworkProtocolProperty ' +
             'WHERE InstanceName="{#SQL_INSTANCE_NAME}" AND ' +
             'ProtocolName="Tcp" AND ' +
             'IPAddressName="IPAll"';

  WbemObjectSet:= WbemServices.ExecQuery(WQLQuery);
  if (not VarIsNull(WbemObjectSet)) then
  begin
    if (WbemObjectSet.Count > 0) then
    begin
      for i := 0 to WbemObjectSet.Count - 1 do
      begin
        tcpProperty := WbemObjectSet.ItemIndex(i);
        if (not VarIsNull(tcpProperty)) then
        begin
          if (tcpProperty.PropertyName = 'TcpPort') then
          begin
            tcpNewValue := IntToStr(port);
          end
          else
          begin
            tcpNewValue := '';
          end;

          if (tcpProperty.SetStringValue(tcpNewValue) <> 0) then
          begin
            MsgBox('Error trying to set the new SQL TCP/IP port to ' + IntToStr(port) + '!  ' +
            'The property "' + tcpProperty.PropertyName + '" could not be set to "' + tcpNewValue + '".', mbCriticalError, MB_OK);
          end;
        end;
      end;
    end;
  end;
end;

I think I almost have it done but I'm running into an error on the following line...

if (WbemObjectSet.Count > 0) then

enter image description here

It seems like maybe the property .Count does not exist? Also the error says Exception: SWbemObjectSet: Invalid class, seems kinda weird that it would use the text SWbemObjectSet instead of WbemObjectSet.

Any ideas as to what I might be doing wrong?

EDIT #2

OK so I made a few changes to the script that seems to get past the issue I was having and this is what I came up with...

function GetSqlServerVersion: Integer;
var
  i: Integer;
  WbemLocator: Variant;
  WbemServices: Variant;
  service: String;
begin
  result := -1;

  for i := 4 downto 0 do
  begin
    //Test out the higher versions of SQL Server first
    case i of
      4: service := 'ComputerManagement13'; //SQL Server 2016
      3: service := 'ComputerManagement12'; //SQL Server 2014
      2: service := 'ComputerManagement11'; //SQL Server 2012
      1: service := 'ComputerManagement10'; //SQL Server 2008
      0: service := 'ComputerManagement'; //SQL Server 2005
    end;

    try
      //Try to connect to the wbem locator
      WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
      WbemServices := WbemLocator.ConnectServer('localhost', 'root\Microsoft\SqlServer\' + service);

      //Got a connection so lets use this one
      case i of
        0: result := 0; //SQL Server 2005
        1: result := 10; //SQL Server 2008
        2: result := 11; //SQL Server 2012
        3: result := 12; //SQL Server 2014
        4: result := 13; //SQL Server 2016
      end;

      //No need to continue because we found a good connection
      Exit;
    except
      //Got an error so that not a good connection
      result := -1;
    end;
  end; 
end;

function SetSqlTcpPort(port: Integer): Boolean;
var
  version: Integer;
  service: String;
  WbemLocator: Variant;
  WbemServices: Variant;
  WQLQuery: string;
  tcpProperties: Variant;
  i: Integer;
  tcpProperty: Variant;
  tcpNewValue: String;
  count: Integer;
begin
  result := false;

  version := GetSqlServerVersion;
  if (version > 0) then
  begin
    service := 'ComputerManagement' + IntToStr(version);
  end
  else if (version = 0) then
  begin
    service := 'ComputerManagement';
  end
  else
  begin
    MsgBox('There does not seem to be an SQL server installed on this system yet!  Tried connecting to SQL Server 2005, 2008, 2012, 2014, and 2016 to no avail.  Could not change the SQL TCP/IP Server port!', mbCriticalError, MB_OK);
    Exit;
  end;

  WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  WbemServices := WbemLocator.ConnectServer('localhost', 'root\Microsoft\SqlServer\' + service);

  WQLQuery := 'SELECT * FROM ServerNetworkProtocolProperty ' +
             'WHERE InstanceName="{#SQL_INSTANCE_NAME}" AND ' +
             'ProtocolName="Tcp" AND ' +
             'IPAddressName="IPAll"';

  tcpProperties:= WbemServices.ExecQuery(WQLQuery);
  if (not VarIsNull(tcpProperties)) then
  begin
    count:= Length(tcpProperties);  //ERROR IS HERE

    if (count > 0) then
    begin
      for i := 0 to count - 1 do
      begin
        tcpProperty := tcpProperties.ItemIndex(i);
        if (not VarIsNull(tcpProperty)) then
        begin
          if (tcpProperty.PropertyName = 'TcpPort') then
          begin
            tcpNewValue := IntToStr(port);
          end
          else
          begin
            tcpNewValue := '';
          end;

          if (tcpProperty.SetStringValue(tcpNewValue) <> 0) then
          begin
            MsgBox('Error trying to set the new SQL TCP/IP port to ' + IntToStr(port) + '!  ' +
            'The property "' + tcpProperty.PropertyName + '" could not be set to "' + tcpNewValue + '".', mbCriticalError, MB_OK);
          end;
        end;
      end;
    end;
  end;
end;

Now as you can see I have implemented a new function that tries to determine the version of SQL Server installed by trial and error. This works great but I still seem to be having an issue when it comes to getting the COUNT of objects returned from the ExecQuery method. I know this is returning EXACTLY what I want because I have used wbemtest.exe to run the query with perfect results.

The issue is from the line...

count:= Length(tcpProperties);

So currently the issue is...

How do I get the count of objects/elements that the method ExecQuery() has produced?

I have tried things like Count(tcpProperties), Length(tcpProperties), GetArrayLength(tcpProperties), etc but nothing I do will give me the number of items/rows/elements returned.

EDIT #3

So I upgraded to the Unicode version of Inno Setup and changed some code the Unicode version did not approve of. I thought all was going to be good and now I get this error..

enter image description here

Guess what line that is? Yep you guessed it, it happens on the following line...

count:= tcpProperties.Count;

As you can see from the below image when hovering over tcpProperties, it does not seem to be NULL or nil.

enter image description here

Suggestions?

EDIT #4 (Requested)

wbmetest.exe returns the following. This shows 2 objects just as I would expect the function to return.

enter image description here

Arvo Bowen
  • 4,524
  • 6
  • 51
  • 109
  • We cannot see whole query on the screenshot. + Maybe you should for now simplify your code to use literal queries (specific value instead of `SQL_INSTANCE_NAME`) and namespaces (get rid of the `GetSqlServerVersion`). – Martin Prikryl Feb 04 '17 at 06:36
  • It's the she exact query that is used in the original question... – Arvo Bowen Feb 04 '17 at 15:35

1 Answers1

0

How do I get the count of objects/elements that the method ExecQuery() has produced?

There's the .Count property. Exactly as your original code shows:

if tcpProperties.Count > 0 then

See some examples of handling results of WMI queries that return collections:

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • That does not work. I'm using inno (non-unicode). This solution will not work in inno. Those examples are using Unicode Inno Setup. – Arvo Bowen Feb 03 '17 at 12:42
  • Well, first you should not use the Ansi version of Inno Setup in any case. It's 21st century, the Unicode is a must! In any case, at least try the code in the Unicode version to verify it. I rather doubt the Ansi vs. Unicode matters in this case. – Martin Prikryl Feb 03 '17 at 13:12
  • Yea I already made that decision and I'm currently working to correct old code the new Unicode version doesn't like. – Arvo Bowen Feb 03 '17 at 14:35
  • So after the upgrade `.Count` still is giving me issues... See my updated question `EDIT #3`. – Arvo Bowen Feb 03 '17 at 14:51
  • Show us a screenshot of the `wbemtest` for the same query. – Martin Prikryl Feb 03 '17 at 16:38