转:ide
http://www.cnblogs.com/BoyXiao/archive/2011/08/07/2130208.html函数
近来在 Windows 下摆弄了一阵子的服务程序,有在 C++ 下弄服务的,也在 C# 下弄服务的,工具
感受在 C# 下弄服务蛮简单的の,C/C++ 的麻烦蛮多の(固然个人服务所要求的功能也是很简单的,就启动个进程),post
只不过服务在安装啊、调试啊、卸载啊上面麻烦的要死,弄得我烦躁起来了,测试
并且对于服务的安装和卸载中间还有一个小插曲的,this
由于我很早就知道可使用 SCM API 来完成服务的安装、启动、中止、卸载等功能,spa
(固然 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,
在该路径下能够发现以下截图所示的文件:
使用 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. 下断点。
5. 在服务控制台管理器中启动服务。
6. 如下操做必须在 15 秒内完成,不然没法进入调试状态(由于 Debug.WriteLine 已经执行完了)。
7. VS2010 中 “工具 –> 附加到进程”。
8. 选择好服务所在的进程(我这里的服务进程为 WorkTracker.Service.exe),而后单击附加后就慢慢等待 15 秒钟的过去吧。
9. 15 秒到达时,咱们的服务就会进入到调试状态了,而后再 VS 中就能够来调试服务了。
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 的图标,
方法是打开 Resource.h ,而且对其中的 IDI_ICON1 的值进行修改,使得该值小于 IDR_MAINFRAME 的值,
而后编译好程序后就能够看到图标已经改变了(这里有一个 Bug,
有时候你从新生成后,你在 Release 下会看到你的 EXE 的图标仍是默认的 MFC 图标,
你能够尝试着将这个 EXE 拷贝到桌面上,你会发现拷贝过去之后 EXE 图标就变成你本身所定义的图标了)。
而 Debug 下看到的是你所设置的图标是正确的。
设置 EXE 文件属性:
所谓的文件属性就是以下面得东西:
上面的信息的修改能够直接在资源文件中修改,
在打开的文件中直接修改代码便可,示例以下:
附加个人 InstallSvc:
该工具能够用来实现普通服务的安装,也能够实现 NT 式驱动程序的安装,
有了这个工具的话,在开发服务程序的时候就不须要再使用前面的那些招数了,太麻烦了,
并且也方便了之后内核代码的安装,运行之类的,也算是有点小做用吧。
关于这个工具的实现呢,其实我之前就发过一篇博文的,那篇博文是将 SCM 封装进了 C# 类,
因此彻底可使用哪一个类来开发一个 C# 版本的 InstallSvc,
这篇博文的连接为:http://www.cnblogs.com/BoyXiao/archive/2011/03/31/2001535.html
有兴趣的能够去看看,哪一个类本身以为写得还不错の,
个人工具的截图为:
该工具在 XP 以及低版本操做系统下,显示得不怎么滴,
在关于对话框中的图片显示颇有问题的,估计是 Bitmap 不支持透明或者在 PNG 转换为 Bitmap 时出问题了吧 !