国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

用托管C++編寫Windows服務

2019-11-17 05:27:54
字體:
來源:轉載
供稿:網友

  多年以來,只要提到編寫Windows服務,就會想到用Visual C++編寫,同時,這也是其中一件C++程序員可以做,而VB程序員不可以做的事情。以前,我們只稱其為"服務"或"NT服務",現在,它們被命名為"Windows服務",而且用VB.NET或C#也可以很輕易地編寫。

  但是,假如你想用托管C++來編寫呢?究竟,大多數有經驗的Visual C++程序員都會寫過一兩個服務,也會知道怎樣完成一個類似的工程。假設你有一個必須要一直運行以提供服務的程序,且連接著一些遠程電腦,假如不想編寫一本使用手冊,告訴客戶要記得在每次重啟電腦之后重新運行此程序,你就應該使它成為一個服務;又假設你有一個用于刪除過期數據庫記錄的便利維護工具,假如不想讓治理員每周都親手運行它一次,你就應該使它成為一個服務。看起來挺吸引人的,那就讓我們開始吧。

  創建服務工程

  以下要做的事情非常簡單:打開Visual Studio.NET,創建一個新的工程,在Visual C++工程下,選擇Windows服務(.NET)。接下來,為這個服務取一個方便在電腦的服務列表中查找到的名字,在此為CGNotifier。向導會創建一個繼續自System::ServicePRocess::ServiceBase的類并打開設計視圖,在此,你可放入一個計時器、一個數據庫連接,或其他不可見的組件
讓我們轉到代碼視圖中看一下生成的代碼,在此有一個構造函數與一個Dispose方法,這兩個你都可以忽略,還有一對重載的方法:OnStart()和OnStop)。在OnStart()中,可編寫服務所需的代碼。服務中一個重要的范疇是使用"事件引發對象",例如System::IO::FileSystemWatcher的一個實例,一般可在OnStart()中創建這些對象,在本例中,你可為類加入事件方法,并處理在服務運行期間,由這些對象引發的事件。另有一種服務,它們對發生的事情不作反應,只在天天或每周的特定時間,執行一些特定的任務,這些服務平時通常處于休眠狀態,但因為它們的工作狀態是持續的,所以不應該停止它們,或者可以把它們放入一個循環中,在特定的時間檢查它們是否已被停止。

  OnStart()方法是服務的開始之處,并且會在執行完后返回,在此方法完成之前,服務一般不會顯示為"已啟動"。這就意味著,不能在OnStart()中放入一個經常使用的循環,或從別處直接調用的任何方法。最直接的方法是設置好一個單獨的方法,并在一個新線程中調用它,如下所示:

private:
bool stopping;
int loopsleep; //毫秒
Threading::Thread* servicethread;

protected:
//設置好服務應做的工作
void OnStart(String* args[])
{
 Threading::ThreadStart* threadStart =new Threading::ThreadStart(this,mainLoop);
 servicethread = new Threading::Thread(threadStart);
 servicethread->Start();
}
void mainLoop()
{
 loopsleep = 1000; //毫秒
 stopping = false;
 while (!stopping)
 {
  Threading::Thread::Sleep(loopsleep);
 }
}
  這個循環將會一直運行,直到服務停止,因為OnStop()設置了停止標志:

void OnStop()
{
 stopping = true;
}
  假如你增加loopsleep值,則會在停止時,增加服務的響應時間。 安裝服務

  盡管這個服務什么也不做,但你仍可對它進行安裝、啟動和停止。為簡化安裝過程,可在工程中加入一個安裝程序,這可在設計視圖中完成(假如你喜歡,可在設計視圖中打開屬性窗口,并修改ServiceName屬性;而向導會在工程名后加上WinService,這最好在添加安裝程序之前完成,否則,就需要在多處修改服務名。),鼠標右鍵單擊設計視圖,選擇添加安裝程序。這將創建一個服務安裝程序和一個服務過程安裝程序,并顯示在設計視圖中,以供你設置它們的屬性。

  假如已經閱讀了有關Windows服務的 .NET文檔,你可能會想為什么要添加一個安裝程序呢?難道不可以自動添加嗎?實際上,假如是使用VB或C#,是可以自動添加的,而C++卻不行。

  服務過程安裝程序只有一個比較讓人感愛好的屬性:服務所運行的賬戶。單擊serviceProcessInstaller1選擇它,打開其屬性窗口。默認情況下,賬戶屬性為User,這意味著在安裝服務時,將會提示輸入一個ID和密碼,而且服務將會運行于user權限下--這在服務運行于system賬戶時非常有用。通常有三個選項:LocalSystem是服務被安裝于未運行Windows 2003的電腦上時的唯一選擇;假如服務是面向Windows 2003的,那么LocalService的權限更少,因為是更好的選擇;而NetworkService答應服務驗證另一臺電腦,所以只在需要使用它(例如,一個服務加載了一個web頁),相反,在使用公共web服務時,就不需要作為NetworkService運行,因為它不需驗證遠程電腦。
而服務安裝程序中需要注重的屬性是StartType:手動、自動、禁用。在此例中為手動。

  現在,可以生成服務,并預備安裝了。打開Visual Studio命令提示符,定位到工程的Debug文件夾,輸入以下命令:

InstallUtil CGNotifier.exe
  以下是屏幕的輸出:

Microsoft (R) .NET Framework Installation utility
Version 1.1.4322.573
Copyright (C) Microsoft Corporation 1998-2002.
All rights reserved.

Exception occurred while initializing the installation:
System.IO.FileLoadException: Unverifiable image 'CGNotifier.exe'
cannot be run.
  這真是難以理解,不是嗎?在C++中編寫可驗證代碼向來都是不可能的,且非常難以實現。為什么工程向導創建了一個服務,但卻沒有提示你代碼必須為可驗證的呢?其實不必使你的服務程序產生可驗證代碼。

  打開解決方案資源治理器,找到并打開相應的 .cpp文件,你將會發現隱藏在此的一個main()函數--正是這個main()函數以一種"聰明"的方式為你調用了InstallUtil,并產生了整個的"可驗證代碼"問題。現在回到命令提示符窗口,像以下這樣安裝服務:

CGNotifier.exe -Install

  你可看到服務輕松、流暢地安裝上去了。

  為進行測試,現在打開"計算機治理",并展開"服務和應用程序"項,選擇"服務",你可看到新安裝上去的服務:右鍵單擊它選擇啟動。一旦服務啟動,切換回Visual Studio,選擇服務器資源治理器查看此服務:依次選擇視圖、服務器資源治理器,展開你的計算機名,再展開服務,你將看到一個新服務,而帶有的綠色三角形表明它正在運行。


用托管C++編寫Windows服務(圖一)

  在服務器資源治理器中右擊此服務,選擇停止。現在,請在"事件查看器"中查看事件記錄,可看到二個日志記錄:一個告訴你服務已啟動,而另一個告訴你服務已停止。假如你不想產生事件日志記錄,請在服務的設計視圖中修改AutoLog屬性為False。

  卸載服務

  假如你從Debug目錄中安裝此服務,在對它進行修改期間,并不需要卸載,把它停止,重新生成,再啟動就行了。但是,假如你想卸載它,請回到Visual Studio命令提示符窗口,定位到Debug目錄,輸入以下命令:

CGNotifier.exe -Install /u
  現在,服務就會從"服務器資源治理器"和"計算機治理"的服務列表中消失了,也許,需要刷新列表才能看到變化。 喚醒后做一些事情

  當然,以上所示的服務到目前為止并不能做任何事情,為把它變成一個"在設定時刻喚醒"的服務,第一步應在工程中加入一個配置文件,示例如下:

<configuration>
<appSettings>
<add key="runhour" value="22" />
</appSettings>
</configuration>
  另外,還需要復制帶應用程序名如app.config文件到目標工程目錄(Debug或Release):

copy app.config $(ConfigurationName)/$(TargetFileName).config
  為了讀取配置,可在OnStart()或mainLoop()中循環之前加入相應的代碼,在此傾向于盡可能地保持OnStart()為空,因此在mainLoop()中加入以下代碼:

String* sHour = Configuration::ConfigurationSettings::
AppSettings->get_Item("runhour");
int runHour = System::Int32::Parse(sHour);
bool rantoday = false;
  而循環則如下所示:

stopping = false;
while (!stopping)
{
 if (DateTime::Now.Hour == runHour && !rantoday)
 {
  //執行相應的任務
  rantoday = true;
 }
 else
  rantoday = false;
 Threading::Thread::Sleep(loopsleep);
}
  因為到了事先約定的時間,只想要上述代碼運行一次,因此,在服務執行完相應的任務之后,必須把rantoday標志設為true,只要在其他時間,都會被設為false。

  你可以在服務中查找數據庫的新記錄、或查找過期的文件并刪除它們,當然,在服務中可以做的事情遠遠不只這些。但不管要執行的任務是什么,都需要告訴其他人你做過什么,因為服務不具備一個用戶界面,所以也不能彈出一個消息框,因此,使用事件日志是一個不錯的方法。

  請在mainLoop()的循環之前加入以下代碼,以用于設置事件日志記錄:

Diagnostics::EventLog* log ;
if (! Diagnostics::EventLog::SourceExists("CGNotifierService") )
 Diagnostics::EventLog::CreateEventSource("CGNotifierService",CGNotifierLog");
 log = new Diagnostics::EventLog("CGNotifierLog");
 log->Source = "CGNotifierService";
  雖然不用同時設置日志和源代碼,但這樣做的話,消息會在服務器瀏覽器的事件日志之下,創建它們自己的節點。

用托管C++編寫Windows服務(圖二)

  為向日志中寫入,通常只需一行代碼--可把它放在"執行相應任務"的注釋之后: log->WriteEntry("服務的運行時間到了。",
Diagnostics::EventLogEntryType::Information);

  現在,我們大功告成:一個可以安裝、卸載、啟動、停止,并天天向事件日志中寫入一條信息的服務誕生了!從此以后,你將無堅不摧,用C++編寫的Windows服務可不像其他那些 .NET應用程序,它只局限于你的想像力。另外,在創建服務工程時,還要注重分清C++與VB及C#之間的細微差別。還等什么呢,趕緊動手啊!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 罗甸县| 镇平县| 澎湖县| 万载县| 福海县| 资源县| 新龙县| 镇赉县| 汉寿县| 武鸣县| 土默特右旗| 华阴市| 凤阳县| 通榆县| 苍溪县| 丹江口市| 安陆市| 七台河市| 定西市| 荣昌县| 原阳县| 卓资县| 县级市| 富裕县| 巴塘县| 罗城| 泗阳县| 绥江县| 阿拉善盟| 柳林县| 古田县| 吕梁市| 尼勒克县| 潮州市| 光山县| 乌海市| 荃湾区| 什邡市| 桂阳县| 六安市| 东丽区|