2010-05-21 113 views

回答

6

是的,有: Debugging services: an easy way

你用Delphi创建服务? 那么也许你也在烦恼 耗时的启动方式, 重启,查杀和附加到 服务进程申请每 时间。那么,有补救措施。

您不需要这样做。而是运行 德尔福作为一个系统应用程序,并做 一些小的适应服务 代码。

+0

RunAsSys听起来不错。您链接的文章中的示例代码使用条件定义来选择“模式”。你知道RunAsSys是否允许选择调试模式而不必重建应用程序?即使用命令行参数进入调试模式,而不是作为服务运行? – 2010-05-21 19:43:54

+0

我不确定,但是您似乎可以自己添加该功能。 – Mick 2010-05-24 14:03:03

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的控制代码,并且仍然可以停止并即使每工作者线程冻结的机会也会启动服务。

该方法允许您调试服务应用程序代码,但涉及相当数量的代码,并将几个挂钩放入Windows API函数中以正常工作。在短时间内显示在这里太多了。也许我会在一天的文章中写下它。与此同时,如果你不想自己编码,你有两种选择。或者去SVCOM这样的库,或者Mick提到的那个库,它们都是为你做的,或者是在调试模式下绕过服务代码,然后“简单”地将服务作为“普通”表单应用程序启动。你将不得不从你的TService后代的代码/事件处理程序中分离出你的服务的真正功能,但是由于上述原因,我推荐这么做。

+0

我有与表单和服务相同的应用程序。使用表单工作。有了服务,它不起作用。 – 2010-05-24 12:10:15

+0

@Marjan Venema DebugService位于哪个单元? – 2017-10-12 23:54:26

+0

@SpongebobComrade没有。这是你自己写的东西。守则第一段提到它应该做的事。查看其他答案以获取更多信息。 – 2017-10-13 12:40:35

25

您可以从Colin Wilson's NT Low Level Utilities(网页已不复存在,available in the wayback machine

使用unitDebugService.pas然后在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. 

这样你就可以从内部德尔福调试运行(通过设置项目调试器参数),使用EXE作为服务,或者使用-DEBUG开关和命令行运行。

13

使用运行 - >附加到进程。通过这种方式,您可以在不对代码进行任何更改的情况下调试服务。唯一棘手的部分可能是调试服务启动代码,因为连接可能需要一些时间,并且启动必须在30几秒内发生(尽管您可以调整Windows以允许更长的时间)。您可以使用延迟(sleep ...)让您及时附加,或者如果您只需要查看可以使用OutputDebugString()打印到调试输出(使用Delphi事件视图来查看它)会发生什么情况。

+0

我试过这个,但只出现了汇编代码的cpu窗口。 – 2010-05-24 12:06:09

+0

'附加到进程'工作正常。当调试器第一次连接到服务进程时,CPU窗口确实出现,但您可以简单地关闭它,然后按F9或运行按钮继续正常执行服务,然后像其他任何项目一样调试其代码。 – 2013-11-21 18:53:16

+1

这工作正常。如果您不希望CPU窗口弹出,您可以取消选中“附加后暂停”复选框。 – GolezTrol 2013-12-18 14:34:18

5

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

那么你只应该解决这个问题。

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

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

如果由于某种原因,在开始调试后,CPU只能查看服务的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. 进行完全重建(项目/全部构建)。
  9. 运行您的服务。
+0

这种方法工作得很好。 – Turrican 2015-05-26 12:22:55

13

这其实很简单。只需使用标准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. 
+0

这是一个很好的方法!我们需要写代码,真的,但没有第三部分单位,功能或复杂的Windows注册表配置 – 2015-12-10 20:09:40

+0

exacly我正在寻找。谢谢。 upvoted。 – 2016-09-02 12:38:17