Can you advice me how to get "Log On As" parameter of specific windows service? I need to re-register service in our upgrade project and it needs to be run under the same account as it was set up originally. I've found QueryServiceConfig in advapi32.dll with lpServiceStartName in returned structure but I am not able to make it work from Inno Setup.
Asked
Active
Viewed 1,819 times
2 Answers
5
You cannot use QueryServiceConfig
function from InnoSetup script. To use this function, you would have to allocate buffer from heap and that's impossible in InnoSetup. Instead you can use WMI, or to be more specific, the Win32_Service
WMI class, which contains the StartName
property, that you've asked for. In InnoSetup script it might look like this:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
function GetServiceStartName(const AServiceName: string): string;
var
WbemLocator: Variant;
WbemServices: Variant;
WbemObject: Variant;
WbemObjectSet: Variant;
begin;
Result := '';
WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
WbemServices := WbemLocator.ConnectServer('localhost', 'root\CIMV2');
WbemObjectSet := WbemServices.ExecQuery('SELECT * FROM Win32_Service ' +
'WHERE Name = "' + AServiceName + '"');
if not VarIsNull(WbemObjectSet) and (WbemObjectSet.Count > 0) then
begin
WbemObject := WbemObjectSet.Item('Win32_Service.Name="' +
AServiceName + '"');
if not VarIsNull(WbemObject) then
Result := WbemObject.StartName;
end;
end;
procedure SvcStartNameTestButtonClick(Sender: TObject);
begin
MsgBox(GetServiceStartName('Netlogon'), mbInformation, MB_OK);
end;
procedure InitializeWizard;
var
SvcStartNameTestButton: TNewButton;
begin
SvcStartNameTestButton := TNewButton.Create(WizardForm);
SvcStartNameTestButton.Parent := WizardForm;
SvcStartNameTestButton.Left := 8;
SvcStartNameTestButton.Top := WizardForm.ClientHeight -
SvcStartNameTestButton.Height - 8;
SvcStartNameTestButton.Width := 175;
SvcStartNameTestButton.Caption := 'Get service start name...';
SvcStartNameTestButton.OnClick := @SvcStartNameTestButtonClick;
end;
Quite easier (and probably faster) would be to make an external library and call it from the script. If you have Delphi or Lazarus, you can use the following function, which uses the QueryServiceConfig
function to get the lpServiceStartName
member, that you asked for:
function GetServiceStartName(const AServiceName: string): string;
var
BufferSize: DWORD;
BytesNeeded: DWORD;
ServiceHandle: SC_HANDLE;
ServiceManager: SC_HANDLE;
ServiceConfig: PQueryServiceConfig;
begin
Result := '';
ServiceManager := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if ServiceManager <> 0 then
try
ServiceHandle := OpenService(ServiceManager, PChar(AServiceName),
SERVICE_QUERY_CONFIG);
if ServiceHandle <> 0 then
try
if not QueryServiceConfig(ServiceHandle, nil, 0, BufferSize) and
(GetLastError = ERROR_INSUFFICIENT_BUFFER) then
begin
ServiceConfig := AllocMem(BufferSize);
try
if QueryServiceConfig(ServiceHandle, ServiceConfig, BufferSize,
BytesNeeded)
then
Result := ServiceConfig^.lpServiceStartName;
finally
FreeMem(ServiceConfig);
end;
end;
finally
CloseServiceHandle(ServiceHandle);
end;
finally
CloseServiceHandle(ServiceManager);
end;
end;

TLama
- 75,147
- 17
- 214
- 392
1
I didn't liked the idea of linking external library so I finally solved the problem this way:
function GetServiceLogonAs():string;
var
res : Integer;
TmpFileName, FileContent: String;
begin
TmpFileName := ExpandConstant('{tmp}') + '\Service_Info.txt';
Exec('cmd.exe', '/C sc qc "MyServiceName" > "' + TmpFileName + '"', '', SW_HIDE, ewWaitUntilTerminated, res);
if LoadStringFromFile(TmpFileName, FileContent) then
begin
Result := Trim(Copy(FileContent,Pos('SERVICE_START_NAME', FileContent)+20,Length(FileContent)-(Pos('SERVICE_START_NAME', FileContent)+21)));
DeleteFile(TmpFileName);
end
else
begin
ShowErrorMsg('Error calling: GetServiceLogonAs(" + MYSERVICE + ")', res);
Result := '';
end;
end;

zdenok
- 95
- 10
-
1That's terrible solution. I'd rather follow the WMI way (see the first half of my post). That uses just Windows built-in COM interfaces. – TLama Oct 25 '12 at 13:13
-
What if WMI is not installed? There are still some clients that use WinXP. Anyway thank for your advice. – zdenok Oct 25 '12 at 13:19
-
1Why would you need to [`install it`](http://technet.microsoft.com/en-us/library/ee692772.aspx#EMAA) ? Btw. guess what your code returns on my localized Czech Windows 7 ? There's no `SERVICE_START_NAME` tag, but I have [`Název_spouštěné_služby`](http://i.imgur.com/A5UXa.jpg) instead for the service start name tag. – TLama Oct 25 '12 at 13:31
-
1OK, thank for you advice, I thought that WMI was not preinstalled on WinXP. By the way Název_spouštěné_služby seems inadequate translation because its not name of the service but name of the user account. ;-) – zdenok Oct 26 '12 at 08:06