Configuration Inno安装服务登录为

Configuration Inno安装服务登录为,configuration,windows-services,inno-setup,advapi32,Configuration,Windows Services,Inno Setup,Advapi32,您能告诉我如何获取特定windows服务的“登录身份”参数吗? 我需要在我们的升级项目中重新注册服务,它需要在最初设置的相同帐户下运行。 我在advapi32.dll中找到了QueryServiceConfig,返回的结构中包含lpServiceStartName,但我无法从Inno安装程序使其工作。您无法使用InnoSetup脚本中的函数。要使用此函数,您必须从堆中分配缓冲区,这在InnoSetup中是不可能的。相反,您可以使用WMI,或者更具体地说,使用WMI类,它包含您要求的StartNa

您能告诉我如何获取特定windows服务的“登录身份”参数吗? 我需要在我们的升级项目中重新注册服务,它需要在最初设置的相同帐户下运行。 我在advapi32.dll中找到了QueryServiceConfig,返回的结构中包含lpServiceStartName,但我无法从Inno安装程序使其工作。

您无法使用InnoSetup脚本中的函数。要使用此函数,您必须从堆中分配缓冲区,这在InnoSetup中是不可能的。相反,您可以使用WMI,或者更具体地说,使用WMI类,它包含您要求的
StartName
属性。在InnoSetup脚本中,它可能如下所示:

[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;
创建一个外部库并从脚本中调用它会更容易(可能更快)。如果您有Delphi或Lazarus,您可以使用以下函数,该函数使用该函数获取您请求的成员:

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; 
函数GetServiceStartName(const AServiceName:string):string;
变量
缓冲区大小:DWORD;
拜特:德沃德;
服务手柄:SC_手柄;
服务经理:SC_手柄;
ServiceConfig:PQueryServiceConfig;
开始
结果:='';
ServiceManager:=OpenSCManager(无,无,SC_管理器_连接);
如果ServiceManager为0,则
尝试
ServiceHandle:=OpenService(ServiceManager,PChar(AServiceName),
服务(查询)(配置);;
如果ServiceHandle为0,则
尝试
如果不是QueryServiceConfig(ServiceHandle,nil,0,BufferSize)和
(GetLastError=ERROR\u缓冲区不足)然后
开始
ServiceConfig:=AllocMem(BufferSize);
尝试
如果QueryServiceConfig(ServiceHandle、ServiceConfig、BufferSize、,
字节(需要)
然后
结果:=ServiceConfig^.lpServiceStartName;
最后
FreeMem(ServiceConfig);
结束;
结束;
最后
CloseServiceHandle(ServiceHandle);
结束;
最后
CloseServiceHandle(ServiceManager);
结束;
结束;

我不喜欢链接外部库的想法,所以我最终通过以下方式解决了问题:

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;

这是一个糟糕的解决方案。我宁愿遵循WMI的方式(见我文章的前半部分)。仅使用Windows内置COM接口。如果未安装WMI怎么办?仍然有一些客户端使用WinXP。不管怎样,谢谢你的建议。你为什么要这么做?顺便说一句,猜猜你的代码在我的本地化的捷克Windows7上返回了什么?没有
SERVICE\u START\u NAME
标记,但是我已经为SERVICE START NAME标记添加了标记。好的,谢谢你的建议,我认为WMI没有预装在WinXP上。顺便说一句,Název_spouštěNéu služBy的翻译似乎不够,因为它不是服务名称,而是用户帐户的名称