Dar*_*tar 11 windows delphi windows-services
我创建了非常简单的Windows服务应用程序使用Delphi按时间顺序更新一些数据文件.服务应用程序编译,并且运行良好,但我对最终的exe文件大小不满意.它超过900K.服务本身不使用Forms,Dialogs,但是我看到SvcMgr正在引用Forms和我没有使用的其他大型垃圾.
Name Size Group Package
------------ ------ ----- -------
Controls 80,224 CODE
Forms 61,204 CODE
Classes 46,081 CODE
Graphics 37,054 CODE
Run Code Online (Sandbox Code Playgroud)
有没有办法让服务应用更小?或者是否有其他服务模板我可以使用而不使用表格等?
Run*_*ner 20
这是我用来创建基于纯API的非常小的服务的代码.exe的大小只有50K.可能更小,我使用了一些其他可以省略的单位.使用的编译器是Delphi 7.新编译器可能会更大,但我没有检查.
代码很旧,我没有检查.我几年前写的.所以以它为例,请不要复制粘贴.
{
NT Service model based completely on API calls. Version 0.1
Inspired by NT service skeleton from Aphex
Adapted by Runner
}
program PureAPIService;
{$APPTYPE CONSOLE}
{$IF CompilerVersion > 20}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
{$WEAKLINKRTTI ON}
{$IFEND}
uses
Windows,
WinSvc;
const
ServiceName = 'PureAPIService';
DisplayName = 'Pure Windows API Service';
NUM_OF_SERVICES = 2;
var
ServiceStatus : TServiceStatus;
StatusHandle : SERVICE_STATUS_HANDLE;
ServiceTable : array [0..NUM_OF_SERVICES] of TServiceTableEntry;
Stopped : Boolean;
Paused : Boolean;
var
ghSvcStopEvent: Cardinal;
procedure OnServiceCreate;
begin
// do your stuff here;
end;
procedure AfterUninstall;
begin
// do your stuff here;
end;
procedure ReportSvcStatus(dwCurrentState, dwWin32ExitCode, dwWaitHint: DWORD);
begin
// fill in the SERVICE_STATUS structure.
ServiceStatus.dwCurrentState := dwCurrentState;
ServiceStatus.dwWin32ExitCode := dwWin32ExitCode;
ServiceStatus.dwWaitHint := dwWaitHint;
case dwCurrentState of
SERVICE_START_PENDING: ServiceStatus.dwControlsAccepted := 0;
else
ServiceStatus.dwControlsAccepted := SERVICE_ACCEPT_STOP;
end;
case (dwCurrentState = SERVICE_RUNNING) or (dwCurrentState = SERVICE_STOPPED) of
True: ServiceStatus.dwCheckPoint := 0;
False: ServiceStatus.dwCheckPoint := 1;
end;
// Report the status of the service to the SCM.
SetServiceStatus(StatusHandle, ServiceStatus);
end;
procedure MainProc;
begin
// we have to do something or service will stop
ghSvcStopEvent := CreateEvent(nil, True, False, nil);
if ghSvcStopEvent = 0 then
begin
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
Exit;
end;
// Report running status when initialization is complete.
ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );
// Perform work until service stops.
while True do
begin
// Check whether to stop the service.
WaitForSingleObject(ghSvcStopEvent, INFINITE);
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
Exit;
end;
end;
procedure ServiceCtrlHandler(Control: DWORD); stdcall;
begin
case Control of
SERVICE_CONTROL_STOP:
begin
Stopped := True;
SetEvent(ghSvcStopEvent);
ServiceStatus.dwCurrentState := SERVICE_STOP_PENDING;
SetServiceStatus(StatusHandle, ServiceStatus);
end;
SERVICE_CONTROL_PAUSE:
begin
Paused := True;
ServiceStatus.dwcurrentstate := SERVICE_PAUSED;
SetServiceStatus(StatusHandle, ServiceStatus);
end;
SERVICE_CONTROL_CONTINUE:
begin
Paused := False;
ServiceStatus.dwCurrentState := SERVICE_RUNNING;
SetServiceStatus(StatusHandle, ServiceStatus);
end;
SERVICE_CONTROL_INTERROGATE: SetServiceStatus(StatusHandle, ServiceStatus);
SERVICE_CONTROL_SHUTDOWN: Stopped := True;
end;
end;
procedure RegisterService(dwArgc: DWORD; var lpszArgv: PChar); stdcall;
begin
ServiceStatus.dwServiceType := SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwCurrentState := SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted := SERVICE_ACCEPT_STOP or SERVICE_ACCEPT_PAUSE_CONTINUE;
ServiceStatus.dwServiceSpecificExitCode := 0;
ServiceStatus.dwWin32ExitCode := 0;
ServiceStatus.dwCheckPoint := 0;
ServiceStatus.dwWaitHint := 0;
StatusHandle := RegisterServiceCtrlHandler(ServiceName, @ServiceCtrlHandler);
if StatusHandle <> 0 then
begin
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
try
Stopped := False;
Paused := False;
MainProc;
finally
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
end;
end;
end;
procedure UninstallService(const ServiceName: PChar; const Silent: Boolean);
const
cRemoveMsg = 'Your service was removed sucesfuly!';
var
SCManager: SC_HANDLE;
Service: SC_HANDLE;
begin
SCManager := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
if SCManager = 0 then
Exit;
try
Service := OpenService(SCManager, ServiceName, SERVICE_ALL_ACCESS);
ControlService(Service, SERVICE_CONTROL_STOP, ServiceStatus);
DeleteService(Service);
CloseServiceHandle(Service);
if not Silent then
MessageBox(0, cRemoveMsg, ServiceName, MB_ICONINFORMATION or MB_OK or MB_TASKMODAL or MB_TOPMOST);
finally
CloseServiceHandle(SCManager);
AfterUninstall;
end;
end;
procedure InstallService(const ServiceName, DisplayName, LoadOrder: PChar;
const FileName: string; const Silent: Boolean);
const
cInstallMsg = 'Your service was Installed sucesfuly!';
cSCMError = 'Error trying to open SC Manager';
var
SCMHandle : SC_HANDLE;
SvHandle : SC_HANDLE;
begin
SCMHandle := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
if SCMHandle = 0 then
begin
MessageBox(0, cSCMError, ServiceName, MB_ICONERROR or MB_OK or MB_TASKMODAL or MB_TOPMOST);
Exit;
end;
try
SvHandle := CreateService(SCMHandle,
ServiceName,
DisplayName,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_IGNORE,
pchar(FileName),
LoadOrder,
nil,
nil,
nil,
nil);
CloseServiceHandle(SvHandle);
if not Silent then
MessageBox(0, cInstallMsg, ServiceName, MB_ICONINFORMATION or MB_OK or MB_TASKMODAL or MB_TOPMOST);
finally
CloseServiceHandle(SCMHandle);
end;
end;
procedure WriteHelpContent;
begin
WriteLn('To install your service please type <service name> /install');
WriteLn('To uninstall your service please type <service name> /remove');
WriteLn('For help please type <service name> /? or /h');
end;
begin
if (ParamStr(1) = '/h') or (ParamStr(1) = '/?') then
WriteHelpContent
else if ParamStr(1) = '/install' then
InstallService(ServiceName, DisplayName, 'System Reserved', ParamStr(0), ParamStr(2) = '/s')
else if ParamStr(1) = '/remove' then
UninstallService(ServiceName, ParamStr(2) = '/s')
else if ParamCount = 0 then
begin
OnServiceCreate;
ServiceTable[0].lpServiceName := ServiceName;
ServiceTable[0].lpServiceProc := @RegisterService;
ServiceTable[1].lpServiceName := nil;
ServiceTable[1].lpServiceProc := nil;
StartServiceCtrlDispatcher(ServiceTable[0]);
end
else
WriteLn('Wrong argument!');
end.
Run Code Online (Sandbox Code Playgroud)
编辑:
我在没有资源和SysUtils的情况下编译了上面的代码.我在Delphi XE下获得了32KB可执行文件,在Delphi 2006下获得了22KB可执行文件.在XE下我删除了RTTI信息.我会写博客,因为它很有趣.我想知道C++可执行文件有多大.
EDIT2:
我更新了代码.现在是一个有效的代码.大多数较大的错误都应该消失.它仍然绝不是生产质量.
你可以没有"大垃圾".但是你必须自己与windows API交谈.看一下线索的来源.
"大废话"可以让您更轻松地编码.为了增加代码大小,它减少了设计时间.这只是你认为重要的问题.
另外,你编译时没有调试信息吗?调试信息大大增加了exe的大小.