none
调用StartServiceCtrlDispatcher()出现异常。 RRS feed

  • 问题

  • vs2008 sp1下程序编译通过,运行到StartServiceCtrlDispatcher(entry);这一句发生异常

    0xC0000005:读取位置0xcccccccc时发生访问冲突

    0xC0000005:拒绝访问

    并且无法捕获。

    求解。

    2019年8月14日 2:39

答案

  • 你好

    尝试main函数使用以下这段代码。

    int _tmain(int argc, _TCHAR **argv)
    {
    	//SERVICE_TABLE_ENTRY entrytable[] = 
    	//{ 
    	//	{(LPWSTR)"MyService", (LPSERVICE_MAIN_FUNCTION)ServiceMain},
    	//	{NULL, NULL} //"哨兵"
    	//};
    	SERVICE_TABLE_ENTRY entrytable[2];
    	CString cstr("MyService");
    	entrytable[0].lpServiceName = cstr.GetBuffer();
    	cstr.ReleaseBuffer();
    	entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
    	entrytable[1].lpServiceName = NULL;
    	entrytable[1].lpServiceProc = NULL;
    	StartServiceCtrlDispatcher(entrytable);//绑定服务
    	return 0;
    }

    SERVICE_TABLE_ENTRY结构数组要求最后一个成员组都为NULL,我们称之为“哨兵”(所有值都为NULL),表示该服务表末尾。一个服务启动后,马上调用StartServiceCtrlDispatcher()通知服务控制程序服务正在执行,并提供服务函数的地址。StartServiceCtrlDispatcher()只需要一个至少有两SERVICE_TABLE_ENTRY结构的数组,它为每个服务启动一个线程,一直等到它们结束才返回。

    这就是产生访问冲突的原因,当你的代码去结构数组中找第二个结构体元素时,但你的数组定义只有一个元素,因此发生访问越界,导致了访问冲突。

    Best Regards,

    Suarez Zhou

    • 已标记为答案 雨鹜 2019年8月15日 0:46
    2019年8月14日 9:40

全部回复

  • 你好,

    感谢你在这里发帖。

    >>0xC0000005:读取位置0xcccccccc时发生访问冲突

    发生访问冲突的可能有很多,而且一般错误都在这句之前就埋下了伏笔。这样的错误可能由于指针没有初始化,或者指针、数组越界访问造成的。查找具体报错的办法,只能是通过单步调试(调试+断点)这样的方式找到具体哪个指针出现了问题。

    在翻看过一些相关错误后,我建议你查看一下与这个函数相关的一些指针是否进行了初始化,极大可能使用了未初始化的指针导致了这个错误,在这个函数之前设置断点,然后查看代码中的指针数值是否有异常。或者如果你方便提供一下能还原这个错误的demo,我们将不甚感激。

    Best Regards,

    Suarez Zhou





    2019年8月14日 6:56
  • #include<Windows.h>
    #include<iostream>
    #include<atlstr.h>
    #include<fstream>
    #include<tchar.h>
    bool brun=false;
    SERVICE_STATUS servicestatus;//定义服务结构体变量,该结构体包含该服务的所有信息
    SERVICE_STATUS_HANDLE hstatus;//服务处理函数的句柄
    void WriteToLog(const std::string &str)//自定义的写日志函数
    {
    	std::ofstream p("D:/log.txt",std::ios::app);
    	if(!p.is_open())
    		return;
    	p<<str<<std::endl;
    	p.close();
    }
    void WINAPI CtrlHandler(DWORD request)
    {
    	switch(request)
    	{
    	case SERVICE_CONTROL_STOP:
    		brun=false;
    		servicestatus.dwCurrentState=SERVICE_STOPPED;
    		break;
    	case SERVICE_CONTROL_SHUTDOWN:
    		brun=false;
    		servicestatus.dwCurrentState=SERVICE_STOPPED;
    	}
    	SetServiceStatus(hstatus,&servicestatus);//更新服务状态
    }
    void WINAPI ServiceMain(int argc,char **argv)//服务的主函数
    {
    	servicestatus.dwServiceType=SERVICE_WIN32;//服务类型
    	servicestatus.dwCurrentState=SERVICE_START_PENDING;//服务当前的状态
    	servicestatus.dwControlsAccepted=SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_STOP;//服务接受以及在处理函数中处理的控制码
    	servicestatus.dwWin32ExitCode=0;//错误码
    	servicestatus.dwServiceSpecificExitCode=0;//特定于服务的错误码,用于在服务启动或关闭时报错;
    	servicestatus.dwCheckPoint=0;//检测点值
    	servicestatus.dwWaitHint=0;//估计时间
    	hstatus=::RegisterServiceCtrlHandler("MyService",CtrlHandler);//指定服务于处理函数
    	if(hstatus==0)//根据绑定的情况写日志
    	{
    		WriteToLog("RegisterServiceCtrlHandler failed");
    		return;
    	}
    	WriteToLog("RegisterServiceCtrlHandler success");
    	servicestatus.dwCurrentState=SERVICE_RUNNING;//更改服务的当前状态
    	SetServiceStatus(hstatus,&servicestatus);//为调用的服务更新服务状态管理器的状态信息
    	brun=true;
    	MEMORYSTATUSEX memstatus;//内存相关的结构体指针
    	char str[100];
    	memset(str,'\0',100);//初始化内存
    	while(brun)
    	{
    		GlobalMemoryStatusEx(&memstatus);//获取内存状态
    		SIZE_T availmb=memstatus.ullAvailPhys/1024/1024;//转换内存表现方式
    		sprintf_s(str,100,"available memory is %zdMB",availmb);
    		WriteToLog(str);
    		Sleep(2000);
    	}
    	WriteToLog("service stopped");
    }
    int _tmain(int argc,_TCHAR **argv)
    {
    	SERVICE_TABLE_ENTRY entrytable[1];
    	CString cstr("MyService");
    	entrytable[0].lpServiceName=cstr.GetBuffer();
    	cstr.ReleaseBuffer();
    	entrytable[0].lpServiceProc=(LPSERVICE_MAIN_FUNCTION)ServiceMain;
    	StartServiceCtrlDispatcher(entrytable);//绑定服务
    	return 0;
    }
    2019年8月14日 8:37
  • 我无法上传图片,提示需要验证账户。

    2019年8月14日 8:38
  • 你好,

    >>我无法上传图片,提示需要验证账户。

    访问下面这个链接,依照其他留言留下回复,稍后会为你验证账户。验证完就能上传图片了。

    https://social.technet.microsoft.com/Forums/en-US/dc4002e4-e3de-4b1e-9a97-3702387886cc/verify-account-42?forum=reportabug

    Best Regards,

    Suarez Zhou

    2019年8月14日 8:42
  • 你好

    尝试main函数使用以下这段代码。

    int _tmain(int argc, _TCHAR **argv)
    {
    	//SERVICE_TABLE_ENTRY entrytable[] = 
    	//{ 
    	//	{(LPWSTR)"MyService", (LPSERVICE_MAIN_FUNCTION)ServiceMain},
    	//	{NULL, NULL} //"哨兵"
    	//};
    	SERVICE_TABLE_ENTRY entrytable[2];
    	CString cstr("MyService");
    	entrytable[0].lpServiceName = cstr.GetBuffer();
    	cstr.ReleaseBuffer();
    	entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
    	entrytable[1].lpServiceName = NULL;
    	entrytable[1].lpServiceProc = NULL;
    	StartServiceCtrlDispatcher(entrytable);//绑定服务
    	return 0;
    }

    SERVICE_TABLE_ENTRY结构数组要求最后一个成员组都为NULL,我们称之为“哨兵”(所有值都为NULL),表示该服务表末尾。一个服务启动后,马上调用StartServiceCtrlDispatcher()通知服务控制程序服务正在执行,并提供服务函数的地址。StartServiceCtrlDispatcher()只需要一个至少有两SERVICE_TABLE_ENTRY结构的数组,它为每个服务启动一个线程,一直等到它们结束才返回。

    这就是产生访问冲突的原因,当你的代码去结构数组中找第二个结构体元素时,但你的数组定义只有一个元素,因此发生访问越界,导致了访问冲突。

    Best Regards,

    Suarez Zhou

    • 已标记为答案 雨鹜 2019年8月15日 0:46
    2019年8月14日 9:40
  • Writing a Service Program's main Function

    Visual C++ enthusiast, like network programming and driver development. At present is being engaged in the WinCE/Windows Mobile platform embedded development.

    2019年8月14日 9:50
    版主
  • 我的账户仍未验证。
    2019年8月15日 2:24
  • 你好,

    验证账户需要等到相关人员看到你的回复才会进行,请耐心等待。

    Best Regards,

    Suarez Zhou

    2019年8月15日 7:16