用Delphi创建服务程序

Windows 2000 / XP和2003等支持一种叫做"服务程序"的东西.程序作为服务启动有以下几个好处:

(1)不用登陆进系统即可运行.
(2)具有SYSTEM特权.所以你在进程管理器里面是无法结束它的.

笔者在2003年为一公司开发机顶盒项目的时候, 曾经写过课件上传和媒体服务, 下面就介绍一下如何用Delphi7创建一个Service程序.
运行Delphi7, 选择菜单File - - > New - - > Other - - - > Service Application.将生成一个服务程序的框架.将工程保存为ServiceDemo.dpr和Unit_Main.pas, 然后回到主框架.我们注意到, Service有几个属性.其中以下几个是我们比较常用的:

(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.

我们的计划是为这个服务添加一个主窗口, 运行后任务栏显示程序的图标, 双击图标将显示主窗口, 上面有一个按钮, 点击该按钮将实现Ctrl + Alt + Del功能.

实际上, 服务程序莫认是工作于Winlogon桌面的, 可以打开控制面板, 查看我们刚才那个服务的属性 - - > 登陆, 其中"允许服务与桌面交互 "是不打钩的.怎么办?呵呵, 回到IDE, 注意那个布尔属性: Interactive, 当这个属性为True的时候, 该服务程序就可以与桌面交互了.

file - - > New - - > Form为服务添加窗口FrmMain, 单元保存为Unit_FrmMain, 并且把这个窗口设置为手工创建.完成后的代码如下:


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.


主窗口单元如下:

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)关于更多服务程序的演示程序, 请访问以下Url: http: //www.torry.net/pages.php?id=226,上面包含了多个演示如何控制和管理系统服务的代码.

(2)请切记: Windows实际上存在多个桌面.例如屏幕传输会出现白屏, 可能有两个原因: 一是系统处于锁定或未登陆桌面, 二是处于屏幕保护桌面.这时候要将当前桌面切换到该桌面才能抓屏.

(3)关于服务程序与桌面交互, 还有种动态切换方法.大概单元如下:
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实现的话, 单元如下:

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工具箱"的功能?首先, 根据进程名称来杀死进程是用以下函数:
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权限即可:
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;

使用方法:
EnableDebugPrivilege; //提升权限
KillTask(xxxx.exe); //关闭该服务程序.

 (此文原出处:http://www.programbbs.com/doc/379.htm

原文地址:https://www.cnblogs.com/bingege/p/1946923.html