青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

大龍的博客

常用鏈接

統計

最新評論

Windows服務編寫原理及探討(三)

    現在我們還剩下一個函數可以在細節上討論,那就是服務的CtrlHandler函數。

  當調用RegisterServiceCtrlHandler函數時,SCM得到并保存這個回調函數的地址。一個SCP調一個告訴SCM如何去控制服務的Win32函數,現在已經有10個預定義的控制請求:

 Requests the service to stop. The hService handle must have SERVICE_STOP access. Requests the service to pause. The hService handle must have SERVICE_PAUSE_CONTINUE access. Requests the paused service to resume. The hService handle must have SERVICE_PAUSE_CONTINUE access. Requests the service to update immediately its current status information to the service control manager. The hService handle must have SERVICE_INTERROGATE access. Requests the service to perform cleanup tasks, because the system is shutting down. For more information, see Remarks. Windows 2000: Requests the service to reread its startup parameters. The hService handle must have SERVICE_PAUSE_CONTINUE access. Windows 2000: Requests the service to update its network binding. The hService handle must have SERVICE_PAUSE_CONTINUE access. Windows 2000: Notifies a network service that a component for binding has been removed. The service should reread its binding information and unbind from the removed component.  Windows 2000: Notifies a network service that a disabled binding has been enabled. The service should reread its binding information and add the new binding.  Windows 2000: Notifies a network service that one of its bindings has been disabled. The service should reread its binding information and remove the binding.  

  上表中標有Windows 2000字樣的就是2000中新添加的控制代碼。除了這些代碼之外,服務也可以接受用戶定義的,范圍在128-255之間的代碼。

  當CtrlHandler函數收到一個SERVICE_CONTROL_STOP、SERVICE_CONTROL_PAUSE、
SERVICE_CONTROL_CONTINUE控制代碼的時候,SetServiceStatus必須被調用去確認這個代碼,并指定你認為服務處理這個狀態變化所需要的時間。

  例如:你的服務收到了停止請求,首先要把SERVICE_STATUS結構的dwCurrentState成員設置成SERVICE_STOP_PENDING,這樣可以使SCM確定你已經收到了控制代碼。當一個服務的暫停或停止操作正在執行的時候,必須指定你認為這種操作所需要的時間:這是因為一個服務也許不能立即改變它的狀態,它可能必須等待一個網絡請求被完成或者數據被刷新到一個驅動器上。指定時間的方法就像我上一章說的那樣,用成員dwCheckPoint和dwWaitHint來指明它完成狀態改變所需要的時間。如果需要,可以用增加dwCheckPoint成員的值和設置dwWaitHint成員的值去指明你期待的服務到達下一步的時間的方式周期性的報告進展情況。

  當整個啟動的過程完成之后,要再一次調用SetServiceStatus。這時就要把SERVICE_STATUS結構的dwCurrentState成員設置成SERVICE_STOPPED,當報告狀態代碼的同時,一定要把成員dwCheckPoint和dwWaitHint設置為0,因為服務已經完成了它的狀態變化。暫停或繼續服務的時候方法也一樣。

  當CtrlHandler函數收到一個SERVICE_CONTROL_INTERROGATE控制代碼的時候,服務將簡單的將dwCurrentState成員設置成服務當前的狀態,同時,把成員dwCheckPoint和dwWaitHint設置為0,然后再調用SetServiceStatus就可以了。

  在操作系統關閉的時候,CtrlHandler函數收到一個SERVICE_CONTROL_SHUTDOWN控制代碼。服務根本無須回應這個代碼,因為系統即將關閉。它將執行保存數據所需要的最小行動集,這是為了確定機器能及時關閉。缺省時系統只給很少的時間去關閉所有的服務,MSDN里面說大概是20秒的時間,不過那可能是Windows NT 4的設置,在我的Windows 2000 Server里這個時間是10秒,你可以手動的修改這個數值,它被記錄在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control子鍵里面的WaitToKillServiceTimeout,單位是毫秒。

  當CtrlHandler函數收到任何用戶定義的代碼時,它應該執行期望的用戶自定義行動。除非用戶自定義的行動要強制服務去暫停、繼續或停止,否則不調SetServiceStatus函數。如果用戶定義的行動強迫服務的狀態發生變化,SetServiceStatus將被調用去設置dwCurrentState、dwCheckPoint和dwWaitHint,具體控制代碼和前面說的一樣。

  如果你的CtrlHandler函數需要很長的時間執行操作的話,千萬要注意:假如CtrlHandler函數在30秒內沒有返回的話,SCM將返回一個錯誤,這不是我們所期望的。所以如果出現上述情況,最好的辦法是再建立一個線程,讓它去繼續執行操作,以便使得CtrlHandler函數能夠迅速的返回。例如,當收到一個SERVICE_CONTROL_STOP請求的時候,就像上面說的一樣,服務可能正在等待一個網絡請求被完成或者數據被刷新到一個驅動器上,而這些操作所需要的時間是你不能估計的,那么就要建立一個新的線程等待操作完成后執行停止命令,CtrlHandler函數在返回之前仍然要報告SERVICE_STOP_PENDING狀態,當新的線程執行完操作之后,再由它將服務的狀態設置成SERVICE_STOPPED。如果當前操作的時間可以估計的到就不要這樣做,仍然使用前面交待的方法處理。

  CtrlHandler函數我就先講這些,下面說說服務怎么安裝。一個服務程序可以使用CreateService函數將服務的信息添加到SCM的數據庫。

SC_HANDLE CreateService(
SC_HANDLE hSCManager, 
// handle to SCM database 
LPCTSTR lpServiceName, 
// name of service to start
LPCTSTR lpDisplayName, 
// display name
DWORD dwDesiredAccess, 
// type of access to service
DWORD dwServiceType, 
// type of service
DWORD dwStartType, 
// when to start service
DWORD dwErrorControl, 
// severity of service failure
LPCTSTR lpBinaryPathName, 
// name of binary file
LPCTSTR lpLoadOrderGroup, 
// name of load ordering group
LPDWORD lpdwTagId, 
// tag identifier
LPCTSTR lpDependencies, 
// array of dependency names
LPCTSTR lpServiceStartName, 
// account name 
LPCTSTR lpPassword 
// account password
);

  hSCManager是一個標示SCM數據庫的句柄,可以簡單的通過調用OpenSCManager得到。

SC_HANDLE OpenSCManager(
LPCTSTR lpMachineName, 
// computer name
LPCTSTR lpDatabaseName, 
// SCM database name
DWORD dwDesiredAccess 
// access type
);

  lpMachineName是目標機器的名字,還記得我在第一章里說過可以在其它的機器上面安裝服務嗎?這就是實現的方法。對方機器名字必須以“\\”開始。如果傳遞NULL或者一個空的字符串的話就默認是本機。

  lpDatabaseName是目標機器上面SCM數據庫的名字,但MSDN里面說這個參數要默認的設置成SERVICES_ACTIVE_DATABASE,如果傳遞NULL,就默認的打開SERVICES_ACTIVE_DATABASE。所以我還沒有真的搞明白這個參數的存在意義,總之使用的時候傳遞NULL就行了。

  dwDesiredAccess是SCM數據庫的訪問權限,具體值見下表:

SC_MANAGER_ALL_ACCESS:
 Includes STANDARD_RIGHTS_REQUIRED, in addition to all of the access types listed in this table. Enables connecting to the service control manager. Enables calling of the CreateService function to create a service object and add it to the database. Enables calling of the EnumServicesStatus function to list the services that are in the database. Enables calling of the LockServiceDatabase function to acquire a lock on the database. Enables calling of the QueryServiceLockStatus function to retrieve the lock status information for the database. 


  想要獲得訪問權限的話,似乎沒那么復雜。MSDN里面說所有進程都被允許獲得對所有SCM數據庫的SC_MANAGER_CONNECT, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS權限,這些權限使得你可以連接SCM數據庫,枚舉目標機器上安裝的服務和查詢目標數據庫是否已被鎖住。但如果要創建服務,首先你需要擁有目標機器的管理員權限,一般的傳遞SC_MANAGER_ALL_ACCESS就可以了。這個函數返回的句柄可以被CloseServiceHandle函數關閉。

  lpServiceName是服務的名字,lpDisplayName是服務在“服務”管理工具里顯示的名字。

  dwDesiredAccess也是訪問的權限,有一個比上面的還長的多的一個表,各位自己查MSDN吧。我們要安裝服務,仍然簡單的傳遞SC_MANAGER_ALL_ACCESS。

  dwServiceType是指你的服務是否和其它的進程相關聯,一般是SERVICE_WIN32_OWN_PROCESS,表示不和任何進程相關聯。如果你確認你的服務需要和某些進程相關聯,就設置成SERVICE_WIN32_SHARE_PROCESS。當你的服務要和桌面相關聯的時候,需要設置成SERVICE_INTERACTIVE_PROCESS。

  dwStartType是服務的啟動方式。服務有三種啟動方式,分別是“自動(SERVICE_AUTO_START)”“手動(SERVICE_DEMAND_START)”和“禁用(SERVICE_DISABLED)”。在MSDN里還有另外的兩種方式,不過是專為驅動程序設置的。

  dwErrorControl決定服務如果在系統啟動的時候啟動失敗的話要怎么辦。

SERVICE_ERROR_IGNORE:
 啟動程序記錄錯誤發生,但繼續啟動。 啟動程序記錄錯誤發生,并彈出一個消息框,但仍繼續啟動 啟動程序記錄錯誤發生,如果是以last-known-good configuration啟動的話,啟動會繼續。否則會以last-known-good configuration重新啟動計算機。 啟動程序記錄錯誤發生,如果可能的話。如果是以last-known-good configuration啟動的話,啟動會失敗。否則會以last-known-good configuration重新啟動計算機。好嚴重的錯誤啊。 


  lpBinaryPathName是服務程序的路徑。MSDN里面特別提到如果服務路徑里面有空格的話一定要將路徑用引號引起來。例如"d:\\my share\\myservice.exe"就一定要指定為"\"d:\\my share\\myservice.exe\""。

  lpLoadOrderGroup的意義在于,如果有一組服務要按照一定的順序啟動的話,這個參數用于指定一個組名用于標志這個啟動順序組,不過我還沒有用過這個參數。你的服務如果不屬于任何啟動順序組,只要傳遞NULL或者一個空的字符串就行了。

  lpdwTagId是應用了上面的參數之后要指定的值,專用于驅動程序,與本文內容無關。傳遞NULL。

  lpDependencies標示一個字符串數組,用于指明一串服務的名字或者一個啟動順序組。當與一個啟動順序組建立關聯的時候,這個參數的含義就是只有你指定的啟動順序組里有至少一個經過對整個組里所有的成員已經全部嘗試過啟動后,有至少一個成員成功啟動,你的服務才能啟動。不需要建立依存關系的話,仍是傳遞NULL或者一個空的字符串。但如果你要指定啟動順序組的話,必須為組名加上SC_GROUP_IDENTIFIER前綴,因為組名和服務名是共享一個命名空間的。

  lpServiceStartName是服務的啟動賬號,如果你設置你的服務的關聯類型是SERVICE_WIN32_OWN_PROCESS的話,你需要以DomainName\UserName的格式指定用戶名,如果這個賬戶在你本機的話,用.\UserName就可以指定。如果傳遞NULL的話,會以本地的系統賬戶登陸。如果是Win NT 4.0或更早的版本的話,如果你指定了SERVICE_WIN32_SHARE_PROCESS,就必須傳遞.\System指定服務使用本地的系統賬戶。最后,如果你指定了SERVICE_INTERACTIVE_PROCESS,你必須使服務運行在本機系統賬戶。

  看名字就知道了,lpPassword是賬戶的密碼。如果指定系統賬戶的話,傳遞NULL。如果賬戶沒有密碼的話,傳遞空字符串。

  總之服務的基本原理就是這樣子了,到了這里這篇文章似乎可以告一段落了,但實際上還有很多內容必須要討論,所以我還不能草草收筆,敬請關注下一章。

本文測試環境為Win2000 Server + SP2
Athlon XP 1700 + 256MB DDR
全部資料參考自MSDN OCT 2001

posted on 2007-12-22 18:08 大龍 閱讀(614) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品v欧美精品v日本精品动漫| 亚洲无亚洲人成网站77777| 欧美国产视频一区二区| 久久精品日韩一区二区三区| 亚洲无限av看| 午夜久久久久久| 久久精品一区二区国产| 久久久久国产精品www| 免费成人在线观看视频| 久久久之久亚州精品露出| 久久一区二区三区四区| 国产精品久久中文| 亚洲国产99| 亚洲欧美久久| 欧美成人精品h版在线观看| 亚洲久久一区| 激情五月综合色婷婷一区二区| 国产午夜精品理论片a级探花| 一区一区视频| 亚洲欧美日韩国产成人| 免费亚洲一区二区| 中文欧美字幕免费| 久久夜色精品国产欧美乱| 国产精品久久久久久久浪潮网站 | 蜜臀av一级做a爰片久久| 欧美日精品一区视频| 91久久久在线| 亚洲福利久久| 久久久久久尹人网香蕉| 国产亚洲a∨片在线观看| 欧美在线视频全部完| 亚洲欧美激情诱惑| 国产小视频国产精品| 欧美一级久久久| 欧美在线91| 在线精品在线| 亚洲国产另类久久精品| 久久一二三四| 一区二区三区|亚洲午夜| 亚洲国产精品综合| 国产精品久久久久毛片软件| 亚洲欧美视频一区| 欧美在线91| 99精品国产高清一区二区| 99精品国产在热久久下载| 欧美日韩国产一区二区三区地区| 99综合精品| 欧美一级播放| 久久精品九九| 中文一区二区| 久久久www成人免费无遮挡大片| 在线观看亚洲a| 99精品国产在热久久下载| 极品av少妇一区二区| 日韩一级二级三级| 一区在线免费观看| 亚洲一区在线直播| 亚洲网站啪啪| 免费一级欧美片在线观看| 午夜精品视频在线观看| 欧美国产日本韩| 噜噜噜躁狠狠躁狠狠精品视频| 欧美日韩系列| 亚洲二区视频| 亚洲人成网站色ww在线| 欧美一级夜夜爽| 久久电影一区| 国产精品一级在线| 亚洲一区二区三区中文字幕| 99re6这里只有精品视频在线观看 99re6这里只有精品 | 欧美韩国一区| 亚洲第一天堂av| 久久精品一区| 免费不卡在线视频| 91久久夜色精品国产网站| 久久综合成人精品亚洲另类欧美| 性亚洲最疯狂xxxx高清| 国产区二精品视| 久久精品视频导航| 欧美福利在线| 亚洲亚洲精品三区日韩精品在线视频| 免费欧美视频| 亚洲一区二区三区乱码aⅴ蜜桃女| 亚洲国产精品女人久久久| 欧美精品97| 欧美尤物一区| 国产精品美腿一区在线看| 亚洲精品乱码视频| 欧美黄色日本| 欧美大尺度在线观看| 一区二区三区视频在线 | 欧美日韩国产探花| 一区二区三区国产在线| 亚洲男人第一av网站| 国产亚洲精品bv在线观看| 你懂的视频欧美| 国产精品高清网站| 久久精品人人做人人爽电影蜜月| 久久久久99| 亚洲一区久久久| 老司机午夜精品视频| 亚洲午夜av在线| 久久在线播放| 欧美一区二区播放| 欧美日本高清一区| 老司机一区二区| 欧美日韩国产一级片| 久久米奇亚洲| 国产精品久久久久999| 欧美成人69av| 国产一区二区久久| 一区二区冒白浆视频| 亚洲国产精品电影| 午夜精品成人在线视频| 制服丝袜亚洲播放| 久久尤物视频| 麻豆91精品| 国产中文一区| 午夜欧美视频| 欧美一级理论片| 欧美区亚洲区| 亚洲高清在线精品| 国产欧美精品一区aⅴ影院| 亚洲精品一区久久久久久 | 亚洲欧美日韩国产中文| 欧美jizz19性欧美| 欧美插天视频在线播放| 国内精品视频一区| 午夜精品久久久久久久久久久| 在线一区二区三区四区五区| 久久野战av| 免费一级欧美片在线播放| 国产一区二区在线观看免费播放| 亚洲视频在线观看网站| 亚洲图片在线| 欧美性猛交99久久久久99按摩| 亚洲国产一区在线观看| 亚洲精品视频在线观看网站| 免费不卡亚洲欧美| 欧美黄色免费网站| 亚洲伦理精品| 欧美日韩国产一区二区三区地区| 欧美高清视频| 久久久精品一品道一区| 久久久久久综合网天天| 韩国久久久久| 久久综合99re88久久爱| 亚洲高清在线播放| 亚洲天天影视| 国产一区 二区 三区一级| 久久精品久久99精品久久| 免费在线视频一区| 亚洲国产日韩欧美在线图片| 欧美a级理论片| 中文精品视频| 久久久久91| 亚洲日韩欧美视频| 欧美视频不卡中文| 性欧美暴力猛交69hd| 欧美成人免费在线视频| 日韩午夜av| 国产日本亚洲高清| 猛男gaygay欧美视频| 日韩视频一区二区在线观看| 午夜精品久久久久久久久| 韩日欧美一区二区| 欧美福利影院| 亚洲欧美另类在线观看| 欧美成人首页| 亚洲欧洲av一区二区| 1769国产精品| 国产精品久久波多野结衣| 久久久噜噜噜久久狠狠50岁| 亚洲麻豆一区| 美女国内精品自产拍在线播放| 一区二区三区 在线观看视| 国产日本亚洲高清| 欧美精品在线免费播放| 欧美中文在线字幕| 夜夜爽99久久国产综合精品女不卡| 久久精品综合网| 亚洲小视频在线观看| 韩国av一区二区三区在线观看| 欧美久久精品午夜青青大伊人| 午夜亚洲视频| 9人人澡人人爽人人精品| 欧美a级一区二区| 亚洲免费一在线| 亚洲精品日日夜夜| 极品裸体白嫩激情啪啪国产精品| 欧美日韩精品免费| 欧美96在线丨欧| 久久久人成影片一区二区三区观看| 亚洲乱码视频| 亚洲第一精品在线| 久热精品视频在线观看一区| 午夜精品理论片| 亚洲午夜久久久久久久久电影网| 在线观看一区| 国内欧美视频一区二区|