最近写的WINDOWS 服务,以前用VC6写过简单的服务。VC6 带的ATL 创建服务后,会生成一个继承于CcomModule 的类,并覆盖了START、STOP等(不记得了),只需在START、STOP里写相应的代码就行了。

现在已用VS2005,当然不用VC6了,VC8中的服务项目是基于.NET的,考虑.NET的性能对服务不合适,还是选择ATL8。但创建完项目就发现生成的类除了安全检测外什么也没有。

生成的类继承于CatlServiceModuleT的,在网上搜了一下CatlServiceModuleT,资料很少,例子较全的是一个英文网站上的,拿来一用出现一些问题,经过几天的摸索(先把作业叫了,再摸索的),大体弄清CatlServiceModuleT。

CatlServiceModuleT 用T* pT = static_cast<T*>(this) 来实现对子类函数的调用(如果子类重写了该函数)。我们可重写的函数有ParseCommandLine、Start、Run、PreMessageLoop、RunMessageLoop、PostMessageLoop、InitializeSecurity、OnStop、OnPause、OnContinue、OnShutdown、ServiceMain、Handler、RegisterAppId等。

网上一般是重写PreMessageLoop来做服务的开始工作,PostMessageLoop做结束工作。RegisterAppId 用来更改服务注册信息。

主线程有一个消息循环,它不做什么,只等收到消息推出程序。PreMessageLoop里面可以启动自己的线程,并进入服务处理循环。主线程和工作线程可用事件来交互,(如果多线程可能要用到互斥量、信号量),比如主线程OnStop的时候结束工作线程。

RegisterAppId 里面可以更改服务注册信息,主要用函数ChangeServiceConfig2来更改服务的描述,也就是在服务管理里面每个服务的描述,不改就为空。

结束工作可用PostMessageLoop,但我是直接在OnStop里面写的,也许主类中有要释放的资源才用PostMessageLoop。我的资源全在工作类中。

现在是一些问题:

1,调试:怎样才能在VS2005中调试。
看CatlServiceModuleT中的WinMain,检查输入参数有效就调用START。START先检测服务有没有注册过,没有注册的就直接返回退出。所以一定要先注册。检测到有注册就查看是否注册为LocalService(也就是 -Service),如果为LocalService就把_ServiceMain连接到SCM(服务管理器),但在调试模式下不能连接成功,或者必须由SCM来启动,要不它认为已启动。所以不能注册为服务,只能注册为RegSever(-RegSever)。调试完后,再注册为服务。如果只有在服务里面才出错,可用CatlServiceModuleT带的LogEvent 把调试信息写到windows事件里面。MSDN中讲可以服务进程连到VS2005我没试过,因为全在RegSever模式下解决了。

2,更改服务的启动模式。
没找到更改服务启动模式的方法。查看代码发现在CatlServiceModuleT的Install中写死的。
SC_HANDLE hService = ::CreateService(
hSCM, m_szServiceName, m_szServiceName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
szFilePath, NULL, NULL, _T("RPCSS/0"), NULL, NULL);

SERVICE_DEMAND_START表示手动在SCM启动。有个方法,在重写的RegisterAppId用ChangeServiceConfig修改,但看一下ChangeServiceConfig的参数,好多呀,太麻烦。加上我觉得写一个服务就应该自动启动,什么时候处理任务是服务的事,而且不想用了可以在SCM里禁用。所以我做了一个不道德的地方――把CatlServiceModuleT源程序改了。把SERVICE_DEMAND_START改为SERVICE_AUTO_START。
SC_HANDLE hService = ::CreateService(
hSCM, m_szServiceName, m_szServiceName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
szFilePath, NULL, NULL, _T("RPCSS/0"), NULL, NULL);
谁叫他不道德没流一个好的方法。当然你可以用ChangeServiceConfig,自己查一下。

3,暂停和继续,
我想用暂停和继续来实现配置的更新,因为不想改配置的时候,要停止服务,再启动,那样服务会断。还有就是用命名管道或全局消息让配置工具和服务通讯,但太麻烦,我只是想重新应有配置。
第一个问题,在SMC中暂停和继续的菜单是灰的。找了很久,找到::SetServiceStatus(m_hServiceStatus, &m_status) ,还好m_status是Public ,用m_status. dwControlsAccepted=m_status.dwControlsAccepted| SERVICE_ACCEPT_PAUSE_CONTINUE;搞定。
另一个问题,重写了OnPause但更本没进去。用LogEvent调试,发现CatlServiceModuleT的_Handler都没进去(LocalService就把_ServiceMain连接到SCM,_ServiceMain调用ServiceMain,ServiceMain中注册Handler为SCM处理函数,处理STOP、PAUSE等),_Handler 中是这样调用的((T*)_pAtlModule)->Handler(dwOpcode); 不知到_pAtlModule是指向谁的实例。我重写了Handler,就可以进来了。在自己的Handler中调用PAUSE,OnContinue后,就调用父类的Handler。

终于完成了,代码如下,工作线程没写出来。

class CNVSStoreServerModule : public CAtlServiceModuleT< CNVSStoreServerModule, IDS_SERVICENAME >
{
private:
CWorkThread * pWork; //工作类,没写出来。
public :
DECLARE_LIBID(LIBID_NVSStoreServerLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_NVSSTORESERVER, "{CF40AF29-C742-4D52-906C-5915A611F2D6}")
HRESULT InitializeSecurity() throw()
{
return S_OK;
}
void OnPauze() throw()
{
SetEvent(pWork->mServerStopEvent);
SetServiceStatus(SERVICE_PAUSED);
__super::OnPause();
}
void OnStop() throw()
{
SetEvent(pWork->mServerStopEvent);
WaitForSingleObject(pWork->mCanStopEvent,INFINITE);
__super::OnStop();
}
void Handler(DWORD dwOpcode) throw()
{
switch (dwOpcode)
{
case SERVICE_CONTROL_PAUSE:
OnPauze();
break;
case SERVICE_CONTROL_CONTINUE:
OnContinue();
break;
}
__super::Handler(dwOpcode);
}
CServiceStatus GetServiceStatus() throw()
{
return this->m_ServiceStatus;
}
void OnContinue( ) throw( )
{
SetServiceStatus(SERVICE_RUNNING);
__super::OnContinue();
}
HRESULT PreMessageLoop(int nShowCmd) throw()
{
m_status.dwControlsAccepted =m_status.dwControlsAccepted | SERVICE_ACCEPT_PAUSE_CONTINUE;
HRESULT hr = __super::PreMessageLoop(nShowCmd);
if (hr == S_FALSE) hr = S_OK; //要这句才能走下去
pWork=new CWorkThread();
return hr;
}
HRESULT RegisterAppId(bool bService = false) 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 = ::OpenServiceW(hSCM, m_szServiceName, SERVICE_CHANGE_CONFIG);
if (hService != NULL)
{
const int m_szServiceNameLen = 4096;
const int m_szServiceDescriptionLen = 2000;
WCHAR m_szServiceDescription[m_szServiceDescriptionLen]=L"你的服务描述";
SERVICE_DESCRIPTION sdBuf = {m_szServiceDescription};
res = ChangeServiceConfig2W(hService, SERVICE_CONFIG_DESCRIPTION, &sdBuf);
::CloseServiceHandle(hService);
}
else
hr = AtlHresultFromLastError();
::CloseServiceHandle(hSCM);
}

}
}
return hr;
}
};

CNVSStoreServerModule _AtlModule;

extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/, int nShowCmd)
{
return _AtlModule.WinMain(nShowCmd);
}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/udpcn/archive/2007/01/23/1491466.aspx

VS2005 ATL WINDOWS服务感想相关推荐

  1. InstallShield Limited Edition Project 打包windows服务解析

    最近项目从vs2005 升级到vs2010后,发现新的vs2010 不再带有原来的安装工程项目,导致以前的安装包不可以使用,查找资料后发现微软从vs2010 版本后不再提供自带的安装工程,尝试着利用  ...

  2. 将Java程序转换为Windows服务 作者:IT168 seasky 2007-09-19

    [IT168 专稿] 一.概述 现在Java语言越来越受到程序员的关注.和Java相关的应用也越来越多.虽然Java是跨平台语言,但在国内有很多的应用都是运行在Windows下的.尤其是一些服务类程序 ...

  3. 玩转Windows服务系列——Windows服务小技巧

    伴随着研究Windows服务,逐渐掌握了一些小技巧,现在与大家分享一下. 将Windows服务转变为控制台程序 由于默认的Windows服务程序,编译后为Win32的窗口程序.我们在程序启动或运行过程 ...

  4. [置顶] Windows服务(Windows Service,system权限)程序显示界面与用户交互(xp,win7通用)

    [置顶] [置顶] Windows服务(Windows Service,system权限)程序显示界面与用户交互(xp,win7通用) 2012-08-20 15:04 673人阅读 评论(1) 收藏 ...

  5. Windows服务(Windows Service,system权限)程序显示界面与用户交互(xp,win7通用)

    1.VC2008中编写"Windows服务"(Windows Service)程序 源码资源下载: http://download.csdn.net/detail/stony198 ...

  6. .Net Core快速创建Windows服务

    1.新建.Net Core控制台程序,添加新建项Windows服务: 修改Progran.cs: class Program{static void Main(string[] args){Servi ...

  7. C#创建Windows服务

    利用VS.NET创建C# Windows服务 在很多应用中需要做windows服务来操作数据库等操作,比如 (1)一些非常慢的数据库操作,不想一次性去做,想慢慢的通过服务定时去做,比如定时为数据库备份 ...

  8. C#实现一个用于开机启动其他程序的Windows服务

    今天决定写写博客,不为别的,只当自己的积累,如果与此同时能不误导他人甚至给了朋友们一些启发,那真是更好了! 程序的目的和用途: 很多开机启动程序仅仅加在启动项里面,只有登陆后才真正启动.windows ...

  9. 用.NET创建Windows服务

    用.NET创建Windows服务 译者说明:我是通过翻译来学习C#的,文中涉及到的有Visual Studio.NET有关操作,我都根据中文版的VS.NET显示信息来处理的,可以让大家不致有误解. 作 ...

最新文章

  1. awk 控制语句(if for do while)
  2. ETSI MEC — 网业协同架构
  3. python循环五角星做法_python实现while循环打印星星的四种形状
  4. java mcv_Spring和SpringMCV配置
  5. beta冲刺7-咸鱼
  6. python循环括号_Python for循环内括号语法
  7. 百度地图订单分布php,php与百度地图API实现注册用户分布图
  8. IIS安装程序无法复制文件的问题 安装IIS提示安装程序无法复制文件staxmem.d...
  9. 软件系统分析与设计考试重点、复习指导及复习笔记汇总
  10. 3D模型在线转换,CAD格式转换,Solidworks版本转换
  11. Git学习笔记(基础操作+分支操作+PR)
  12. luogu P1724 东风谷早苗
  13. CTO(技术总监)平时都在做些什么?
  14. QtCreator总是崩溃卡死的问题
  15. 用sqlyog打开.sql文件
  16. 塔望食业洞察|人参饮料行业环境 市场现状及发展思考
  17. linux 系统qcow2镜像制作
  18. sqlserver数据库错误码
  19. 2022年6月大学英语六级翻译
  20. 足球大数据预测中欧亚大小球随时间变化的处理

热门文章

  1. Apache shutdown unexpectedly启动错误解决方法
  2. Mysql中怎样设置指定ip远程访问连接
  3. MongoDb在Windows上的下载安装以及可视化工具的下载与使用
  4. SourceTree中拉取GitLab代码时提示:Too many authentication failures“ fatal: Could not read from remote reposit
  5. 史上最全Winform中使用ZedGraph教程与资源汇总整理(附资源下载)
  6. C#中将字符串内容换行写入到txt文件中
  7. Flutter 制作一个具有酷炫液体滑动效果的酷炫入门页面
  8. 从方法到实践!深度解读:企业数据治理到底治什么?怎么治?
  9. 意向保护:你的 A/B 测试数据期骗你了吗?
  10. 点点客李新 | 移动社交电商行业案例干货分享