小生负责公司的WINDOWS NT服务层编程,在写完服务程序后,日前在写控制程序的时候发现一个极其古怪的问题,就是如果我CreateService之后没有关闭,那么OpenService要么返回的是0,要么就返回的值和CreateService不一样,并由此导致DeleteService删除对象之后无法在当前控制程序中再次安装服务(服务和控制程序是独立的实体),除非退出控制程序并重启。因为在
CreateService->OpenService->DeleteService->CloseServiceHandle会导致服务状态变成“已禁用”但没有被删除,程序关闭后,服务被删除
CreateService->CloseServiceHandle->OpenService->DeleteService->CloseServiceHandle完全成功
代码如下
procedure TFrmMain.InstallBtnClick(Sender: TObject);
var
  P: PChar;
begin
  hSCManager := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  if hSCManager = 0 then
    // didn't work, maybe we asked for too many access rights?
    hSCManager := OpenSCManager(nil, nil, 0);
  if hSCManager <> 0 then
  begin
    hService := CreateService(
      hSCManager, // SCManager database
      PChar(ServiceNameEdit.Text), // name of service
      PChar(DisplayEdit.Text), // service name to display
      SERVICE_ALL_ACCESS, // desired access
      SERVICE_WIN32_SHARE_PROCESS, // service type
      SERVICE_AUTO_START, // start type
      SERVICE_ERROR_NORMAL, // error control type
      PChar(ProviderEdit.Text), // service's binary
      nil, // no load ordering group
      nil, // no tag identifier
      nil, // no dependencies
      nil, // LocalSystem account
      nil); // no password
    CloseServiceHandle(hSCManager);
    if hService <> 0 then
    begin
      P := PChar(DescrEdit.Text);
      ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, @P);
      if StartService(hService, 0, PChar(nil^)) then
      begin
        CloseServiceHandle(hService);/////////这里如果我不关闭掉这个全局句柄,点卸载按钮的时候就会产生奇怪的现象,服务程序状态为已禁用,而控制程序关闭后,服务程序就被卸载了
        MessageBox(0, 'Install Service successed', 'Congratulation...', MB_ICONINFORMATION);
      end;
    end;
  end;
end;procedure TFrmMain.UninstallBtnClick(Sender: TObject);
var
  hSConfig: DWORD;
  lpSConfig: PQueryServiceConfig;
  ServiceStatus: TServiceStatus;
  ConfigError: boolean;
begin
  hSCManager := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  if hSCManager = 0 then hSCManager := OpenSCManager(nil, nil, 0);
  if hSCManager <> 0 then
  begin
    hService := OpenService(hSCManager, PChar(ServiceNameEdit.Text), SERVICE_ALL_ACCESS or _DELETE);
    CloseServiceHandle(hSCManager);
    if hService <> 0 then
    begin
      ConfigError := False;
      hSConfig := 0;
      QueryServiceConfig(hService, nil, 0, hSConfig);
      if hSConfig <> 0 then
      begin
        lpSConfig := Pointer(LocalAlloc(LPTR, hSConfig * 2));
        ConfigError := QueryServiceConfig(hService, lpSConfig, hSConfig * 2, hSConfig) and
          ((lpSConfig^.dwServiceType = SERVICE_WIN32_SHARE_PROCESS) and
          (lpSConfig^.dwStartType = SERVICE_AUTO_START) and
          (IsTextEqual(lpSConfig^.lpDisplayName, PChar(DisplayEdit.Text))));
        LocalFree(DWORD(lpSConfig));
      end;
      if not ControlService(hService, SERVICE_CONTROL_INTERROGATE, ServiceStatus) then
        ServiceStatus.dwCurrentState := SERVICE_STOPPED;
      if (ConfigError) and (ServiceStatus.dwCurrentState = SERVICE_RUNNING) then
      begin
        // the parameters are correct, so we try to stop and remove it
        if ControlService(hService, SERVICE_CONTROL_STOP, ServiceStatus) then
        begin
          if DeleteService(hService) then
          begin
            CloseServiceHandle(hService);
            MessageBox(0, 'The service is removed again', 'information...', MB_ICONINFORMATION);
          end
          else
            MessageBox(0, 'The service is stopped, but removing failed', 'warning...', MB_ICONWARNING);
        end
        else
          MessageBox(0, 'Stopping failed', 'warning...', MB_ICONWARNING);
      end
      else
      begin
        if not ConfigError then
          // not all parameters are correct, so we try to correct them
          if ChangeServiceConfig(hService, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
            arrCh, nil, nil, nil, nil, nil, PChar(DisplayEdit.Text)) then
            MessageBox(0, 'Correction of service parameters succeeded', 'information...', MB_ICONINFORMATION)
          else
            MessageBox(0, 'Correction of service parameters failed', 'warning...', MB_ICONWARNING);
      end;
    end;
  end;
end;