国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院

首頁 > 編程 > C > 正文

深入詳解C編寫Windows服務(wù)程序的五個步驟

2020-01-26 16:17:08
字體:
供稿:網(wǎng)友

  Windows 服務(wù)被設(shè)計用于需要在后臺運行的應(yīng)用程序以及實現(xiàn)沒有用戶交互的任務(wù)。為了學(xué)習(xí)這種控制臺應(yīng)用程序的基礎(chǔ)知識,C(不是C++)是最佳選擇。本文將建立并實現(xiàn)一個簡單的服務(wù)程序,其功能是查詢系統(tǒng)中可用物理內(nèi)存數(shù)量,然后將結(jié)果寫入一個文本文件。最后,你可以用所學(xué)知識編寫自己的 Windows 服務(wù)。

  當(dāng)初我寫第一個NT 服務(wù)時,我到 MSDN 上找例子。在那里我找到了一篇 Nigel Thompson 寫的文章:“Creating a Simple Win32 Service in C++”,這篇文章附帶一個 C++ 例子。雖然這篇文章很好地解釋了服務(wù)的開發(fā)過程,但是,我仍然感覺缺少我需要的重要信息。我想理解通過什么框架,調(diào)用什么函數(shù),以及何時調(diào)用,但 C++ 在這方面沒有讓我輕松多少。面向?qū)ο蟮姆椒ü倘环奖悖捎谟妙悓Φ讓?Win32 函數(shù)調(diào)用進(jìn)行了封裝,它不利于學(xué)習(xí)服務(wù)程序的基本知識。這就是為什么我覺得 C 更加適合于編寫初級服務(wù)程序或者實現(xiàn)簡單后臺任務(wù)的服務(wù)。在你對服務(wù)程序有了充分透徹的理解之后,用 C++ 編寫才能游刃有余。當(dāng)我離開原來的工作崗位,不得不向另一個人轉(zhuǎn)移我的知識的時候,利用我用 C 所寫的例子就非常容易解釋 NT 服務(wù)之所以然。

  服務(wù)是一個運行在后臺并實現(xiàn)勿需用戶交互的任務(wù)的控制臺程序。Windows NT/2000/XP 操作系統(tǒng)提供為服務(wù)程序提供專門的支持。人們可以用服務(wù)控制面板來配置安裝好的服務(wù)程序,也就是 Windows 2000/XP 控制面板|管理工具中的“服務(wù)”(或在“開始”|“運行”對話框中輸入 services.msc /s――譯者注)。可以將服務(wù)配置成操作系統(tǒng)啟動時自動啟動,這樣你就不必每次再重啟系統(tǒng)后還要手動啟動服務(wù)。

  本文將首先解釋如何創(chuàng)建一個定期查詢可用物理內(nèi)存并將結(jié)果寫入某個文本文件的服務(wù)。然后指導(dǎo)你完成生成,安裝和實現(xiàn)服務(wù)的整個過程。

  第一步:主函數(shù)和全局定義

  首先,包含所需的頭文件。例子要調(diào)用 Win32 函數(shù)(windows.h)和磁盤文件寫入(stdio.h):

復(fù)制代碼 代碼如下:

#include <windows.h>
#include <stdio.h>

接著,定義兩個常量:
復(fù)制代碼 代碼如下:

#define SLEEP_TIME 5000
#define LOGFILE "C://MyServices//memstatus.txt"

SLEEP_TIME 指定兩次連續(xù)查詢可用內(nèi)存之間的毫秒間隔。在第二步中編寫服務(wù)工作循環(huán)的時候要使用該常量。

  LOGFILE 定義日志文件的路徑,你將會用 WriteToLog 函數(shù)將內(nèi)存查詢的結(jié)果輸出到該文件,WriteToLog 函數(shù)定義如下:

復(fù)制代碼 代碼如下:

int WriteToLog(char* str)
{
 FILE* log;
 log = fopen(LOGFILE, "a+");
 if (log == NULL)
  return -1;
 fprintf(log, "%s/n", str);
 fclose(log);
 return 0;
}

聲明幾個全局變量,以便在程序的多個函數(shù)之間共享它們值。此外,做一個函數(shù)的前向定義:
復(fù)制代碼 代碼如下:

SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;

void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();


  現(xiàn)在,準(zhǔn)備工作已經(jīng)就緒,你可以開始編碼了。服務(wù)程序控制臺程序的一個子集。因此,開始你可以定義一個 main 函數(shù),它是程序的入口點。對于服務(wù)程序來說,main 的代碼令人驚訝地簡短,因為它只創(chuàng)建分派表并啟動控制分派機(jī)。
復(fù)制代碼 代碼如下:

void main()
{
 SERVICE_TABLE_ENTRY ServiceTable[2];
 ServiceTable[0].lpServiceName = "MemoryStatus";
 ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;

 ServiceTable[1].lpServiceName = NULL;
 ServiceTable[1].lpServiceProc = NULL;

 // 啟動服務(wù)的控制分派機(jī)線程
 StartServiceCtrlDispatcher(ServiceTable);
}


  一個程序可能包含若干個服務(wù)。每一個服務(wù)都必須列于專門的分派表中(為此該程序定義了一個 ServiceTable 結(jié)構(gòu)數(shù)組)。這個表中的每一項都要在 SERVICE_TABLE_ENTRY 結(jié)構(gòu)之中。它有兩個域:

  lpServiceName: 指向表示服務(wù)名稱字符串的指針;當(dāng)定義了多個服務(wù)時,那么這個域必須指定;
  lpServiceProc: 指向服務(wù)主函數(shù)的指針(服務(wù)入口點);

  分派表的最后一項必須是服務(wù)名和服務(wù)主函數(shù)域的 NULL 指針,文本例子程序中只宿主一個服務(wù),所以服務(wù)名的定義是可選的。

  服務(wù)控制管理器(SCM:Services Control Manager)是一個管理系統(tǒng)所有服務(wù)的進(jìn)程。當(dāng) SCM 啟動某個服務(wù)時,它等待某個進(jìn)程的主線程來調(diào)用 StartServiceCtrlDispatcher 函數(shù)。將分派表傳遞給 StartServiceCtrlDispatcher。這將把調(diào)用進(jìn)程的主線程轉(zhuǎn)換為控制分派器。該分派器啟動一個新線程,該線程運行分派表中每個服務(wù)的 ServiceMain 函數(shù)(本文例子中只有一個服務(wù))分派器還監(jiān)視程序中所有服務(wù)的執(zhí)行情況。然后分派器將控制請求從 SCM 傳給服務(wù)。

  注意:如果 StartServiceCtrlDispatcher 函數(shù)30秒沒有被調(diào)用,便會報錯,為了避免這種情況,我們必須在 ServiceMain 函數(shù)中(參見本文例子)或在非主函數(shù)的單獨線程中初始化服務(wù)分派表。本文所描述的服務(wù)不需要防范這樣的情況。

  分派表中所有的服務(wù)執(zhí)行完之后(例如,用戶通過“服務(wù)”控制面板程序停止它們),或者發(fā)生錯誤時。StartServiceCtrlDispatcher 調(diào)用返回。然后主進(jìn)程終止。

  第二步:ServiceMain 函數(shù)

  Listing 1 展示了 ServiceMain 的代碼。該函數(shù)是服務(wù)的入口點。它運行在一個單獨的線程當(dāng)中,這個線程是由控制分派器創(chuàng)建的。ServiceMain 應(yīng)該盡可能早早為服務(wù)注冊控制處理器。這要通過調(diào)用 RegisterServiceCtrlHadler 函數(shù)來實現(xiàn)。你要將兩個參數(shù)傳遞給此函數(shù):服務(wù)名和指向 ControlHandlerfunction 的指針。

  它指示控制分派器調(diào)用 ControlHandler 函數(shù)處理 SCM 控制請求。注冊完控制處理器之后,獲得狀態(tài)句柄(hStatus)。通過調(diào)用 SetServiceStatus 函數(shù),用 hStatus 向 SCM 報告服務(wù)的狀態(tài)。

  Listing 1 展示了如何指定服務(wù)特征和其當(dāng)前狀態(tài)來初始化 ServiceStatus 結(jié)構(gòu),ServiceStatus 結(jié)構(gòu)的每個域都有其用途:

  dwServiceType:指示服務(wù)類型,創(chuàng)建 Win32 服務(wù)。賦值 SERVICE_WIN32;

  dwCurrentState:指定服務(wù)的當(dāng)前狀態(tài)。因為服務(wù)的初始化在這里沒有完成,所以這里的狀態(tài)為 SERVICE_START_PENDING;

  dwControlsAccepted:這個域通知 SCM 服務(wù)接受哪個域。本文例子是允許 STOP 和 SHUTDOWN 請求。處理控制請求將在第三步討論;

  dwWin32ExitCode 和 dwServiceSpecificExitCode:這兩個域在你終止服務(wù)并報告退出細(xì)節(jié)時很有用。初始化服務(wù)時并不退出,因此,它們的值為 0;

  dwCheckPoint 和 dwWaitHint:這兩個域表示初始化某個服務(wù)進(jìn)程時要30秒以上。本文例子服務(wù)的初始化過程很短,所以這兩個域的值都為 0。

  調(diào)用 SetServiceStatus 函數(shù)向 SCM 報告服務(wù)的狀態(tài)時。要提供 hStatus 句柄和 ServiceStatus 結(jié)構(gòu)。注意 ServiceStatus 一個全局變量,所以你可以跨多個函數(shù)使用它。ServiceMain 函數(shù)中,你給結(jié)構(gòu)的幾個域賦值,它們在服務(wù)運行的整個過程中都保持不變,比如:dwServiceType。

  在報告了服務(wù)狀態(tài)之后,你可以調(diào)用 InitService 函數(shù)來完成初始化。這個函數(shù)只是添加一個說明性字符串到日志文件。如下面代碼所示:

復(fù)制代碼 代碼如下:

// 服務(wù)初始化
int InitService()
{
 int result;
 result = WriteToLog("Monitoring started.");
 return(result);
}

在 ServiceMain 中,檢查 InitService 函數(shù)的返回值。如果初始化有錯(因為有可能寫日志文件失敗),則將服務(wù)狀態(tài)置為終止并退出 ServiceMain:
復(fù)制代碼 代碼如下:

error = InitService();
if (error)
{
 // 初始化失敗,終止服務(wù)
 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
 ServiceStatus.dwWin32ExitCode = -1;
 SetServiceStatus(hStatus, &ServiceStatus);
 // 退出 ServiceMain
 return;
}

如果初始化成功,則向 SCM 報告狀態(tài):
復(fù)制代碼 代碼如下:

// 向 SCM 報告運行狀態(tài)
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);

接著,啟動工作循環(huán)。每五秒鐘查詢一個可用物理內(nèi)存并將結(jié)果寫入日志文件。

  如 Listing 1 所示,循環(huán)一直到服務(wù)的狀態(tài)為 SERVICE_RUNNING 或日志文件寫入出錯為止。狀態(tài)可能在 ControlHandler 函數(shù)響應(yīng) SCM 控制請求時修改。

  第三步:處理控制請求

  在第二步中,你用 ServiceMain 函數(shù)注冊了控制處理器函數(shù)。控制處理器與處理各種 Windows 消息的窗口回調(diào)函數(shù)非常類似。它檢查 SCM 發(fā)送了什么請求并采取相應(yīng)行動。

  每次你調(diào)用 SetServiceStatus 函數(shù)的時候,必須指定服務(wù)接收 STOP 和 SHUTDOWN 請求。Listing 2 示范了如何在 ControlHandler 函數(shù)中處理它們。

  STOP 請求是 SCM 終止服務(wù)的時候發(fā)送的。例如,如果用戶在“服務(wù)”控制面板中手動終止服務(wù)。SHUTDOWN 請求是關(guān)閉機(jī)器時,由 SCM 發(fā)送給所有運行中服務(wù)的請求。兩種情況的處理方式相同:

  寫日志文件,監(jiān)視停止;

  向 SCM 報告 SERVICE_STOPPED 狀態(tài);

  由于 ServiceStatus 結(jié)構(gòu)對于整個程序而言為全局量,ServiceStatus 中的工作循環(huán)在當(dāng)前狀態(tài)改變或服務(wù)終止后停止。其它的控制請求如:PAUSE 和 CONTINUE 在本文的例子沒有處理。

  控制處理器函數(shù)必須報告服務(wù)狀態(tài),即便 SCM 每次發(fā)送控制請求的時候狀態(tài)保持相同。因此,不管響應(yīng)什么請求,都要調(diào)用 SetServiceStatus。

 
圖一 顯示 MemoryStatus 服務(wù)的服務(wù)控制面板

  第四步:安裝和配置服務(wù)

  程序編好了,將之編譯成 exe 文件。本文例子創(chuàng)建的文件叫 MemoryStatus.exe,將它拷貝到 C:/MyServices 文件夾。為了在機(jī)器上安裝這個服務(wù),需要用 SC.EXE 可執(zhí)行文件,它是 Win32 Platform SDK 中附帶的一個工具。(譯者注:Visaul Studio .NET 2003 IDE 環(huán)境中也有這個工具,具體存放位置在:C:/Program Files/Microsoft Visual Studio .NET 2003/Common7/Tools/Bin/winnt)。使用這個實用工具可以安裝和移除服務(wù)。其它控制操作將通過服務(wù)控制面板來完成。
以下是用命令行安裝 MemoryStatus 服務(wù)的方法:

復(fù)制代碼 代碼如下:

sc create MemoryStatus binpath= c:/MyServices/MemoryStatus.exe


  發(fā)出此創(chuàng)建命令。指定服務(wù)名和二進(jìn)制文件的路徑(注意 binpath= 和路徑之間的那個空格)。安裝成功后,便可以用服務(wù)控制面板來控制這個服務(wù)(參見圖一)。用控制面板的工具欄啟動和終止這個服務(wù)。


圖二 MemoryStatus 服務(wù)的屬性窗口


  MemoryStatus 的啟動類型是手動,也就是說根據(jù)需要來啟動這個服務(wù)。右鍵單擊該服務(wù),然后選擇上下文菜單中的“屬性”菜單項,此時顯示該服務(wù)的屬性窗口。在這里可以修改啟動類型以及其它設(shè)置。你還可以從“常規(guī)”標(biāo)簽中啟動/停止服務(wù)。

以下是從系統(tǒng)中移除服務(wù)的方法:

復(fù)制代碼 代碼如下:

sc delete MemoryStatus

 指定 “delete” 選項和服務(wù)名。此服務(wù)將被標(biāo)記為刪除,下次西通重啟后,該服務(wù)將被完全移除。

  第五步:測試服務(wù)

  從服務(wù)控制面板啟動 MemoryStatus 服務(wù)。如果初始化不出錯,表示啟動成功。過一會兒將服務(wù)停止。檢查一下 C:/MyServices 文件夾中 memstatus.txt 文件的服務(wù)輸出。在我的機(jī)器上輸出是這樣的:

復(fù)制代碼 代碼如下:

Monitoring started.
273469440
273379328
273133568
273084416
Monitoring stopped.

  為了測試 MemoryStatus 服務(wù)在出錯情況下的行為,可以將 memstatus.txt 文件設(shè)置成只讀。這樣一來,服務(wù)應(yīng)該無法啟動。

  去掉只讀屬性,啟動服務(wù),在將文件設(shè)成只讀。服務(wù)將停止執(zhí)行,因為此時日志文件寫入失敗。如果你更新服務(wù)控制面板的內(nèi)容,會發(fā)現(xiàn)服務(wù)狀態(tài)是已經(jīng)停止。

  開發(fā)更大更好的服務(wù)程序

  理解 Win32 服務(wù)的基本概念,使你能更好地用 C++ 來設(shè)計包裝類。包裝類隱藏了對底層 Win32 函數(shù)的調(diào)用并提供了一種舒適的通用接口。修改 MemoryStatus 程序代碼,創(chuàng)建滿足自己需要的服務(wù)!為了實現(xiàn)比本文例子所示范的更復(fù)雜的任務(wù),你可以創(chuàng)建多線程的服務(wù),將作業(yè)劃分成幾個工作者線程并從 ServiceMain 函數(shù)中監(jiān)視它們的執(zhí)行。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表

圖片精選

国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院
羞羞视频在线观看免费| eeuss影院在线播放| 国产主播福利在线| 国产不卡在线| 51成人精品网站| 香蕉视频在线看| 九九视频精品在线| 五月天亚洲激情| 91最新在线| av在线免费播放| 国内外激情在线| 国产精品视频一区麻豆| 在线免费观看黄色av| www亚洲天堂| 国产在线一二三区| 国产日韩欧美一区二区三区视频| 国产黄色在线免费观看| gogo高清在线播放免费| 狠狠操五月天| 亚洲午夜久久久久中文字幕| 国内精品一区视频| av在线第一页| 9999在线视频| 中文字幕人成高视频| 亚洲v片在线观看| 中文字幕视频在线| 欧美性猛交p30| 国产精品久久麻豆| 国产乱码在线| www.91在线播放| 在线观看国产视频| 国产成人精品实拍在线| 中文字幕视频在线免费| 在线天堂av| 国产精品伦一区二区三区级视频频 | 国产美女福利在线观看| 中文字幕2019第三页| 最新国产在线| 九九热免费在线视频| 亚洲精品视频区| 精品麻豆视频| 2021av天天| 69精品视频| 国产超碰在线| 99久热re在线精彩视频| 91啦中文在线| 亚洲综合在线免费| 樱花草在线观看www| 99爱在线观看| www狠狠操| 丁香花视频在线观看| 黄网站在线观看高清免费| 免费在线黄色av| 国产精品一区二区三区视频网站| 中文字幕麻豆| 在线视频婷婷| 天天插天天干| 国产美女在线播放| 国产精品9区| 亚洲综合在线不卡| 九九热在线视频免费观看| 88av在线| 99久久国产视频| 不卡av免费观看| 国产午夜三区视频在线| av大片在线播放| 狠狠插狠狠操| 中文一区在线观看| 国产在线观看a视频| 国产国语**毛片高清视频| 在线免费看黄| 国产女人在线视频| 在线视频三区| 中文字幕不卡免费视频| √天堂资源中文www| 激情六月婷婷| 在线观看的av| 国产网友自拍视频导航网站在线观看| 在线观看视频污| 国产精品区一区二| 交换国产精品视频一区| 99在线视频影院| 中文字幕免费中文| 黄色av网站在线| 牛牛热在线视频| 中文产幕区在线观看| 国产美女视频一区二区三区| 在线免费观看黄色片| 国产精品理人伦一区二区三区| 怡红院av在线| 国产黄色在线| 国产女主播在线| 最新黄网在线观看| 国产美女性感在线观看懂色av| wwww亚洲| 免费在线高清av| www黄在线观看| 在线看a视频| 2021av在线| 精品亚洲成a人片在线观看| 国产一区精品| 国产一级激情| 国产毛片毛片| 最新国产在线精品91尤物| 成人免费一区二区三区视频网站| 青青草视频在线免费观看| free性亚洲| 欧美黑人乱大交ⅹxxxxx| 欧美日韩性视频一区二区三区| 亚洲伊人网在线观看| 亚洲尤物在线视频| 欧美性猛交xxxx免费看蜜桃| 久久亚洲资源| 中文字幕一区免费| 国产福利免费观看| 在线免费国产视频| 蜜桃视频中文字幕| 免费网站看黄yyy222| 99视频在线观看地址| 国产私人影院| gogo在线高清视频| 尤物网址在线观看| 国产激情视频网址| 一级二级在线观看| 精品中文字幕不卡在线视频| 高清色视频在线观看| 2018狠狠干| 久久精品最新免费国产成人| 最新中文字幕av专区| 伊人222成人综合网| 国产中文字幕在线| 99热99re6国产在线播放| 日本在线观看| 国产精品四虎| 二人午夜免费观看在线视频| 在线国产一区二区三区| 五月综合激情在线| 白浆爆出在线观看| 精品卡一卡卡2卡3网站| 午夜av电影| 黄色电影网站在线观看| 亚洲视频日韩| 国产激情在线| 国产乱子伦三级在线播放| 亚洲最新永久观看在线| 国产青青草在线| 最近中文字幕mv2018在线高清| 999国产在线视频| 国产精品一二三区视频| www.超级碰| av男人的天堂网| 国产变态拳头交视频一区二区| 免费在线看v| 日本成人网址| av片在线观看| 中文字幕2019第三页| 国产天堂av| 中文字幕国产视频| 激情亚洲综合网| 九九热视频免费在线观看| wwww亚洲| 免费在线看v| 亚洲最新永久观看在线| 在线观看精品视频一区二区三区| 国产精品视频一区二区三区麻豆 | 国产原创精品视频| 麻豆福利在线观看| 久久er视频| 国产一级影片| 国产99re66在线视频| 国产黄色在线| av免费在线观看网站| 色吊丝av中文字幕| www.eeuss影院| 狠狠干天天爱| 国产福利免费在线观看| 国产成免费视频| av中文在线| 国产美女自拍视频| 国产成人精品实拍在线| 亚洲人成电影| 国产女呦网站| 在线欧美一级视频| 久久精品视频观看| 国产污污在线观看| 在线天堂视频| 丁香综合在线| 国产一级二级在线| 国产区视频在线| 青青草免费在线观看| jlzzjlzz欧美| 国产视频三区| www.狠狠艹| 国产国产国产国产国产国产| 69视频在线| 国产精品一区牛牛影视| av网站大全在线观看| 午夜在线小视频| 午夜在线不卡| 91精选福利|