将基于MFC的对话框应用程序修改为服务程序
2011-10-20 19:05
183 查看
Windows(NT/2000)下有很多服务程序(它们在系统登录前运行),它们一般都没有界面,我们可以在服务管理器(运行services.msc)中启动和关闭它们。下面我试着修改一个有界面的MFC对话框程序,使它成为一个服务程序。网上提到了一种方法就是,从建立一个COM服务程序入手,然后将一个MFC项目改造成服务程序,最后让这一程序在启动时可以显示图形界面。这种方法的优点就是,程序向导已经帮我们写好了服务程序的主要代码,我们的任务就是把它们移植到MFC程序中(这个方法很不错!)。我的方法和这种方法思想基本一致,但也不完全一样。我是直接将有些写在CUI服务程序中的代码移植过来。主要思想就是把主服务函数等定义为全局函数,这样在主对话框类中就可以访问它们了。 此程序需要注意的地方: 一次只能安装一个服务,如果已安装过一个服务,先将其卸载再安装其他服务,设置其他应用程序时,在SCM启动后,因没有相应启动请求会被kill掉。本来以为任何程序都可以被设置为服务程序,后来实验发现,一般的应用程序被设置为服务程序后,由于它不能够与SCM进行通信,所以SCM无法将其启动。错误提示如下:(下面wcdj是我的服务名字) 本地计算机无法启动wcdj服务 错误1053:服务没有及时响应启动或控制请求 这个服务程序的主要流程如下: SERVICE_TABLE_ENTRY DispatchTable[]={{"Service1",ServiceMain},{NULL,NULL}}; if (!StartServiceCtrlDispatcher(DispatchTable)) { AfxMessageBox("当不是用SCM启动程序的时候,程序执行下面的代码"); ... //显示我们服务程序的对话框 CTestDlg dlg; //m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } } 否则程序会执行回调函数: void WINAPI ServiceMain(DWORD argc, LPTSTR *argv) { AfxMessageBox("当用SCM启动程序的时候,程序执行下面的代码"); //初始化 m_ServiceStatus.dwServiceType = SERVICE_WIN32; m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; ... while(1) { //Sleep(3000); //Place Your Code for processing here.... //显示我们服务程序的对话框(当SCM启动服务程序的时候(系统重启时或手动在SCM中启动时),也让它显示主对话框界面) CTestDlg dlg; //m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } ... } } 具体的细节看下面的步骤,主要步骤如下: (1)首先生成一个基于对话框的应用程序框架,假设我的工程名称为test。 (2)在test.cpp中添加几个全局变量和几个全局函数。 //设置两个全局变量 SERVICE_STATUS m_ServiceStatus; SERVICE_STATUS_HANDLE m_ServiceStatusHandle; //添加几个全局函数 ////////////////////////////////////////////////////////////////////////// //函数声明 void WINAPI ServiceMain(DWORD argc, LPTSTR *argv); void WINAPI ServiceCtrlHandler(DWORD Opcode); BOOL InstallService(CString &strPath); BOOL DeleteService(); ////////////////////////////////////////////////////////////////////////// //函数定义 void WINAPI ServiceMain(DWORD argc, LPTSTR *argv) { // DWORD status; // DWORD specificError; AfxMessageBox("当用SCM启动程序的时候,程序执行下面的代码"); m_ServiceStatus.dwServiceType = SERVICE_WIN32; m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; m_ServiceStatus.dwWin32ExitCode = 0; m_ServiceStatus.dwServiceSpecificExitCode = 0; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; m_ServiceStatusHandle = RegisterServiceCtrlHandler("Service1",ServiceCtrlHandler); if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) { AfxMessageBox("Handler not installed"); return; } m_ServiceStatus.dwCurrentState = SERVICE_RUNNING; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; if (!SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus)) { } //bRunning=true; //while(bRunning) while(1) { //Sleep(3000); //Place Your Code for processing here.... CTestDlg dlg; //m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel //AfxMessageBox("cancel"); //break;//跳出while循环 m_ServiceStatus.dwCurrentState = SERVICE_STOPPED; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; if (!SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus)) { } exit(0);//后面退出不了,只能强行退出 } #ifdef _temp_delete//使用下面代码,只能关闭对话框不能关闭程序 //关闭对话框用,传递消息 MSG msg; while (GetMessage(&msg, 0, 0, 0)) { if (msg.message) { CString strMsg; strMsg.Format("%d",msg.message); AfxMessageBox(strMsg); } DispatchMessage(&msg); } #endif } return; } void WINAPI ServiceCtrlHandler(DWORD Opcode) { switch(Opcode) { case SERVICE_CONTROL_PAUSE: m_ServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: m_ServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: m_ServiceStatus.dwWin32ExitCode = 0; m_ServiceStatus.dwCurrentState = SERVICE_STOPPED; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; SetServiceStatus (m_ServiceStatusHandle,&m_ServiceStatus); //bRunning=false; break; case SERVICE_CONTROL_INTERROGATE: break; } return; } BOOL InstallService(CString &strPath)//无法创建其他应用程序为服务,因为它们不能响应启动请求 { //char strDir[1024]={0}; HANDLE schSCManager,schService; // GetCurrentDirectory(1024,strDir); // strcat(strDir,"\\test.exe"); schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) return false; //LPCTSTR lpszBinaryPathName=strDir; LPCTSTR lpszBinaryPathName; if (strPath=="") { AfxMessageBox("You must tell me Exepath!"); return FALSE; } else { lpszBinaryPathName=strPath; } schService = CreateService(schSCManager,"Service1","wcdj",// service name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS, // service type //SERVICE_DEMAND_START, // start type SERVICE_AUTO_START, //系统启动时自动启动 SERVICE_ERROR_NORMAL, // error control type lpszBinaryPathName, // service's binary NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies NULL, // LocalSystem account NULL); // no password if (schService == NULL) return false; CloseServiceHandle(schService); return true; } BOOL DeleteService() { HANDLE schSCManager; SC_HANDLE hService; schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) return false; hService=OpenService(schSCManager,"Service1",SERVICE_ALL_ACCESS); if (hService == NULL) return false; if(DeleteService(hService)==0) return false; if(CloseServiceHandle(hService)==0) return false; else return true; } (3)修改BOOL CTestApp::InitInstance()中代码,还是在test.cpp中。 //在别处显示对话框 // CTestDlg dlg; // m_pMainWnd = &dlg; // int nResponse = dlg.DoModal(); // if (nResponse == IDOK) // { // // TODO: Place code here to handle when the dialog is // // dismissed with OK // } // else if (nResponse == IDCANCEL) // { // // TODO: Place code here to handle when the dialog is // // dismissed with Cancel // } //启动服务(两种方式:双击运行和SCM启动,执行流程如刚开始提到的那样),对话框在下面显示 SERVICE_TABLE_ENTRY DispatchTable[]={{"Service1",ServiceMain},{NULL,NULL}}; //StartServiceCtrlDispatcher(DispatchTable); if (!StartServiceCtrlDispatcher(DispatchTable)) { AfxMessageBox("当不是用SCM启动程序的时候,程序执行下面的代码"); CTestDlg dlg; //m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } } 再在上面声明全局函数: extern void WINAPI ServiceMain(DWORD argc, LPTSTR *argv); (4)在主对话框上,添加4个新按钮和1个编辑框,功能分别是:安装服务、删除服务、打开服务管理器、显示启动项。代码如下: void CTestDlg::OnButton1() //安装服务 { UpdateData(TRUE);//读取编辑框变量m_strSvrPath的值 if(InstallService(m_strSvrPath)) { //printf("\n\nService Installed Sucessfully\n"); MessageBox("Service Installed Sucessfully","note",MB_OK|MB_ICONINFORMATION); } else { //printf("\n\nError Installing Service\n"); MessageBox("Error Installing Service","note",MB_OK|MB_ICONWARNING); } } void CTestDlg::OnButton2() //删除服务 { if(DeleteService()) { //printf("\n\nService UnInstalled Sucessfully\n"); MessageBox("Service UnInstalled Sucessfully","note",MB_OK|MB_ICONINFORMATION); } else { //printf("\n\nError UnInstalling Service\n"); MessageBox("Error UnInstalling Service","note",MB_OK|MB_ICONWARNING); } } void CTestDlg::OnButton3() //打开服务管理器 { //打开服务管理器 ::ShellExecute(NULL,"open","cmd.exe","/c services.msc",NULL,SW_HIDE); } void CTestDlg::OnButton4() //显示启动项 { //打开启动项 ::ShellExecute(NULL,"open","cmd.exe","/c msconfig",NULL,SW_HIDE); } 最后别忘了在开头声明全局函数: extern void WINAPI ServiceCtrlHandler(DWORD Opcode); extern BOOL InstallService(CString &strPath); extern BOOL DeleteService(); 这个服务程序还不是很完善,应该再添加一些判断和LogEvent记录信息,但是主要的服务程序框架应该都包含了。 最后,希望读到此篇文章的朋友提出自己的意见。 :)
相关文章推荐
- 将基于MFC的对话框应用程序修改为服务程序
- 将基于MFC的对话框应用程序修改为服务程序
- 将基于MFC的对话框应用程序修改为服务程序
- 将基于MFC的对话框应用程序修改为服务程序---------
- 将基于MFC的对话框应用程序修改为服务程序
- 基于MFC对话框的NT服务程序框架
- 基于MFC对话框的Windows服务程序
- 【转载、修改、增强】MFC基于对话框程序如何最小化到托盘?
- 【MFC-11】VS2010/MFC基于对话框程序之修改Enter/ESC按键默认响应
- 修改基于对话框的MFC程序的主窗口类名
- 如何让基于对话框的MFC程序启动后自动隐藏对话框
- 基于对话框MFC程序添加状态栏
- 基于MFC对话框程序中添加菜单栏 (CMenu)
- 如何初始化基于对话框的MFC程序中对话框的大小
- 基于MFC的对话框程序加启动进度条
- MFC学习笔记——状态栏(基于对话框的MFC程序)
- 在基于对话框的MFC程序中,使程序在任务栏中不显示图标
- MFC中基于对话框程序快捷键的实现
- MFC中关于基于对话框的应用程序的WM_COMMAND消息的流动路径
- 在基于对话框的MFC程序中,使程序在任务栏中不显示图标