如何使用Delphi调试Windows服务?

时间:2010-05-21 18:38:40

标签: delphi debugging windows-services service

有没有办法用Delphi完全调试Windows服务?

6 个答案:

答案 0 :(得分:26)

您可以使用 Colin Wilson's NT Low Level Utilities 中的unitDebugService.pas(页面已消失,available in the wayback machine

然后在DPR中:

begin
  if (paramCount > 0) and (SameText(ParamStr(1), '-DEBUG')) then
  begin
    FreeAndNil (Application);
    Application := TDebugServiceApplication.Create(nil);
  end;

  //... the rest of the normal DPR code
end.

通过这种方式,您可以在Delphi中运行调试(通过设置项目调试器参数),使用EXE作为服务,或使用-DEBUG开关从命令行运行,并且。

答案 1 :(得分:18)

实际上很容易。只需使用标准的DEBUG编译器指令即可将服务作为控制台应用程序而非服务启动。

program MyServiceApp;

{$ifdef DEBUG}
  {$APPTYPE CONSOLE}
{$endif}

uses
  System.SysUtils,

[..]

begin
  {$ifdef DEBUG}
  try
    // In debug mode the server acts as a console application.
    WriteLn('MyServiceApp DEBUG mode. Press enter to exit.');

    // Create the TService descendant manually.
    ServerContainer1 := TServerContainer.Create(nil);

    // Simulate service start.
    ServerContainer1.ServiceStart(ServerContainer1, MyDummyBoolean);

    // Keep the console box running (ServerContainer1 code runs in the background)
    ReadLn;

    // On exit, destroy the service object.
    FreeAndNil(ServerContainer1);
  except
    on E: Exception do
    begin
      Writeln(E.ClassName, ': ', E.Message);
      WriteLn('Press enter to exit.');
      ReadLn;
    end;
  end;
  {$else}
  // Run as a true windows service (release).
  if not Application.DelayInitialize or Application.Installing then
    Application.Initialize;
  Application.CreateForm(TServerContainer, ServerContainer1);
  Application.Run;
  {$endif}
end.

答案 2 :(得分:14)

使用Run - >附加到流程。这样,您可以调试服务,而无需对其代码进行任何更改。唯一棘手的部分可能是调试服务启动代码,因为附加可能需要一些时间,并且启动必须在30秒内完成(尽管您可以调整Windows以允许更长的时间)。您可以使用延迟(睡眠...)来允许您及时附加,或者如果您只是需要查看会发生什么,您可以使用OutputDebugString()打印到调试输出(使用Delphi事件视图查看它)。

答案 3 :(得分:6)

是的,有: Debugging services: an easy way

  

您是否使用Delphi创建服务?   那么也许你也对此感到恼火   耗时的开始方式,   重启,杀戮和附加   每个服务流程应用程序   时间。好吧,有补救措施。

     

您不需要这样做。而是跑   Delphi作为SYSTEM应用程序而且做到了   一些小的适应服务   代码。

答案 4 :(得分:5)

  

我试过这个,但只出现带有汇编代码的cpu窗口。

那你只能解决这个问题。

基本上,要调试Win2服务,有几种方法:

  • 使用“附加到进程”命令将调试器附加到已运行的服务。如果需要在一开始就附加,可以插入启动延迟以有时间附加调试器。但是,您还必须调整系统以增加服务超时。
  • 在服务启动时使用"Image File Execution Options" registry key强制运行Delphi的调试器。有关系统超时的相同注意事项适用。
  • 将服务临时转换为常规应用程序并在调试器下正常运行。您可以在不同的用户帐户下重新启动IDE以获得“服务”的更多权限。

如果由于某种原因在开始调试后只有您的服务的CPU视图 - 这意味着Delphi的调试器无法找到您的服务的调试信息。这是一个不同的问题,您应该搜索解决方案。

通常,您需要这样做:

  1. 确保服务应用程序的输出文件夹设置为系统将从中加载的文件夹。即如果您的服务位于C:\ Windows \ System32 - 然后将输出文件夹设置为C:\ Windows \ System32。不要将.exe文件从输出文件夹中复制到其他位置。对于64个系统,您可以尝试别名(sysnative / SysWOW64)或真实姓名。我认为最好将输出路径设置为项目文件夹并重新注册要从项目文件夹加载的服务。
  2. (可选)将DCU的输出路径设置为与.exe文件相同的文件夹。
  3. 删除所有DCU文件。
  4. 确保在项目选项的“编译器”页面上启用调试选项。
  5. (可选)此外,您还可以在“链接器”页面上包含TD32 / RSM / MAP选项。
  6. 确保没有IDE专家/扩展程序,这可能会修改这些文件的.exe文件,调试信息或文件修改日期。
  7. 确保其他位置没有旧文件(DCU / exe)。
  8. 进行完全重建(Project / Build all)。
  9. 运行您的服务。

答案 5 :(得分:3)

是的。

在你的dpr中:

Application.CreateForm(TMyService, MyService);

_ServiceInDebugMode := SysUtils.FindCmdLineSwitch('DEBUG', True);
if _ServiceInDebugMode then
  DebugService(MyService)
else
  SvcMgr.Application.Run;

DebugService是一个创建调试表单,服务控制线程并通过调用Forms.Application.Run来启动所有内容的过程。

您可以将服务控制线程与Windows的SCM(服务控制管理器)进行比较,调试表单与一个与SCM通信的应用程序(例如services.msc)来启动和停止服务。该服务还应该有自己的线程(服务线程)来响应来自SCM或我们的服务控制线程的控制代码以及一个或多个单独的线程来完成其实际工作。您需要单独的线程用于实际工作(而不是在TService后代的事件处理程序中对其进行编码),以确保TService本身运行的线程始终可以自由响应来自SCM的控制代码,您仍然可以停止并且即使每次机会a /工作线程被冻结,也要启动服务。

这种方法也允许您调试服务应用程序代码,但涉及大量代码并将一些挂钩放入windows api函数中以正常工作。在短时间内显示太多。也许我有一天会在一篇文章中写下来。

与此同时,如果您不想自己编码,您有两种选择。要么使用像SVCOM这样的库,要么使用Mick提到的库来为您完成所有这些工作,或者在调试模式下将服务代码全部一起通过并“简单地”将您的服务作为“普通”表单应用程序启动。您必须从TService后代的代码/事件处理程序中解开服务的实际功能,但出于上述原因,这是我建议的。