如何调试Windows服务

x759pob2  于 2022-12-14  发布在  Windows
关注(0)|答案(7)|浏览(159)

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

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

svujldwt

svujldwt1#

Ferruccio建议将调试器附加到正在运行的服务是一个很好的建议,包括一个作为控制台应用程序运行的选项也是一个很好的建议(尽管这对您的情况没有帮助)。
要调试启动代码,可以在启动代码的开头调用DebugBreak()。这将启动调试器并在该点暂停服务的执行。一旦进入调试器,设置所需的断点,然后继续执行。

gc0ot86w

gc0ot86w2#

你可以在调试模式下构建一个服务,并在运行的服务上附加一个调试器。这种技术的唯一问题是你不能调试服务的启动代码。由于这个原因,以及为了调试服务而不断注册/注销/启动/停止服务是一件痛苦的事情,我总是编写服务,以便它们也可以作为命令行程序运行。
如果StartServiceCtrlDispatcher()失败并且GetLastError()返回ERROR_FAILED_SERVICE_CONTROLLER_CONNECT,您的服务可以判断它是从命令行启动的。
当然,当您从命令行运行服务时,它可以访问桌面,而服务通常不能访问桌面,并且它是在当前登录用户的上下文中运行的,而不是在LocalSystem或指定帐户中运行的,因此在以这种方式调试服务时,您需要考虑这些差异。

1tu0hz3e

1tu0hz3e3#

使用以下代码调试您的服务,将其放入服务启动函数中,它将弹出窗口并保持执行,直到您说OK或直到60秒,将断点放入下一个执行语句中,然后您可以继续调试-
包含此标头-

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

代码-

wchar_t title[] = L"service 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 );
lymgl2op

lymgl2op4#

我建议写一个小的Logger-Class,它把信息写到一个文本文件中。然后你可以写一些东西,比如:

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

while(running) {

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

   //...
}
eni9jsuy

eni9jsuy5#

我在这里有一些调试windows服务的一般技巧,尽管乍一看我认为这是因为你使用的是需要桌面交互的ShellExecute,一个服务通常运行在LocalService帐户上,所以它没有连接到物理桌面。

4ktjp1zp

4ktjp1zp6#

服务是无头的,所以试图启动任何与GUI相关的东西都不会产生可见的效果。ShellExecute会在服务的可视上下文中启动一个应用程序,而桌面将无法看到它。
如果你想证明你的服务正在做一些事情,写一些东西到文件系统(或者相信它正在运行,因为服务管理器已经准备好告诉你它是否在运行)。

svdrlsy4

svdrlsy47#

或者,OutputDebugString()可以放在服务应用程序中,打印可以在DbgView中看到。我这样做是为了调试我的服务应用程序。希望这对某些人有帮助。

相关问题