如何调试Windows服务

时间:2011-02-21 09:38:48

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

我使用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;
}

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

7 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:3)

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

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

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

答案 2 :(得分:0)

服务是无头的,因此尝试启动任何与GUI相关的操作都将导致无效。 ShellExecute会在服务的可视上下文中启动一个应用程序,桌面将无法看到该应用程序。

如果你想证明你的服务正在做某事,那就把一些东西写到文件系统(或者相信它正在运行,因为服务管理员已经准备好告诉你它是不是)。

答案 3 :(得分:0)

我建议写一个Logger-Class,它将信息写入文本文件。然后你可以,例如像这样的东西:

if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
{
    Logger.LogError("Service handler is 0.");
    return;
}    

while(running) {

   Logger.LogInfo("I am running.");

   //...
}

答案 4 :(得分:0)

我有一些关于调试Windows服务here的一般提示,但初看起来我认为你使用的ShellExecute需要桌面交互。服务通常在LocalService帐户上运行,因此它与物理桌面无关。

答案 5 :(得分:0)

或者,可以将OutputDebugString()放入服务应用程序中,并在DbgView中看到打印件。我已经完成了它来调试我的服务应用程序。 希望这有助于某人..

答案 6 :(得分:0)

使用下面的代码调试服务,将其置于服务启动功能中,它将弹出一个窗口并保留执行,直到您说确定或直到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 );