vc windows服务程序调试

80 篇文章 2 订阅
44 篇文章 0 订阅

最近在编写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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值