最近在编写Windows服务程序,服务程序的启动不像一般的exe程序双击即可运行,它需要通过SCM管理器来启动。所以调试它,在VC中和VS中按F5或者F10都是不行的,这样它启动不起来。而通过SCM管理器来启动,我们编写的服务又直接启动了,脱离了我们的调试环境,也没法调试。
网上说了种“附加到进程”的方式,这的确是一种正道。只是一开始你摸不着门道,也不知道如何下手。
我写了个测试的服务程序,源码见:
该服务程序启动后,会将当前时间写入StartTime.txt文件,并将运行日志写入log文件夹。完成后,就退出,所以这一过程非常短。如果采取“附加到进程”这种方式,当我还没有把“附加到进程”这个对话框打开,服务程序就运行完毕终止了。
第二种情况,服务程序运行后,工作线程在运行,主线程一般会运行一个循环等待。如果我们要调试循环之前的代码,或者想从服务一开始启动就进入调试,这样“附加到进行”方式也是有问题。附加的进程是正在运行的进程,刚开始启动的代码已经运行过了,想要下断点是不可能的。
针对这两种情况,我想到了一个比较好的解决办法。
就是在使用SetServiceStatus报告SCM管理器服务正在启动之后,使用一个Sleep函数,先暂停30秒或更多,以便你有足够的时间来操作(把进程附加到调试器中)。
这个方法比较有效,我试过了。看下面的例子代码,Sleep(30000)所在的位置。要注意的是Sleep(30000)要在报告SCM服务启动状态之后,否则服务会启动异常。因为SCM在启动服务后,必须在短时间内知道服务的启动状态,而Sleep之后,将无法及时获取服务状态,所以Sleep必须在报告状态之后。
void WINAPI ServiceMain()
{
HANDLE hThread = NULL;
DWORD dwThreadID = 0;
CSerCtrl.WriteToLog("ServiceMain开始!",sizeof("ServiceMain开始!"));
//DebugBreak();
//初始化
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwServiceType = SERVICE_WIN32;
hStatus = RegisterServiceCtrlHandl er(tzServiceName,(LPHANDLER_FUNCTION)ServiceCtrlHandle);
if (hStatus == (SERVICE_STATUS_HANDLE)0)
{
CSerCtrl.WriteToLog("RegisterServiceCtrlHandl er启动失败!",sizeof("RegisterServiceCtrlHandl er启动失败!"));
return;
}
CSerCtrl.WriteToLog("RegisterServiceCtrlHandl er成功!",sizeof("RegisterServiceCtrlHandl er成功!"));
//报告正在启动
SetServiceStatus(hStatus,&ServiceStatus);
CSerCtrl.WriteToLog("SetServiceStatus成功!",sizeof("SetServiceStatus成功!"));
//创建一个事件进行同步
hEventEnd = CreateEvent(NULL,TRUE,FALSE,NULL);
if (hEventEnd == NULL)
{
CSerCtrl.WriteToLog("CreateEvent失败!",sizeof("CreateEvent失败!"));
return;
}
ResetEvent(hEventEnd);
CSerCtrl.WriteToLog("CreateEvent成功!",sizeof("CreateEvent成功!"));
//报告启动完毕
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus,&ServiceStatus);
//暂停30秒,在这一句代码的后面下断点。
//在这段时间中,使用VC或者VS打开“附加到进程”,找到这个程序“StartTimeService.exe”,确定附加。
//时间到了,就中断了。
Sleep(30000);
//创建运行线程
hThread = CreateThread(NULL,0,ThreadMain,NULL,NULL,&dwThreadID);
if (!hThread)
{
SetEvent(hEventEnd);
}
CloseHandle(hThread);
CSerCtrl.WriteToLog("CreateThread成功!",sizeof("CreateThread成功!"));
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus,&ServiceStatus);
//等待事件退出
CSerCtrl.WriteToLog("WaitForSingleObject开始!",sizeof("WaitForSingleObject开始!"));
WaitForSingleObject(hEventEnd,INFINITE);
CSerCtrl.WriteToLog("WaitForSingleObject结束!",sizeof("WaitForSingleObject结束!"));
CSerCtrl.WriteToLog("ExitThread结束!",sizeof("ExitThread结束!"));
CloseHandle(hEventEnd);
//报告停止状态
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus,&ServiceStatus);
CSerCtrl.WriteToLog("ServiceMain结束!",sizeof("ServiceMain结束!")); }
From:http://blog.sina.com.cn/s/blog_87c9cb300101ce7k.html