Windows 服务(附服务开发辅助工具)

标签: windows 服务 服务 | 发表时间:2011-08-07 19:30 | 作者:Zachary.XiaoZhen Bloger
出处:http://www.cnblogs.com/

引子

             

近来在 Windows 下摆弄了一阵子的服务程序,有在 C++ 下弄服务的,也在 C# 下弄服务的,

感觉在 C# 下弄服务蛮简单的の,C/C++ 的麻烦蛮多の(当然我的服务所要求的功能也是很简单的,就启动个进程),

只不过服务在安装啊、调试啊、卸载啊上面麻烦的要死,弄得我烦躁起来了,

而且对于服务的安装和卸载中间还有一个小插曲的,

因为我很早就知道可以使用 SCM API 来完成服务的安装、启动、停止、卸载等功能,

(当然 SCM API 也可以完成 NT 式驱动程序的安装、启动、停止、卸载等功能,可以将 NT 式驱动程序理解为内核服务)

但是由于人贱手懒,一直也没有把它实现成一个工具,所以就到网上当了一个也是别人弄的工具,

而且他的压缩包下还有一个测试的 .sys (.sys 为内核中文件,可以理解为驱动程序),

于是我就拿他的 .sys 做了一下测试,好,把我蓝屏了,我立即起火了,

就个 TestSys 都蓝屏了,坑爹啊!于是就打算着有空自己写一个了啊 !

(其实后来想想,不应该怪他的 TestSys 的,

估计他的这个 .sys 是使用 XP 下的 WDK 编译的,在 Win7 下蓝屏也是有可能的)

                         

由于一直也都在摆弄一下底层程序,所以一直都有用 OsLoader 之类的 NT 式驱动程序安装工具,

不过没拿它来摆弄过服务,但是那东西并不受我喜欢,因为他奶奶的,

在 XP 上一个版本,在 Server 上又是一个版本,到了 Vista/Win7 还又一个版本了,

烦躁不咯,而刚好这次由于工作的原因,我顺便把服务的安装、启动、停止、卸载都放入了 DLL 中,

所以做一个自己的安装服务的程序应该是不难的。

               

本篇博文呢,并不只是来简单的介绍 C# 下 Windows Service 的开发的,而是来介绍一下 C# 服务的调试,

以及在 .Net Framework 4.0 下开发服务的注意事项以及如何利用 VS2010 自带的服务安装工具来进行服务的安装和卸载。

然后呢介绍一下我自己做的这个工具 InstallSvc 的实现以及在实现过程中(基于 VC/MFC)所作的一些细节修改问题。

下面的这篇博文呢,我会很简单很简单的介绍,我想是个人都是可以看的懂的,哈哈哈

注意:我乃 MFC 菜鸟,不怎么会用,所以有很多东西可能牛们看见了会觉得恶心,恶心者可以飘过 !

                   

                   

服务部分:

      

Visual Studio 中服务安装和卸载 :

首先是定位到路径(根据自己的 VS 版本来定位):C:\Windows\Microsoft.NET\Framework\v4.0.30319,

在该路径下可以发现如下截图所示的文件:

image_thumb9

使用 InstallUtil 来完成服务的安装和卸载必须在命令行下完成:

假设我们现在已经采用 C# 完成了一个服务,服务名称为 TestService.exe ,

该服务所在的路径为 D:\Service\TestService.exe,

那么使用 InstallUtil.exe 来完成该服务的安装和卸载过程如下:

在命令行下运行下面三条命令即可:

1. 定位到 InstallUtil 所在目录:C:\Windows\Microsoft.NET\Framework\v4.0.30319

2. 执行 TestService.exe 服务的安装:InstallUtil D:\Service\TestService.exe
3. 执行 TestService.exe 服务的卸载:InstallUtil /u D:\Service\TestService.exe

                  

服务启动和停止

服务的启动和停止则可以在服务控制台管理器中实现,

打开服务控制台管理器的简单方式:运行 services.msc 命令即可。

                         

服务中定时器的使用:

   1:          /// <summary>
   2:          /// 定义定时器
   3:          /// </summary>
   4:          private System.Timers.Timer myTimer;

                    

   1:          /// <summary>
   2:          /// 服务启动时触发的事件
   3:          /// </summary>
   4:          /// <param name="args"></param>
   5:          protected override void OnStart(string[] args)
   6:          {
   7:              Debug.WriteLine("MyService Is Started !");
   8:   
   9:              myTimer = new System.Timers.Timer(3000);
  10:   
  11:              myTimer.Elapsed += Timer_Tick;
  12:              myTimer.Interval = 3000;
  13:              myTimer.Enabled = true;
  14:          }
                         
   1:          /// <summary>
   2:          /// 定时器回调处理例程
   3:          /// </summary>
   4:          /// <param name="source"></param>
   5:          /// <param name="e"></param>
   6:          private void Timer_Tick(object source, System.Timers.ElapsedEventArgs e)
   7:          {
   8:              Debug.WriteLine("In Timer_Tick !");
   9:              //停掉定时器
  10:              myTimer.Enabled = false;
  11:              Debug.WriteLine("Out Timer_Tick !");
  12:          }
                  

服务调试:

服务的调试是比较变态的,方法貌似也还是有几种,

不过我呢,反正也就知道下面一种而已,个人觉得这种方式也还用得下去,即调试起来感觉还不错的 !

1. 首先在你的服务源代码中添加一个定时器,定时器的示例代码如上所示。

2. 在服务的 Start 事件中启动定时器,并且将定时器设置为可用状态。

3. 在服务中添加如下代码:(我的定时器为 3 秒钟,所以 15 秒后就会执行 Debug.WriteLine 了)

   1:          private Int32 nCount = 0;
   2:   
   3:          /// <summary>
   4:          /// 定时器回调处理例程
   5:          /// </summary>
   6:          /// <param name="source"></param>
   7:          /// <param name="e"></param>
   8:          private void Timer_Tick(object source, System.Timers.ElapsedEventArgs e)
   9:          {
  10:              nCount++;
  11:              if (nCount == 5)
  12:              {
  13:                  Debug.WriteLine("In Timer_Tick !");
  14:              }

3. 编译和安装好服务。

4. 下断点。

image_thumb26

5. 在服务控制台管理器中启动服务。

6. 以下操作必须在 15 秒内完成,否则无法进入调试状态(因为 Debug.WriteLine 已经执行完了)。

7. VS2010 中 “工具 –> 附加到进程”。

image_thumb31

8. 选择好服务所在的进程(我这里的服务进程为 WorkTracker.Service.exe),然后单击附加后就慢慢等待 15 秒钟的过去吧。

9. 15 秒到达时,我们的服务就会进入到调试状态了,然后再 VS 中就可以来调试服务了。

image_thumb37

                   

VC++/MFC 部分:

               

设置窗口透明度:

在对话框的 OnInitDialog 处理例程中添加以下代码即可:

  1: //设置窗体透明度,120 是透明度,范围是 0~255
  2: ::SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);  
  3: ::SetLayeredWindowAttributes(m_hWnd, 0, 215, LWA_ALPHA);

                  

设置窗口背景颜色:

1. 首先给对话框类(我这里是 CAboutDialog 类)中添加以下私有成员变量:

  1: private:
  2: 	CBrush m_brush;

2. 然后在 CAboutDialog 类的构造函数中初始化 m_brush 成员变量:

  1: CAboutDialog::CAboutDialog(CWnd* pParent /*=NULL*/)
  2: 	: CDialogEx(CAboutDialog::IDD, pParent)
  3: {
  4: 	this->m_brush.CreateSolidBrush(RGB(200, 245, 142)); 
  5: }

3. 再在 CAboutDialog 的 OnCtlColor 处理例程中修改为:

  1: HBRUSH CAboutDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  2: {
  3: 	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
  5: 	//只有当是对话框窗体时,才将画刷设置为 m_brush
  6: 	//对于一些其他的控件之类的则不操作,即使用预定义背景色
  7: 	if(nCtlColor == CTLCOLOR_DLG)
  8: 	{  
  9: 		return this->m_brush;
 10: 	} 
 12: 	// TODO:  如果默认的不是所需画笔,则返回另一个画笔
 13: 	return hbr;
 14: }

         

MFC 中使用 PNG 图片:

  1: //从资源文件中读取出 PNG 格式的图片,并且将该图片转换为 Bitmap,然后显示在指定 ID 的控件上
  2: void CAboutDialog::SetResourceImageToCtrl(LPCTSTR lpszImgType, int nCtrlCode, int nImgResourceID)
  3: {
  4: 	CImage cImg;
  5: 	HRSRC hRsrc = FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(nImgResourceID), lpszImgType);
  6: 	if(NULL != hRsrc)
  7: 	{
  8: 		HGLOBAL hImgData = LoadResource(AfxGetResourceHandle(), hRsrc);
  9: 		if(NULL != hImgData)
 10: 		{
 11: 			LPSTREAM lpStream = NULL;
 12: 			LPVOID lpVoid = LockResource(hImgData);
 13: 			DWORD dwSize = SizeofResource(AfxGetResourceHandle(), hRsrc);
 14: 
 15: 			HGLOBAL hAllocate = GlobalAlloc(GHND, dwSize);
 16: 			LPBYTE lpByte = (LPBYTE)GlobalLock(hAllocate);
 17: 			memcpy(lpByte, lpVoid, dwSize);
 18: 			GlobalUnlock(hAllocate);
 19: 
 20: 			HRESULT hResult = CreateStreamOnHGlobal(hAllocate, TRUE, &lpStream);
 21: 			if(S_OK == hResult)
 22: 			{
 23: 				cImg.Load(lpStream);
 25: 				HBITMAP hBitmap = cImg.Detach();
 27: 				((CButton *)GetDlgItem(nCtrlCode))->SetBitmap(hBitmap);				
 28: 			}
 30: 			GlobalFree(hAllocate);
 31: 			FreeResource(hImgData);
 32: 		}
 33: 	}
 34: }

该函数的调用代码为:

  1: SetResourceImageToCtrl(TEXT("PNG"), IDC_LOG_BTN, IDB_PNG1);

             

设置窗口图标:

  1: BOOL CInstallSvcDlg::OnInitDialog()
  2: {
  3: 	CDialogEx::OnInitDialog();
  5: 	//设置窗体上的窗口图标为 IDI_ICON1
  6: 	HICON hIcon=AfxGetApp()->LoadIcon(IDI_ICON1);
  7: 	SetIcon(hIcon, FALSE);	// 设置小图标
  8: 	SetIcon(hIcon, TRUE);	// 设置大图标		
 10: 	//设置窗体透明度,120 是透明度,范围是 0~255
 11: 	::SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);  
 12: 	::SetLayeredWindowAttributes(m_hWnd, 0, 215, LWA_ALPHA);
 14: 	InitControl();
 16: 	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
 17: }

设置 EXE 图标:

这个可以很轻松的实现,就需要进入 Resource.h 中修改就可以了,

比如在我的项目中,有一个资源 IDI_ICON1 ,我需要将该资源设置为我的 EXE 的图标,

image_thumb67

方法是打开 Resource.h ,并且对其中的 IDI_ICON1 的值进行修改,使得该值小于 IDR_MAINFRAME 的值,

image_thumb74
然后编译好程序后就可以看到图标已经改变了(这里有一个 Bug,

有时候你重新生成后,你在 Release 下会看到你的 EXE 的图标还是默认的 MFC 图标,

你可以尝试着将这个 EXE 拷贝到桌面上,你会发现拷贝过去以后 EXE 图标就变成你自己所定义的图标了)。

而 Debug 下看到的是你所设置的图标是正确的。

                    

设置 EXE 文件属性:

所谓的文件属性就是如下面得东西:

image_thumb88

上面的信息的修改可以直接在资源文件中修改,

image_thumb94

在打开的文件中直接修改代码即可,示例如下:

image_thumb100

           

             

附加我的 InstallSvc:

         

该工具可以用来实现普通服务的安装,也可以实现 NT 式驱动程序的安装,

有了这个工具的话,在开发服务程序的时候就不需要再使用前面的那些招数了,太麻烦了,

而且也方便了以后内核代码的安装,运行之类的,也算是有点小作用吧。

关于这个工具的实现呢,其实我以前就发过一篇博文的,那篇博文是将 SCM 封装进了 C# 类,

所以完全可以使用哪个类来开发一个 C# 版本的 InstallSvc,

这篇博文的链接为:http://www.cnblogs.com/BoyXiao/archive/2011/03/31/2001535.html

有兴趣的可以去看看,哪个类自己觉得写得还不错の,

我的工具的截图为:

image_thumb108

image_thumb116

该工具在 XP 以及低版本操作系统下,显示得不怎么滴,

在关于对话框中的图片显示很有问题的,估计是 Bitmap 不支持透明或者在 PNG 转换为 Bitmap 时出问题了吧 !

image_thumb124

                 

下载 InstallSvc.zip

                  

版权所有,迎转载,但转载请注明: 转载自 Zachary.XiaoZhen - 梦想的天空

                

                

                 

 

作者: Zachary.XiaoZhen 发表于 2011-08-07 19:30 原文链接

评论: 4 查看评论 发表评论


最新新闻:
· 诺基亚成中国消费者最爱品牌(2011-08-08 10:25)
· 作家维权联盟向百度苹果发律师函获回应(2011-08-08 10:24)
· 语音技术公司iSpeech免费对外开放(2011-08-08 10:20)
· 真正的“人工”智能?——让人意外却有惊喜的“土而奇机器人”(2011-08-08 10:15)
· 创新工场:成长的“烦恼”(2011-08-08 10:13)

编辑推荐:C#与闭包

网站导航:博客园首页  我的园子  新闻  闪存  小组  博问  知识库

相关 [windows 服务 服务] 推荐:

Windows 搭建VPN服务器

- 洋白菜 - iGFW
Windows XP搭建PPTP VPN. 普通用户,在家里也可以搭建自己的VPN. 需要将服务器端的电脑直接放置于外网访问下,若是ADSL拨号的话,可以用此电脑直接拨号,中间不接路由器. 若是接路由器的话,可以启用NAT(网络地址转换)中的DMZ,将该服务器IP地址填入此处,那么外网访问到本路由Wan口时,就会直接转到该服务器上.

Windows Server 迎来新的 Azure 云服务

- - ITeye资讯频道
WPC 2012大会上,微软宣布将推出最新的Windows Azure服务,主要面向Windows平台的虚拟主机和网站托管服务. 新版Windows Azure服务,提供以Windows Server管理门户网站、API建设、虚拟机等服务,使托管服务供应商可以轻松地在基于Windows Server的环境服务方案中提供高密度的网站建设和基础设施.

Windows 服务(附服务开发辅助工具)

- Bloger - 博客园-首页原创精华区
近来在 Windows 下摆弄了一阵子的服务程序,有在 C++ 下弄服务的,也在 C# 下弄服务的,. 感觉在 C# 下弄服务蛮简单的の,C/C++ 的麻烦蛮多の(当然我的服务所要求的功能也是很简单的,就启动个进程),. 只不过服务在安装啊、调试啊、卸载啊上面麻烦的要死,弄得我烦躁起来了,. 而且对于服务的安装和卸载中间还有一个小插曲的,.

官方认证 Windows Phone 解锁服务 ChevronWP7 Labs 定价:$9

- ccyuling - LiveSino - LiveSide 中文版
WMPoweruser 注意到 ChevronWP7 团队成员 Chris Walsh 在 Twitter 上透露“ChevronWP7 Labs 解锁费用只需 $9”. ChevronWP7 Labs 解锁服务正是为希望在真机上测试应用而又暂时不想向微软 App Hub 支付 $99 费用的开发者,或者是所在市场仍未被支持的开发者提供的.

使用C#创建一个进程杀手Windows服务

- Bloger - 博客园-首页原创精华区
自定义事件目录并使用EventLogInstaller. 使用ServiceProcessInstaller和ServiceInstaller. 使用installutil.exe部署程序. 使用AssemblyInstaller部署程序. 使用批处理文件快速安装应用程序集. 此程序可以注册一个Windows服务(Windows Service),并通过启动参数可以制定需要杀掉的进程名称和执行间隔.

Windows平台网站图片服务器架构的演进

- - 博客园_知识库
  构建在Windows平台之上的网站,往往会被业内众多架构师认为很“保守”. 很大部分原因,是由于微软技术体系的封闭和部分技术人员的短视造成的. 由于长期缺乏开源支持,所以只能“闭门造车”,这样很容易形成思维局限性和短板. 就拿图片服务器为例子,如果前期没有容量规划和可扩展的设计,那么随着图片文件的不断增多和访问量的上升,由于在性能、容错/容灾、扩展性等方面的设计不足,后续将会给开发、运维工作带来很多问题,严重时甚至会影响到网站业务正常运作和互联网公司的发展(这绝不是在危言耸听).

使用ntbind架设Windows下的DNS服务器

- - 启光博客
  提到DNS服务器估计多数技术人员首先想到的是Bind,这也没错,Bind的强大自不用细说. Bind入门不难,但要想架设一个实用环境的DNS服务器即使对于专业的运维人员也比较繁琐. 对一般企业的网管来说使用Linux架设一台DNS服务器不是那么容易的一件事,也许在windows下他们更能顺手一些.

服务企业级用户新平台Windows Phone for business上线

- - WPDang
Windows Phone平台最新的服务Windows Phone for business已经正式上线,该服务直接面向企业级用户提供各类Windows Phone领域的技术支持,目前该服务 中国本地化网站也已经上线运营. 微软对Windows Phone for business的解释是,可在Windows 基础结构中轻松部署和管理Windows Phone的服务,具体的功能和服务内容包括:.

在Windows上以服务方式运行 Redis

- - 博客园_首页
ServiceStack.Redis 使用教程里提到Redis最好还是部署到Linux下去,Windows只是用来做开发环境,现在这个命题发生改变了,在Windows上也可以部署生产环境的Redis,这都要感谢微软的开放,把Redis在Windows上的环境给我们搞定了,最新的版本已经支持64位了.

使用VisualVM来监控包装为windows服务的java程序

- - BlogJava-首页技术区
java wrapper是一个可以用于将java应用程序包装成windows服务的工具. 并且可以通过简单的配置来允许使用visualVM进行监控. 在wrapper.conf中添加如下3行. wrapper.java.additional.1=-Dcom.sun.management.jmxremote.port=9898 #这里的端口号可以自行选择.