要求:一個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;}