使用VS C++ 2005使用ATL编写一个Windows服务,发现不知道如何单步调试。msdn的说法是:
如何:调试 Windows 服务应用程序更新:2007 年 11 月由于服务必须从服务控制管理器的上下文中运行,而不是从 Visual Studio 中运行,因此调试服务不像调试其他 Visual Studio 应用程序类型那样简单。若要调试服务,必须首先启动服务,然后将一个调试器附加到正在运行服务的进程中。然后可以使用 Visual Studio 的所有标准调试功能来调试应用程序。 我将程序编译成功后,在“管理工具”中的服务管理器中其中已经注册的服务,然后VS 2005的菜单栏“调试”——〉“附加到进程”,在可用进程列表中选择我编写的windows服务,接着在程序中设置断点,按F5开始调试,但是总是进入不了我的那个函数。但是如果我采用写日志的方式进行调试,发现确是可以进入那个函数的。 网上的另外一个说法是:可以先不注册成服务,按普通的exe程序那样执行,就可以调试了。 但是我试过了。也不行。 我的主要代码是这样的:
#include "stdafx.h"
#include "resource.h"
#include "StartThunder.h"#include <stdio.h>class CStartThunderModule : public CAtlServiceModuleT< CStartThunderModule, IDS_SERVICENAME >
{
public :
DECLARE_LIBID(LIBID_StartThunderLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_STARTTHUNDER, "{B3B6CFFE-DDFE-4397-88DC-B3DBE7D68D82}")
HRESULT InitializeSecurity() throw()
{
// TODO : 调用 CoInitializeSecurity 并为服务提供适当的
// 安全设置
// 建议 - PKT 级别的身份验证、
// RPC_C_IMP_LEVEL_IDENTIFY 的模拟级别
// 以及适当的非 NULL 安全说明符。 return S_OK;
} //HRESULT PreMessageLoop(int nShowCmd) throw(); // HRESULT PostMessageLoop() throw(); HRESULT RegisterAppId(bool bService = false) throw(); HRESULT Start(int nShowCmd) throw(); HRESULT Run(int nShowCmd = SW_HIDE)throw();
};HRESULT CStartThunderModule::Start(int nShowCmd) throw()
{
// HRESULT hr = __super::Start(nShowCmd); HRESULT hr = S_OK; if (SUCCEEDED(hr))
{
// 通过注册表获取迅雷的路径
// 打开键
HKEY hKEY;
LPCTSTR Rgspath = _T("SOFTWARE\\Thunder Network\\ThunderOem\\thunder_backwnd");
LONG ret = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,Rgspath,0, KEY_READ, &hKEY); if(ret != ERROR_SUCCESS)
{
RegCloseKey(hKEY);
return S_FALSE;
}
// 读取键值内容
DWORD dwInfoSize;
DWORD type = REG_SZ;
BYTE UserInfo[255];
/*
注意RegQueryValueEx最后一个参数是个双向参数,入参时表示的是前一个参数的缓冲区大小,出参时表示的是返回的大小。
所以最好把UserInfo的大小给dwInfoSize,防止UserInfo溢出。
*/
dwInfoSize = sizeof(UserInfo)/sizeof(BYTE);
// added end
ret = ::RegQueryValueEx(hKEY, _T("Path"), NULL, &type, UserInfo, &dwInfoSize);
if(ret!=ERROR_SUCCESS)
{
LPVOID lpMsgBuf;
DWORD dw = ::GetLastError(); ::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
::MessageBox(NULL,(LPCTSTR)lpMsgBuf,_T("系统错误"),MB_OK|MB_ICONSTOP);
::LocalFree(lpMsgBuf);
::RegCloseKey(hKEY);
return S_FALSE;
} _tfopen(_T("C:\\Thunder.txt"),_T("w"));
}
return hr;
}
HRESULT CStartThunderModule::RegisterAppId(bool bService) throw()
{
HRESULT hr = S_OK;
BOOL res = __super::RegisterAppId(bService); if (bService)
{
if (IsInstalled())
{
SC_HANDLE hSCM = ::OpenSCManagerW(NULL, NULL, SERVICE_CHANGE_CONFIG);
SC_HANDLE hService = NULL;
if (hSCM == NULL)
hr = AtlHresultFromLastError();
else
{
hService = ::OpenService(hSCM, m_szServiceName, SERVICE_CHANGE_CONFIG);
if (hService != NULL)
{
TCHAR szDisplayName[128];
ZeroMemory(szDisplayName, 128);
lstrcpy(szDisplayName, _T("迅雷自动启动"));
::ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, NULL, NULL, NULL, NULL, NULL, NULL, NULL, szDisplayName); SERVICE_DESCRIPTION Description;
TCHAR szDescription[1024]; ZeroMemory(szDescription, 1024);
ZeroMemory(&Description, sizeof(SERVICE_DESCRIPTION));
lstrcpy(szDescription, _T("XXX软件有限公司 版权所有(R) 2001-2008"));
Description.lpDescription = szDescription;
::ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &Description); ::CloseServiceHandle(hService);
}
else
hr = AtlHresultFromLastError(); ::CloseServiceHandle(hSCM);
} }
}
return hr;
}HRESULT CStartThunderModule::Run(int nShowCmd)throw()
{
HRESULT hr = S_OK; hr = ::CoInitialize(NULL); Start(nShowCmd);
hr = __super::PreMessageLoop(nShowCmd);
if (hr == S_OK)
{
if (m_bService)
{
//可以在这里启动线程,或者什么其他东西来做自己的工作的啦
//这里是什么都没有做了,只输出一条信息
// LogEvent(_T("widebright 的服务启动咯,呵呵 "));
SetServiceStatus(SERVICE_RUNNING);
}
//进入消息循环,不停的处理消息,可能最后分发到Handler去处理,调用了OnShutdown等函数的。
__super::RunMessageLoop();
} if (SUCCEEDED(hr))
{
hr = PostMessageLoop();
} //可以在适当的时候调用Uninstall函数来卸载掉服务
//__super::Uninstall(); ::CoUninitialize(); return hr;
}
CStartThunderModule _AtlModule;//
extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/, int nShowCmd)
{
return _AtlModule.WinMain(nShowCmd);
}
如何:调试 Windows 服务应用程序更新:2007 年 11 月由于服务必须从服务控制管理器的上下文中运行,而不是从 Visual Studio 中运行,因此调试服务不像调试其他 Visual Studio 应用程序类型那样简单。若要调试服务,必须首先启动服务,然后将一个调试器附加到正在运行服务的进程中。然后可以使用 Visual Studio 的所有标准调试功能来调试应用程序。 我将程序编译成功后,在“管理工具”中的服务管理器中其中已经注册的服务,然后VS 2005的菜单栏“调试”——〉“附加到进程”,在可用进程列表中选择我编写的windows服务,接着在程序中设置断点,按F5开始调试,但是总是进入不了我的那个函数。但是如果我采用写日志的方式进行调试,发现确是可以进入那个函数的。 网上的另外一个说法是:可以先不注册成服务,按普通的exe程序那样执行,就可以调试了。 但是我试过了。也不行。 我的主要代码是这样的:
#include "stdafx.h"
#include "resource.h"
#include "StartThunder.h"#include <stdio.h>class CStartThunderModule : public CAtlServiceModuleT< CStartThunderModule, IDS_SERVICENAME >
{
public :
DECLARE_LIBID(LIBID_StartThunderLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_STARTTHUNDER, "{B3B6CFFE-DDFE-4397-88DC-B3DBE7D68D82}")
HRESULT InitializeSecurity() throw()
{
// TODO : 调用 CoInitializeSecurity 并为服务提供适当的
// 安全设置
// 建议 - PKT 级别的身份验证、
// RPC_C_IMP_LEVEL_IDENTIFY 的模拟级别
// 以及适当的非 NULL 安全说明符。 return S_OK;
} //HRESULT PreMessageLoop(int nShowCmd) throw(); // HRESULT PostMessageLoop() throw(); HRESULT RegisterAppId(bool bService = false) throw(); HRESULT Start(int nShowCmd) throw(); HRESULT Run(int nShowCmd = SW_HIDE)throw();
};HRESULT CStartThunderModule::Start(int nShowCmd) throw()
{
// HRESULT hr = __super::Start(nShowCmd); HRESULT hr = S_OK; if (SUCCEEDED(hr))
{
// 通过注册表获取迅雷的路径
// 打开键
HKEY hKEY;
LPCTSTR Rgspath = _T("SOFTWARE\\Thunder Network\\ThunderOem\\thunder_backwnd");
LONG ret = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,Rgspath,0, KEY_READ, &hKEY); if(ret != ERROR_SUCCESS)
{
RegCloseKey(hKEY);
return S_FALSE;
}
// 读取键值内容
DWORD dwInfoSize;
DWORD type = REG_SZ;
BYTE UserInfo[255];
/*
注意RegQueryValueEx最后一个参数是个双向参数,入参时表示的是前一个参数的缓冲区大小,出参时表示的是返回的大小。
所以最好把UserInfo的大小给dwInfoSize,防止UserInfo溢出。
*/
dwInfoSize = sizeof(UserInfo)/sizeof(BYTE);
// added end
ret = ::RegQueryValueEx(hKEY, _T("Path"), NULL, &type, UserInfo, &dwInfoSize);
if(ret!=ERROR_SUCCESS)
{
LPVOID lpMsgBuf;
DWORD dw = ::GetLastError(); ::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
::MessageBox(NULL,(LPCTSTR)lpMsgBuf,_T("系统错误"),MB_OK|MB_ICONSTOP);
::LocalFree(lpMsgBuf);
::RegCloseKey(hKEY);
return S_FALSE;
} _tfopen(_T("C:\\Thunder.txt"),_T("w"));
}
return hr;
}
HRESULT CStartThunderModule::RegisterAppId(bool bService) throw()
{
HRESULT hr = S_OK;
BOOL res = __super::RegisterAppId(bService); if (bService)
{
if (IsInstalled())
{
SC_HANDLE hSCM = ::OpenSCManagerW(NULL, NULL, SERVICE_CHANGE_CONFIG);
SC_HANDLE hService = NULL;
if (hSCM == NULL)
hr = AtlHresultFromLastError();
else
{
hService = ::OpenService(hSCM, m_szServiceName, SERVICE_CHANGE_CONFIG);
if (hService != NULL)
{
TCHAR szDisplayName[128];
ZeroMemory(szDisplayName, 128);
lstrcpy(szDisplayName, _T("迅雷自动启动"));
::ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, NULL, NULL, NULL, NULL, NULL, NULL, NULL, szDisplayName); SERVICE_DESCRIPTION Description;
TCHAR szDescription[1024]; ZeroMemory(szDescription, 1024);
ZeroMemory(&Description, sizeof(SERVICE_DESCRIPTION));
lstrcpy(szDescription, _T("XXX软件有限公司 版权所有(R) 2001-2008"));
Description.lpDescription = szDescription;
::ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &Description); ::CloseServiceHandle(hService);
}
else
hr = AtlHresultFromLastError(); ::CloseServiceHandle(hSCM);
} }
}
return hr;
}HRESULT CStartThunderModule::Run(int nShowCmd)throw()
{
HRESULT hr = S_OK; hr = ::CoInitialize(NULL); Start(nShowCmd);
hr = __super::PreMessageLoop(nShowCmd);
if (hr == S_OK)
{
if (m_bService)
{
//可以在这里启动线程,或者什么其他东西来做自己的工作的啦
//这里是什么都没有做了,只输出一条信息
// LogEvent(_T("widebright 的服务启动咯,呵呵 "));
SetServiceStatus(SERVICE_RUNNING);
}
//进入消息循环,不停的处理消息,可能最后分发到Handler去处理,调用了OnShutdown等函数的。
__super::RunMessageLoop();
} if (SUCCEEDED(hr))
{
hr = PostMessageLoop();
} //可以在适当的时候调用Uninstall函数来卸载掉服务
//__super::Uninstall(); ::CoUninitialize(); return hr;
}
CStartThunderModule _AtlModule;//
extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/, int nShowCmd)
{
return _AtlModule.WinMain(nShowCmd);
}
解决方案 »
- Vc++连接oracle数据库有哪几种方法?
- socket 封包封包封包,我还是不明白
- [求助] missing type specifier - int assumed. Note: C++ does not support default-int,这是什么问题?如何解决呀?
- 谁到有那些好的开源的VR(虚拟现实)程序?
- 怎么打印FormView看到的内容呢? 还是200分哦.
- 关于切分窗口
- 终于拥有了C++PRIMER
- 请教一个关于CompatibleDC的问题!
- 得到外部程序listbox的数据失败
- database数据库的问题
- ODBC数据刷新问题
- 如何给EDIT 添加WM_CHAR消息处理
在列表中找到你的服务,单击右键选择启动即可。
不过事实上,程序是进入了某些函数的,比如_tWinMain启动函数等等,你可以在_tWinMain处设置断点试一试
我也很想知道怎么调试服务程序,原来的做法是写个相同功能的EXE,当EXE没问题后,再做成服务。如果发现服务程序和原来的EXE有差异,只好写日志了。
__asm int 3;
生成程序后正常启动服务,当服务程序执行到上述代码时,会产生一个异常被VC捕获到,然后即可开始调试。
呵呵,好像DebugBreak也可以。
不过貌似不是正宗的方法吧。MSDN上的方法,应该是比较标准的。
MSDN上说,需要启动服务,不知道楼主的服务启动了没?
看到了注册的服务,未必说服务就启动了。
我是先启动服务,再在VS 2005里进入调试状态,再Attach to Process.貌似顺序搞错了,应该是先在VS 2005里进入调试状态,再启动服务,,接着再Attach to Process啊!
_ASSERT( 0 );然后启动服务时候出错,按下重试调试即可。如果要断的地方是在初始化代码里,要在15秒内调试完成或F5跳过,否则会被SCM杀掉