Windows服務調試

Windows 服務(附服務開發輔助工具)html

轉: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,

在該路徑下能夠發現以下截圖所示的文件:

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 - 夢想的天空

相關文章
相關標籤/搜索