vc windows服务程序调试



最近在编写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 = RegisterServiceCtrlHandler(tzServiceName,(LPHANDLER_FUNCTION)ServiceCtrlHandle);
 if (hStatus == (SERVICE_STATUS_HANDLE)0)
 {
  CSerCtrl.WriteToLog("RegisterServiceCtrlHandler启动失败!",sizeof("RegisterServiceCtrlHandler启动失败!"));
  return;
 }
 CSerCtrl.WriteToLog("RegisterServiceCtrlHandler成功!",sizeof("RegisterServiceCtrlHandler成功!"));
 //报告正在启动
 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


展开阅读全文

没有更多推荐了,返回首页