引子
近來在 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,
在該路徑下可以發現如下截圖所示的文件:
使用 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; // 除非將焦點設置到控件,否則返回 TRUE17: }
設置 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 時出問題了吧 !
版權所有,歡迎轉載,但轉載請註明: 轉載自 Zachary.XiaoZhen - 夢想的天空