如何用 Delphi 建立系統服務程序?

如何用 Delphi 建立系統服務程序?php

Windows 2000/XP和2003等支持一種叫作"服務程序"的東西.程序做爲服務啓動有如下幾個好處:html

(1)不用登錄進系統便可運行.數據庫

(2)具備SYSTEM特權.因此你在進程管理器裏面是沒法結束它的.api

筆者在2003年爲一公司開發機頂盒項目的時候,曾經寫過課件上傳和媒體服務,下面就介紹一下如何用Delphi7建立一個Service程序.框架

運行Delphi7,選擇菜單File-->New-->Other--->Service Application.將生成一個服務程序的框架.將工程保存爲ServiceDemo.dpr和Unit_Main.pas,而後回到主框架.咱們注意到,Service有幾個屬性.其中如下幾個是咱們比較經常使用的:ide

(1)DisplayName:服務的顯示名稱函數

(2)Name:服務名稱.工具

咱們在這裏將DisplayName的值改成"Delphi服務演示程序",Name改成"DelphiService".編譯這個項目,將獲得 ServiceDemo.exe.這已是一個服務程序了!進入CMD模式,切換致工程所在目錄,運行命令"ServiceDemo.exe /install",將提示服務安裝成功!而後"net start DelphiService"將啓動這個服務.進入控制面版-->管理工具-->服務,將顯示這個服務和當前狀態.不過這個服務如今什麼也幹不了,由於咱們尚未寫代碼:)先"net stop DelphiService"中止再"ServiceDemo.exe /uninstall"刪除這個服務.回到Delphi7的IDE.oop

咱們的計劃是爲這個服務添加一個主窗口,運行後任務欄顯示程序的圖標,雙擊圖標將顯示主窗口,上面有一個按鈕,點擊該按鈕將實現Ctrl+Alt+Del功能.ui

實際上,服務程序莫認是工做於Winlogon桌面的,能夠打開控制面板,查看咱們剛纔那個服務的屬性-->登錄,其中"容許服務與桌面交互 "是不打鉤的.怎麼辦?呵呵,回到IDE,注意那個布爾屬性:Interactive,當這個屬性爲True的時候,該服務程序就能夠與桌面交互了.

File-->New-->Form爲服務添加窗口FrmMain,單元保存爲Unit_FrmMain,而且把這個窗口設置爲手工建立.完成後的代碼以下:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
unit     Unit_Main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs, Unit_FrmMain;
type
TDelphiService =     class     (TService)
procedure     ServiceContinue(Sender: TService;     var     Continued:     Boolean     );
procedure     ServiceExecute(Sender: TService);
procedure     ServicePause(Sender: TService;     var     Paused:     Boolean     );
procedure     ServiceShutdown(Sender: TService);
procedure     ServiceStart(Sender: TService;     var     Started:     Boolean     );
procedure     ServiceStop(Sender: TService;     var     Stopped:     Boolean     );
private
{ Private declarations }
public
function     GetServiceController: TServiceController; override;
{ Public declarations }
end     ;
var
DelphiService: TDelphiService;
FrmMain: TFrmMain;
implementation
{$R *.DFM}
procedure     ServiceController(CtrlCode: DWord); stdcall;
begin
DelphiService     .     Controller(CtrlCode);
end     ;
function     TDelphiService     .     GetServiceController: TServiceController;
begin
Result := ServiceController;
end     ;
procedure     TDelphiService     .     ServiceContinue(Sender: TService;
var     Continued:     Boolean     );
begin
while     not     Terminated     do
begin
Sleep(     10     );
ServiceThread     .     ProcessRequests(     False     );
end     ;
end     ;
procedure     TDelphiService     .     ServiceExecute(Sender: TService);
begin
while     not     Terminated     do
begin
Sleep(     10     );
ServiceThread     .     ProcessRequests(     False     );
end     ;
end     ;
procedure     TDelphiService     .     ServicePause(Sender: TService;
var     Paused:     Boolean     );
begin
Paused :=     True     ;
end     ;
procedure     TDelphiService     .     ServiceShutdown(Sender: TService);
begin
gbCanClose :=     true     ;
FrmMain     .     Free;
Status := csStopped;
ReportStatus();
end     ;
procedure     TDelphiService     .     ServiceStart(Sender: TService;
var     Started:     Boolean     );
begin
Started :=     True     ;
Svcmgr     .     Application     .     CreateForm(TFrmMain, FrmMain);
gbCanClose :=     False     ;
FrmMain     .     Hide;
end     ;
procedure     TDelphiService     .     ServiceStop(Sender: TService;
var     Stopped:     Boolean     );
begin
Stopped :=     True     ;
gbCanClose :=     True     ;
FrmMain     .     Free;
end     ;
end     .

主窗口單元以下:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
unit     Unit_FrmMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, ShellApi, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
const
WM_TrayIcon = WM_USER +     1234     ;
type
TFrmMain =     class     (TForm)
Timer1: TTimer;
Button1: TButton;
procedure     FormCreate(Sender: TObject);
procedure     FormCloseQuery(Sender: TObject;     var     CanClose:     Boolean     );
procedure     FormDestroy(Sender: TObject);
procedure     Timer1Timer(Sender: TObject);
procedure     Button1Click(Sender: TObject);
private
{ Private declarations }
IconData: TNotifyIconData;
procedure     AddIconToTray;
procedure     DelIconFromTray;
procedure     TrayIconMessage(     var     Msg: TMessage); message WM_TrayIcon;
procedure     SysButtonMsg(     var     Msg: TMessage); message WM_SYSCOMMAND;
public
{ Public declarations }
end     ;
var
FrmMain: TFrmMain;
gbCanClose:     Boolean     ;
implementation
{$R *.dfm}
procedure     TFrmMain     .     FormCreate(Sender: TObject);
begin
FormStyle := fsStayOnTop;
SetWindowLong(Application     .     Handle, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
gbCanClose :=     False     ;
Timer1     .     Interval :=     1000     ;
Timer1     .     Enabled :=     True     ;
end     ;
procedure     TFrmMain     .     FormCloseQuery(Sender: TObject;     var     CanClose:     Boolean     );
begin
CanClose := gbCanClose;
if     not     CanClose     then
begin
Hide;
end     ;
end     ;
procedure     TFrmMain     .     FormDestroy(Sender: TObject);
begin
Timer1     .     Enabled :=     False     ;
DelIconFromTray;
end     ;
procedure     TFrmMain     .     AddIconToTray;
begin
ZeroMemory(@IconData, SizeOf(TNotifyIconData));
IconData     .     cbSize := SizeOf(TNotifyIconData);
IconData     .     Wnd := Handle;
IconData     .     uID :=     1     ;
IconData     .     uFlags := NIF_MESSAGE     or     NIF_ICON     or     NIF_TIP;
IconData     .     uCallbackMessage := WM_TrayIcon;
IconData     .     hIcon := Application     .     Icon     .     Handle;
IconData     .     szTip := Delphi服務演示程序;
Shell_NotifyIcon(NIM_ADD, @IconData);
end     ;
procedure     TFrmMain     .     DelIconFromTray;
begin
Shell_NotifyIcon(NIM_DELETE, @IconData);
end     ;
procedure     TFrmMain     .     SysButtonMsg(     var     Msg: TMessage);
begin
if     (Msg     .     wParam = SC_CLOSE)     or
(Msg     .     wParam = SC_MINIMIZE)     then     Hide
else     inherited     ;     // 執行默認動做
end     ;
procedure     TFrmMain     .     TrayIconMessage(     var     Msg: TMessage);
begin
if     (Msg     .     LParam = WM_LBUTTONDBLCLK)     then     Show();
end     ;
procedure     TFrmMain     .     Timer1Timer(Sender: TObject);
begin
AddIconToTray;
end     ;
procedure     SendHokKey;stdcall;
var
HDesk_WL: HDESK;
begin
HDesk_WL := OpenDesktop (Winlogon,     0     ,     False     , DESKTOP_JOURNALPLAYBACK);
if     (HDesk_WL <>     0     )     then
if     (SetThreadDesktop (HDesk_WL) =     True     )     then
PostMessage(HWND_BROADCAST, WM_HOTKEY,     0     , MAKELONG (MOD_ALT     or     MOD_CONTROL, VK_DELETE));
end     ;
procedure     TFrmMain     .     Button1Click(Sender: TObject);
var
dwThreadID : DWORD;
begin
CreateThread(     nil     ,     0     , @SendHokKey,     nil     ,     0     , dwThreadID);
end     ;
end     .

補充:

(1)關於更多服務程序的演示程序,請訪問如下 http://www.torry.net/pages.php?id=226 ,上面包含了多個演示如何控制和管理系統服務的代碼.

(2)請切記:Windows實際上存在多個桌面.例如屏幕傳輸會出現白屏,可能有兩個緣由:一是系統處於鎖定或未登錄桌面,二是處於屏幕保護桌面.這時候要將當前桌面切換到該桌面才能抓屏.

(3)關於服務程序與桌面交互,還有種動態切換方法.大概單元以下:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
unit     ServiceDesktop;
interface
function     InitServiceDesktop:     boolean     ;
procedure     DoneServiceDeskTop;
implementation
uses     Windows, SysUtils;
const
DefaultWindowStation = WinSta0;
DefaultDesktop = Default;
var
hwinstaSave: HWINSTA;
hdeskSave: HDESK;
hwinstaUser: HWINSTA;
hdeskUser: HDESK;
function     InitServiceDesktop:     boolean     ;
var
dwThreadId: DWORD;
begin
dwThreadId := GetCurrentThreadID;
// Ensure connection to service window station and desktop, and
// save their handles.
hwinstaSave := GetProcessWindowStation;
hdeskSave := GetThreadDesktop(dwThreadId);
hwinstaUser := OpenWindowStation(DefaultWindowStation,     FALSE     , MAXIMUM_ALLOWED);
if     hwinstaUser =     0     then
begin
OutputDebugString(     PChar     (OpenWindowStation failed + SysErrorMessage(GetLastError)));
Result :=     false     ;
exit;
end     ;
if     not     SetProcessWindowStation(hwinstaUser)     then
begin
OutputDebugString(SetProcessWindowStation failed);
Result :=     false     ;
exit;
end     ;
hdeskUser := OpenDesktop(DefaultDesktop,     0     ,     FALSE     , MAXIMUM_ALLOWED);
if     hdeskUser =     0     then
begin
OutputDebugString(OpenDesktop failed);
SetProcessWindowStation(hwinstaSave);
CloseWindowStation(hwinstaUser);
Result :=     false     ;
exit;
end     ;
Result := SetThreadDesktop(hdeskUser);
if     not     Result     then
OutputDebugString(     PChar     (SetThreadDesktop + SysErrorMessage(GetLastError)));
end     ;
procedure     DoneServiceDeskTop;
begin
// Restore window station and desktop.
SetThreadDesktop(hdeskSave);
SetProcessWindowStation(hwinstaSave);
if     hwinstaUser <>     0     then
CloseWindowStation(hwinstaUser);
if     hdeskUser <>     0     then
CloseDesktop(hdeskUser);
end     ;
initialization
InitServiceDesktop;
finalization
DoneServiceDesktop;
end     .

更詳細的演示代碼請參看: http://www.torry.net/samples/samples/os/isarticle.zip

(4)關於安裝服務如何添加服務描述.有兩種方法:一是修改註冊表.服務的詳細信息都位於HKEY_LOCAL_MACHINE\SYSTEM\ ControlSet001\Services\下面,例如咱們剛纔那個服務就位於HKEY_LOCAL_MACHINE\SYSTEM\ ControlSet001\Services\DelphiService下.第二種方法就是先用QueryServiceConfig2函數獲取服務信息,而後ChangeServiceConfig2來改變描述.用Delphi實現的話,單元以下:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
unit     WinSvcEx;
interface
uses     Windows, WinSvc;
const
//
// Service config info levels
//
SERVICE_CONFIG_DESCRIPTION =     1     ;
SERVICE_CONFIG_FAILURE_ACTIONS =     2     ;
//
// DLL name of imported functions
//
AdvApiDLL = advapi32     .     dll;
type
//
// Service description string
//
PServiceDescriptionA = ^TServiceDescriptionA;
PServiceDescriptionW = ^TServiceDescriptionW;
PServiceDescription = PServiceDescriptionA;
{$EXTERNALSYM _SERVICE_DESCRIPTIONA}
_SERVICE_DESCRIPTIONA =     record
lpDescription :     PAnsiChar     ;
end     ;
{$EXTERNALSYM _SERVICE_DESCRIPTIONW}
_SERVICE_DESCRIPTIONW =     record
lpDescription :     PWideChar     ;
end     ;
{$EXTERNALSYM _SERVICE_DESCRIPTION}
_SERVICE_DESCRIPTION = _SERVICE_DESCRIPTIONA;
{$EXTERNALSYM SERVICE_DESCRIPTIONA}
SERVICE_DESCRIPTIONA = _SERVICE_DESCRIPTIONA;
{$EXTERNALSYM SERVICE_DESCRIPTIONW}
SERVICE_DESCRIPTIONW = _SERVICE_DESCRIPTIONW;
{$EXTERNALSYM SERVICE_DESCRIPTION}
SERVICE_DESCRIPTION = _SERVICE_DESCRIPTIONA;
TServiceDescriptionA = _SERVICE_DESCRIPTIONA;
TServiceDescriptionW = _SERVICE_DESCRIPTIONW;
TServiceDescription = TServiceDescriptionA;
//
// Actions to take on service failure
//
{$EXTERNALSYM _SC_ACTION_TYPE}
_SC_ACTION_TYPE = (SC_ACTION_NONE, SC_ACTION_RESTART, SC_ACTION_REBOOT, SC_ACTION_RUN_COMMAND);
{$EXTERNALSYM SC_ACTION_TYPE}
SC_ACTION_TYPE = _SC_ACTION_TYPE;
PServiceAction = ^TServiceAction;
{$EXTERNALSYM _SC_ACTION}
_SC_ACTION =     record
aType : SC_ACTION_TYPE;
Delay : DWORD;
end     ;
{$EXTERNALSYM SC_ACTION}
SC_ACTION = _SC_ACTION;
TServiceAction = _SC_ACTION;
PServiceFailureActionsA = ^TServiceFailureActionsA;
PServiceFailureActionsW = ^TServiceFailureActionsW;
PServiceFailureActions = PServiceFailureActionsA;
{$EXTERNALSYM _SERVICE_FAILURE_ACTIONSA}
_SERVICE_FAILURE_ACTIONSA =     record
dwResetPeriod : DWORD;
lpRebootMsg : LPSTR;
lpCommand : LPSTR;
cActions : DWORD;
lpsaActions : ^SC_ACTION;
end     ;
{$EXTERNALSYM _SERVICE_FAILURE_ACTIONSW}
_SERVICE_FAILURE_ACTIONSW =     record
dwResetPeriod : DWORD;
lpRebootMsg : LPWSTR;
lpCommand : LPWSTR;
cActions : DWORD;
lpsaActions : ^SC_ACTION;
end     ;
{$EXTERNALSYM _SERVICE_FAILURE_ACTIONS}
_SERVICE_FAILURE_ACTIONS = _SERVICE_FAILURE_ACTIONSA;
{$EXTERNALSYM SERVICE_FAILURE_ACTIONSA}
SERVICE_FAILURE_ACTIONSA = _SERVICE_FAILURE_ACTIONSA;
{$EXTERNALSYM SERVICE_FAILURE_ACTIONSW}
SERVICE_FAILURE_ACTIONSW = _SERVICE_FAILURE_ACTIONSW;
{$EXTERNALSYM SERVICE_FAILURE_ACTIONS}
SERVICE_FAILURE_ACTIONS = _SERVICE_FAILURE_ACTIONSA;
TServiceFailureActionsA = _SERVICE_FAILURE_ACTIONSA;
TServiceFailureActionsW = _SERVICE_FAILURE_ACTIONSW;
TServiceFailureActions = TServiceFailureActionsA;
///////////////////////////////////////////////////////////////////////////
// API Function Prototypes
///////////////////////////////////////////////////////////////////////////
TQueryServiceConfig2 =     function     (hService : SC_HANDLE; dwInfoLevel : DWORD; lpBuffer :     pointer     ;
cbBufSize : DWORD;     var     pcbBytesNeeded) : BOOL; stdcall;
TChangeServiceConfig2 =     function     (hService : SC_HANDLE; dwInfoLevel : DWORD; lpInfo :     pointer     ) : BOOL; stdcall;
var
hDLL : THandle ;
LibLoaded :     boolean     ;
var
OSVersionInfo : TOSVersionInfo;
{$EXTERNALSYM QueryServiceConfig2A}
QueryServiceConfig2A : TQueryServiceConfig2;
{$EXTERNALSYM QueryServiceConfig2W}
QueryServiceConfig2W : TQueryServiceConfig2;
{$EXTERNALSYM QueryServiceConfig2}
QueryServiceConfig2 : TQueryServiceConfig2;
{$EXTERNALSYM ChangeServiceConfig2A}
ChangeServiceConfig2A : TChangeServiceConfig2;
{$EXTERNALSYM ChangeServiceConfig2W}
ChangeServiceConfig2W : TChangeServiceConfig2;
{$EXTERNALSYM ChangeServiceConfig2}
ChangeServiceConfig2 : TChangeServiceConfig2;
implementation
initialization
OSVersionInfo     .     dwOSVersionInfoSize := SizeOf(OSVersionInfo);
GetVersionEx(OSVersionInfo);
if     (OSVersionInfo     .     dwPlatformId = VER_PLATFORM_WIN32_NT)     and     (OSVersionInfo     .     dwMajorVersion >=     5     )     then
begin
if     hDLL =     0     then
begin
hDLL:=GetModuleHandle(AdvApiDLL);
LibLoaded :=     False     ;
if     hDLL =     0     then
begin
hDLL := LoadLibrary(AdvApiDLL);
LibLoaded :=     True     ;
end     ;
end     ;
if     hDLL <>     0     then
begin
@QueryServiceConfig2A := GetProcAddress(hDLL, QueryServiceConfig2A);
@QueryServiceConfig2W := GetProcAddress(hDLL, QueryServiceConfig2W);
@QueryServiceConfig2 := @QueryServiceConfig2A;
@ChangeServiceConfig2A := GetProcAddress(hDLL, ChangeServiceConfig2A);
@ChangeServiceConfig2W := GetProcAddress(hDLL, ChangeServiceConfig2W);
@ChangeServiceConfig2 := @ChangeServiceConfig2A;
end     ;
end
else
begin
@QueryServiceConfig2A :=     nil     ;
@QueryServiceConfig2W :=     nil     ;
@QueryServiceConfig2 :=     nil     ;
@ChangeServiceConfig2A :=     nil     ;
@ChangeServiceConfig2W :=     nil     ;
@ChangeServiceConfig2 :=     nil     ;
end     ;
finalization
if     (hDLL <>     0     )     and     LibLoaded     then
FreeLibrary(hDLL);
end     .
unit     winntService;
interface
uses
Windows,WinSvc,WinSvcEx;
function     InstallService(     const     strServiceName,strDisplayName,strDescription,strFilename:     string     ):     Boolean     ;
//eg:InstallService(服務名稱,顯示名稱,描述信息,服務文件);
procedure     UninstallService(strServiceName:     string     );
implementation
function     StrLCopy(Dest:     PChar     ;     const     Source:     PChar     ; MaxLen:     Cardinal     ):     PChar     ; assembler;
asm
PUSH EDI
PUSH ESI
PUSH EBX
MOV ESI,EAX
MOV EDI,EDX
MOV EBX,ECX
XOR     AL,AL
TEST ECX,ECX
JZ @@     1
REPNE SCASB
JNE @@     1
INC ECX
@@     1     : SUB EBX,ECX
MOV EDI,ESI
MOV ESI,EDX
MOV EDX,EDI
MOV ECX,EBX
SHR     ECX,     2
REP MOVSD
MOV ECX,EBX
AND     ECX,     3
REP MOVSB
STOSB
MOV EAX,EDX
POP EBX
POP ESI
POP EDI
end     ;
function     StrPCopy(Dest:     PChar     ;     const     Source:     string     ):     PChar     ;
begin
Result := StrLCopy(Dest,     PChar     (Source), Length(Source));
end     ;
function     InstallService(     const     strServiceName,strDisplayName,strDescription,strFilename:     string     ):     Boolean     ;
var
//ss : TServiceStatus;
//psTemp : PChar;
hSCM,hSCS:THandle;
srvdesc : PServiceDescription;
desc :     string     ;
//SrvType : DWord;
lpServiceArgVectors:     pchar     ;
begin
Result:=     False     ;
//psTemp := nil;
//SrvType := SERVICE_WIN32_OWN_PROCESS and SERVICE_INTERACTIVE_PROCESS;
hSCM:=OpenSCManager(     nil     ,     nil     ,SC_MANAGER_ALL_ACCESS);     //鏈接服務數據庫
if     hSCM=     0     then     Exit;     //MessageBox(hHandle,Pchar(SysErrorMessage(GetLastError)),服務程序管理器,MB_ICONERROR+MB_TOPMOST);
hSCS:=CreateService(     //建立服務函數
hSCM,     // 服務控制管理句柄
Pchar     (strServiceName),     // 服務名稱
Pchar     (strDisplayName),     // 顯示的服務名稱
SERVICE_ALL_ACCESS,     // 存取權利
SERVICE_WIN32_OWN_PROCESS     or     SERVICE_INTERACTIVE_PROCESS,     // 服務類型 SERVICE_WIN32_SHARE_PROCESS
SERVICE_AUTO_START,     // 啓動類型
SERVICE_ERROR_IGNORE,     // 錯誤控制類型
Pchar     (strFilename),     // 服務程序
nil     ,     // 組服務名稱
nil     ,     // 組標識
nil     ,     // 依賴的服務
nil     ,     // 啓動服務賬號
nil     );     // 啓動服務口令
if     hSCS=     0     then     Exit;     //MessageBox(hHandle,Pchar(SysErrorMessage(GetLastError)),Pchar(Application.Title),MB_ICONERROR+MB_TOPMOST);
if     Assigned(ChangeServiceConfig2)     then
begin
desc := Copy(strDescription,     1     ,     1024     );
GetMem(srvdesc,SizeOf(TServiceDescription));
GetMem(srvdesc^.lpDescription,Length(desc) +     1     );
try
StrPCopy(srvdesc^.lpDescription, desc);
ChangeServiceConfig2(hSCS,SERVICE_CONFIG_DESCRIPTION,srvdesc);
finally
FreeMem(srvdesc^.lpDescription);
FreeMem(srvdesc);
end     ;
end     ;
lpServiceArgVectors :=     nil     ;
if     not     StartService(hSCS,     0     , lpServiceArgVectors)     then     //啓動服務
Exit;     //MessageBox(hHandle,Pchar(SysErrorMessage(GetLastError)),Pchar(Application.Title),MB_ICONERROR+MB_TOPMOST);
CloseServiceHandle(hSCS);     //關閉句柄
Result:=     True     ;
end     ;
procedure     UninstallService(strServiceName:     string     );
var
SCManager: SC_HANDLE;
Service: SC_HANDLE;
Status: TServiceStatus;
begin
SCManager := OpenSCManager(     nil     ,     nil     , SC_MANAGER_ALL_ACCESS);
if     SCManager =     0     then     Exit;
try
Service := OpenService(SCManager,     Pchar     (strServiceName), SERVICE_ALL_ACCESS);
ControlService(Service, SERVICE_CONTROL_STOP, Status);
DeleteService(Service);
CloseServiceHandle(Service);
finally
CloseServiceHandle(SCManager);
end     ;
end     ;
end     .

(5)如何暴力關閉一個服務程序,實現咱們之前那個"NT工具箱"的功能?首先,根據進程名稱來殺死進程是用如下函數:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
uses     Tlhelp32;
function     KillTask(ExeFileName:     string     ):     Integer     ;
const
PROCESS_TERMINATE =     01     ;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
Result :=     0     ;
FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,     0     );
FProcessEntry32     .     dwSize := SizeOf(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
while     Integer     (ContinueLoop) <>     0     do
begin
if     ((UpperCase(ExtractFileName(FProcessEntry32     .     szExeFile)) =
UpperCase(ExeFileName))     or     (UpperCase(FProcessEntry32     .     szExeFile) =
UpperCase(ExeFileName)))     then
Result :=     Integer     (TerminateProcess(
OpenProcess(PROCESS_TERMINATE,
BOOL(     0     ),
FProcessEntry32     .     th32ProcessID),
0     ));
ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
end     ;
CloseHandle(FSnapshotHandle);
end     ;

可是對於服務程序,它會提示"拒絕訪問".其實只要程序擁有Debug權限便可:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function     EnableDebugPrivilege:     Boolean     ;
function     EnablePrivilege(hToken:     Cardinal     ; PrivName:     string     ; bEnable:     Boolean     ):     Boolean     ;
var
TP: TOKEN_PRIVILEGES;
Dummy:     Cardinal     ;
begin
TP     .     PrivilegeCount :=     1     ;
LookupPrivilegeValue(     nil     ,     pchar     (PrivName), TP     .     Privileges[     0     ].Luid);
if     bEnable     then
TP     .     Privileges[     0     ].Attributes := SE_PRIVILEGE_ENABLED
else     TP     .     Privileges[     0     ].Attributes :=     0     ;
AdjustTokenPrivileges(hToken,     False     , TP, SizeOf(TP),     nil     , Dummy);
Result := GetLastError = ERROR_SUCCESS;
end     ;
var
hToken:     Cardinal     ;
begin
OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES, hToken);
result:=EnablePrivilege(hToken, SeDebugPrivilege,     True     );
CloseHandle(hToken);
end     ;

使用方法:

?

1
2
3
EnableDebugPrivilege;     //提高權限
KillTask(xxxx     .     exe);     //關閉該服務程序.
相關文章
相關標籤/搜索