【问题标题】:How to Debug a Windows Service如何调试 Windows 服务
【发布时间】:2011-07-01 03:54:36
【问题描述】:

我已经使用Code Project 文章创建了一个 Windows 服务。我可以使用 -i 和 -d 开关安装服务和删除服务。

我可以在 services.msc 中看到该服务,但是当我启动该服务时它什么也不做。下面我将介绍服务主要代码:

void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
  DWORD status;
  DWORD specificError;
  m_ServiceStatus.dwServiceType = SERVICE_WIN32;
  m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  m_ServiceStatus.dwWin32ExitCode = 0;
  m_ServiceStatus.dwServiceSpecificExitCode = 0;
  m_ServiceStatus.dwCheckPoint = 0;
  m_ServiceStatus.dwWaitHint = 0;

  m_ServiceStatusHandle = RegisterServiceCtrlHandler("Service1", 
                                            ServiceCtrlHandler); 
  if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
  {
    return;
  }
  m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  m_ServiceStatus.dwCheckPoint = 0;
  m_ServiceStatus.dwWaitHint = 0;
  if (!SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus))
  {
  }

  bRunning=true;
  while(bRunning)
  {

    Sleep(150000);
    ShellExecute(NULL, "open", "C:\\", NULL, NULL, SW_SHOWNORMAL);

  }
  return;
}

但是当我启动服务时,它既不会休眠也不会启动资源管理器。我错过了什么吗?

【问题讨论】:

  • Explorer 始终在 Windows 上运行,因此不会重新启动它。查看您的任务管理器,了解正在发生的事情。
  • 您对这段代码的期望是什么? “当我启动服务时它什么也不做”是什么意思?如果您希望某个窗口出现,您应该更改服务属性并设置“允许服务与桌面交互”复选框。
  • 您似乎正试图每 150 秒打开一个新的资源管理器窗口(假设该服务被标记为“允许桌面交互)。如果这是您的所有服务,您最好设置设置调度程序任务来执行此操作。

标签: c++ windows windows-services window servicecontroller


【解决方案1】:

使用下面的代码来调试你的服务,把它放在服务启动函数中,它会给你一个弹出窗口并保持执行直到你说OK或直到60秒,把断点放在下一个执行语句中,你可以继续调试 -

包括这个标题-

#include <Wtsapi32.h>
#pragma comment( lib, "Wtsapi32.lib" )

代码-

wchar_t title[] = L"mrnservice in startup - 60 seconds to take action";
wchar_t message[] = L"To debug, first attach to the process with Visual "
                    L"Studio, then click OK. If you don't want to debug, "
                    L"just click OK without attaching";
DWORD consoleSession = ::WTSGetActiveConsoleSessionId();
DWORD response;
BOOL ret = ::WTSSendMessage( WTS_CURRENT_SERVER_HANDLE,
                            consoleSession,
                            title, sizeof(title),
                            message, sizeof(message),
                            MB_OK,
                            60,
                            &response,
                            TRUE );

【讨论】:

    【解决方案2】:

    或者,可以将 OutputDebugString() 放入服务应用程序中,并且可以在 DbgView 中查看打印结果。我已经完成它来调试我的服务应用程序。 希望这对某人有所帮助..

    【讨论】:

      【解决方案3】:

      Ferruccio 建议将调试器附加到正在运行的服务是一个很好的建议,建议包含一个作为控制台应用程序运行的选项(尽管这对您的情况没有帮助)。

      要调试启动代码,您可以在启动代码的开头调用DebugBreak()。这将启动调试器并暂停执行您的服务。进入调试器后,设置所需的任何断点,然后继续执行。

      【讨论】:

      • @Dims 所以要么服务在它开始执行你的代码之前崩溃(你放置 DebugBreak() 的地方),要么你搞错了代码的哪一部分首先被执行。首先,确认 DebugBreak() 可以作为一个非常简单的控制台可执行文件的第一行。 (您可能没有配置 JIT 调试。)一旦工作正常,请再次尝试该服务。如果您确定自己要执行的第一段代码是 DebugBreak() 并且它仍然没有进入调试器,那么这意味着它在服务框架中崩溃了。获取一个新框架。
      【解决方案4】:

      您始终可以在调试模式下构建服务并将调试器附加到正在运行的服务。这种技术的唯一问题是您无法调试服务启动代码。出于这个原因,而且为了调试它而不断注册/取消注册/启动/停止服务可能会很痛苦,我总是编写服务,以便它们也可以作为命令行程序运行。

      如果StartServiceCtrlDispatcher() 失败并且GetLastError() 返回ERROR_FAILED_SERVICE_CONTROLLER_CONNECT,您的服务可以判断它是从命令行启动的。

      当然,当您从命令行运行服务时,它可以访问桌面,而服务通常不能访问桌面,并且它在当前登录用户的上下文中运行,而不是在 LocalSystem 或指定帐户的上下文中运行,所以以这种方式调试服务时,您需要考虑这些差异。

      【讨论】:

        【解决方案5】:

        我有一些关于调试 Windows 服务 here 的一般提示,但乍一看我认为这是您使用 ShellExecute 需要桌面交互的事实。服务通常在LocalService 帐户上运行,因此它与物理桌面没有连接。

        【讨论】:

          【解决方案6】:

          我建议编写一个小 Logger-Class,将信息写入文本文件。然后你可以例如放一些类似的东西:

          if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
          {
              Logger.LogError("Service handler is 0.");
              return;
          }    
          
          while(running) {
          
             Logger.LogInfo("I am running.");
          
             //...
          }
          

          【讨论】:

            【解决方案7】:

            服务是无头的,因此尝试启动任何与 GUI 相关的东西都不会产生可见的效果。 ShellExecute 将在服务的可视上下文中启动应用程序,而您的桌面将无法看到。

            如果您想证明您的服务正在做某事,请改为将某些内容写入文件系统(或者相信它正在运行,因为服务管理器可以告诉您是否没有运行)。

            【讨论】:

              猜你喜欢
              • 2011-07-06
              • 2011-02-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多