作者:Joerg Koenig
翻譯:Yuan Wenmao
原文:A Class For Building An NT Service
曾經嘗試寫一個NT服務嗎?
我最近的一個項目需要開發一個CORBA服務,將其運行成NT服務,由於下一個項目也是需要NT服務,我就想花點時間把他做得通用一點給更多的項目使用。成果就是這個CNTService類,通過CodeGurus與大家分享。
通過這個類可以很容易的創建NT服務,所有的困難部分都被這個類完成了,你只需派生出你自己的類並重寫”Run()”和”Stop()”兩純虛函數就可以了。當然還有好幾個虛函數可以重寫。
這個類接受一組命令行參數。比如說你可以使用-d選項使其按控制檯程序運行,這樣調試起來就容易多了。
此外這個類還可以安裝卸載服務,也是通過命令行參數控制(當然你也可以重定義它)。
CNTService支持UNICODE和非UNICODE兩種編譯方式。
建立一個服務
現在讓我們親眼看看如何創建一個自己的服務。
步驟如下(假設你使用的是VC++5.0)
1. 創建一個新的控制檯應用程序工程文件。
2. 把NTService文件包放入新工程文件目錄中。
3. 將 "NTService.cpp" 和"NTServiceEventLogMsg.mc" 添加到工程中。
4. 打開 Project->Settings ... 對話框並且如下圖所示填寫。
5. 編譯"NTServiceEventLogMsg.mc"文件. 這樣會產生 "NTServiceEventLogMsg.h" 和"NTServiceEventLogMsg.rc"兩個文件。
6. 將產生的資源文件添加到工程中。
7. 從CNTService類派生出自己的服務類並且重寫至少兩個方法"Run()"和"Stop()"。
8. 寫一個簡單的"main()" 函數去啓動你程序的功能(你可以使用 sample 工程作爲一個好的起點)。
9. 一旦工程編譯沒有錯誤了,你就可以立即啓動它。這之前你應該打再次打開 Project->Settings ... 對話框,選擇 AllConfigurations ,選中工程名字那一行,激活 Debug 標籤並在Program arguments:域增加 -d 選項。
現在你可以將你的服務當控制檯程序運行並調試了,可以使用Ctrl-C或Ctrl-Break去停止服務(這會模擬一個對SCM(Service Control Manager)的停止請求)。
如何填寫文件NTServiceEventLogMsg.mc的配置
現在讓我們將服務開啓爲一個真正的NT服務(假定使用Sample工程)
1. 如果你的賬號不屬於管理員組,切換爲管理員賬戶登入(這會是有些事情容易點)。
2. 使用 –i選項開啓程序. 這樣就安裝了你的服務。
3. 如果最後一步順利完成, 你就可以打開控制面板啓動 Services程序。查找你的服務的顯示名字並選中它(如果你嘗試的是sample程序,則顯示名字叫Very Simple Service )。
4. 按下 Startup ... 按鈕,查看 LogOn As:項,現在可以勾選System Account。如果是sample程序,確保你勾選了 Interact With The Desktop項。這是必需的,因爲sample程序使用了MessageBox()函數(這與桌面有關)。如果不勾選此項,sample 不僅不能正確運行還會自動掛起;如此你將不能再次停止服務!只要稍有經驗便可增強sample程序,使它在安裝此服務的同時便選中此選項,但我想保證sample 程序儘可能的簡單,所以這個問題留給你實現。
Sample工程實現了一個非常簡單的服務。派生類(聲明和實現)和main()函數都包含在同一個文件當中(main.cpp)。這個文件少於100行(去除註釋可以確保一頁紙就能打印!)
服務只是每10秒彈出一個消息框。
更多信息,參看 CNTService.h- sample工程。我相信這是很好的註釋(如果有意見,告知我)。
改變的修訂版
· 命令行參數中增加兩個切換選項: -e 使運行中的服務停止(類中的相應方法爲:virtual BOOL EndService())和-s 如果服務未運行,使服務開啓(對應方法:virtual BOOL StartupService())。
· Todd C. Wilson 增加了對Win95的支持。這使得你可以創建一個像Windows 95程序的服務(所謂的"Faceless Application",無界面應用程序)。就想服務一樣, 這樣的應用程序會跟隨系統自動啓動且一個用戶註銷後仍然存在。 我的經歷對此類應用程序作用不大:我可以註銷, 在我再次登入前系統是掛起的。 而且 BoundsChecker 5 (是的,我經常使用這個強大的工具測試我的程序)說, 下列語句返回一個無效指針(準確的說應該是“返回的指針未指向一個函數”)
typedef DWORD (WINAPI *fp_RegServProc)(DWORDdwProcessId,DWORD dwType);
fp_RegServProc fncptr=NULL;
// ...
HMODULE hModule =::GetModuleHandle(TEXT("kernel32.dll"));
fncptr=(fp_RegServProc)::GetProcAddress(hModule,"RegisterServiceProcess");
if (fncptr!=NULL)
(*fncptr)(0, RSP_SIMPLE_SERVICE);
如果達到最後一句,BoundsChecker 警告說, 指針fncptr 未指向一個函數。然而,sample繼續執行未碰到嚴重的錯誤。
如果你打算開發一個windows95下的無界面應用程序,就需要注意這個問題。 Sample工程提供了配置項"Win32 Win95 Debug",你可以用來嘗試此新特性。
NTService 使用 MFC
微軟推薦將NT服務寫成控制檯應用程序。但是,也有可能將使用MFC寫NT服務。 如此,並不需要創建一個MFC嚮導程序(當然也可以這樣做,不過需要移除一些代碼,因爲通常你不需要文檔&視圖結構),一個簡單的Win32程序就夠了。確保你選擇了工程中Settings對話框General標籤中的Using MFC in a shared DLL項。此外,你還需選擇C/C++標籤中的Multithreaded
DLL / DebugMultithreaded DLL, Code Generation 域的 Use run-time Library.
如果你使用了預編譯頭文件,確保不要定義 #define VC_EXTRALEAN,因爲基於MFC的服務需要partsof the "rarely used stuff",這個宏會拒絕windows頭文件 。
我增加了一個MFC示例新工程MFCService 作爲sample服務工作區的一部分。嘗試將它作爲一個更復雜服務的起點。服務(安裝、刪除等)操作和上一章所講一樣。
CNTService包含三個文件:
NTService.h
NTService.cpp
NTServiceEventLogMsg.mc
Download Source 14KB
Download Sample Project 23KB
注意:NTServiceEventLogMsg.mc 文件爲Telic Software International B.V.版權所有。
感謝Telic提供
最後更新時間: February 5, 1999