系統服務和普通FORMS程序共存一體的實現

要求:一個EXE,如何將它做成這樣的效果:
1、雙擊它時,像一個FORMS程序那樣正常顯示窗體運行。
2、註冊成系統服務,每次都可以從service.msc中啓動它。

也就是說,沒註冊之前,它可以當作普通FORMS程序運行,註冊之後,它就可以當系統服務運行。

 

做法:

參考Delphi 裏面scktsrvr的源代碼,Program Files/Borland/Delphi7/Bin 搜索scktsrvr 就會看到有個scktsrvr.dpr,查看它的工程源程序,原理:在啓動程序時,通過啓動的方式來決定如何加載程序。

 

必須的地方使用紅色標記:

 

 program RODBLayer;

{#ROGEN:RODBLayerServices.rodl} // RemObjects: Careful, do not remove!

uses
  uROComInit,

//增加引用
  SvcMgr,  Forms,    SysUtils,  WinSvc,

 

  RODBLayerService in 'RODBLayerService.pas' {RODBServices: TService},
  RODBLayerServices_Intf in 'RODBLayerServices_Intf.pas',
  RODBLayerServices_Invk in 'RODBLayerServices_Invk.pas',
  uADOConnectionPool in 'uADOConnectionPool.pas',
  uConnectionPool in 'uConnectionPool.pas',
  Comm in 'Comm.pas',
  Config in 'Config.pas' {ConfigFrm},
  RODBLayerServices_Impl in 'RODBLayerServices_Impl.pas';

{$R *.RES}
{$R RODLFile.res}

 

//步驟一、查找是否通過命令行來註冊或注消 ,如是則表明是系統服務
function Installing: Boolean;

begin
  Result := FindCmdLineSwitch('INSTALL',['-','/','/'], True) or
            FindCmdLineSwitch('UNINSTALL',['-','/','/'], True);
end;

 

//步驟二、檢測是否是系統服務中啓動服務;
function StartService: Boolean;

var
  Mgr, Svc: Integer;
  UserName, ServiceStartName: string;
  Config: Pointer;
  Size: DWord;
begin
  Result := False;
  Mgr := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  if Mgr <> 0 then
  begin

   //'RODBServices'代表服務名(services name),不是指服務顯示名(services display name)

   //它根據你的服務而定。
    Svc := OpenService(Mgr, PChar('RODBServices'), SERVICE_ALL_ACCESS);
    Result := Svc <> 0;
    if Result then
    begin
      QueryServiceConfig(Svc, nil, 0, Size);
      Config := AllocMem(Size);
      try
        QueryServiceConfig(Svc, Config, Size, Size);
        ServiceStartName := PQueryServiceConfig(Config)^.lpServiceStartName;
        if CompareText(ServiceStartName, 'LocalSystem') = 0 then
          ServiceStartName := 'SYSTEM';
      finally
        Dispose(Config);
      end;
      CloseServiceHandle(Svc);
    end;
    CloseServiceHandle(Mgr);
  end;
  if Result then
  begin
    Size := 256;
    SetLength(UserName, Size);
    GetUserName(PChar(UserName), Size);
    SetLength(UserName, StrLen(PChar(UserName)));
    Result := CompareText(UserName, ServiceStartName) = 0;
  end;
end;

 

//步驟三、判斷

begin
  if not Installing then
  begin
    CreateMutex(nil, True, 'RODBServices');  //創建一個互斥體;
    if GetLastError = ERROR_ALREADY_EXISTS then
    begin
      MessageBox(0, PChar('The RODBServices is already running'), '提示', MB_ICONERROR);
      Halt;
    end;
  end;
  if Installing or StartService then  //兩者之一爲真,表明是系統服務。否則爲Forms程序;
  begin
     SvcMgr.Application.Initialize;
     SvcMgr.Application.CreateForm(TRODBServices, RODBServices);
  SvcMgr.Application.CreateForm(TConfigFrm, ConfigFrm);
     ConfigAppName:='SvcMgr'; //使用它來標識出Application屬於哪種,從而爲關閉TConfigFrm窗體提供依據;這一行只跟你的實際應用有關。不過程序要退出時,要根據是系統服務還是普通FORMS做出不同的退出動作。如下:
     SvcMgr.Application.Run;
  end else
  begin
     Forms.Application.Initialize;
     Forms.Application.CreateForm(TRODBServices, RODBServices);
     Forms.Application.CreateForm(TConfigFrm,ConfigFrm);
     ConfigAppName:='Forms';
     Forms.Application.Run;
  end;
end.

{接上,用來說明不同的退出動作如何做的。

procedure TConfigFrm.BtnCloseClick(Sender: TObject);
begin
  if MessageDlgPos('您確定要退出服務端嗎?',mtConfirmation,[mbOK, mbCancel],0,
  Mouse.CursorPos.X-160,Mouse.CursorPos.Y-130)<>mrOk then Exit;
  RODBServices.ServiceStop(RODBServices,IsConsole) ;
  if ConfigAppName='SvcMgr' then   //前面代碼都相同,僅這裏要變一下。
    RODBServices.Status:=csStopped
  else
    Close;

end;}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章