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

大龍的博客

常用鏈接

統計

最新評論

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>
            国产亚洲一本大道中文在线| 亚洲免费伊人电影在线观看av| av成人国产| 99精品国产99久久久久久福利| 亚洲精品久久在线| 一区二区三区久久精品| 午夜精品一区二区三区在线| 欧美在线看片a免费观看| 久久成年人视频| 欧美顶级艳妇交换群宴| 99精品视频免费观看视频| 亚洲国产日韩一级| 久久精品99无色码中文字幕| 老司机午夜免费精品视频| 亚洲福利视频在线| 亚洲无线观看| 久久夜色精品国产噜噜av| 欧美日韩国产色视频| 欧美在线免费视屏| 免费欧美在线视频| 国产免费成人| 久久裸体视频| 欧美调教视频| 亚洲级视频在线观看免费1级| 亚洲一区二区视频| 麻豆精品精华液| 正在播放欧美一区| 久久综合色88| 国产视频一区免费看| 久久精品亚洲一区| 亚洲精品欧美日韩专区| 欧美中文字幕在线观看| 欧美特黄a级高清免费大片a级| 在线看片日韩| 久久精品国产精品亚洲综合| 日韩一二三区视频| 欧美mv日韩mv国产网站| 国产真实精品久久二三区| 午夜精品久久久久久久久| 亚洲精品午夜精品| 毛片av中文字幕一区二区| 国产香蕉97碰碰久久人人| 亚洲一级特黄| 一区二区av在线| 欧美大胆成人| 久久精品72免费观看| 国产欧美日韩精品丝袜高跟鞋| 国产精品99久久久久久白浆小说 | 欧美在线观看视频一区二区三区 | 免费看的黄色欧美网站| 国产精品网曝门| 亚洲一区二区成人| 亚洲精品资源| 欧美日韩p片| 亚洲天堂av综合网| a4yy欧美一区二区三区| 亚洲视频1区| 国内外成人免费视频| 欧美中文在线免费| 篠田优中文在线播放第一区| 国产一区二区电影在线观看| 国产精品久久久久久久9999 | 久久久www| 久久综合伊人77777尤物| 国语精品中文字幕| 米奇777在线欧美播放| 久久人91精品久久久久久不卡 | 亚洲精品日韩在线| 欧美黄色成人网| 牛夜精品久久久久久久99黑人| 91久久精品视频| 亚洲区第一页| 国产精品久久久一本精品| 久久aⅴ国产紧身牛仔裤| 欧美综合激情网| 亚洲国产一区在线观看| 亚洲高清自拍| 欧美日韩一区在线观看视频| 欧美一级电影久久| 久久不射网站| 日韩一本二本av| 亚洲小说春色综合另类电影| 日韩视频在线播放| 国产精品一区在线播放| 毛片av中文字幕一区二区| 欧美aaaaaaaa牛牛影院| 亚洲图片欧洲图片日韩av| 欧美亚洲色图校园春色| 欧美激情一区二区三区在线| 久久九九国产精品| 日韩亚洲在线| 久久黄色级2电影| 欧美成人资源网| 亚洲欧美中文日韩在线| 老色批av在线精品| 欧美一级电影久久| 欧美护士18xxxxhd| 久久精品欧美日韩精品| 欧美日韩国产精品成人| 久久久一区二区| 国产精品h在线观看| 麻豆九一精品爱看视频在线观看免费 | 欧美在线视频不卡| 欧美国产在线观看| 国产欧美一区二区精品婷婷| 亚洲国产一区二区在线| 国产一区二区三区在线观看免费 | 免费成人高清在线视频| 国产精品二区三区四区| 91久久久久久久久久久久久| 一本大道久久a久久精二百| 亚洲在线观看免费| 亚洲一区二区三区高清 | 日韩一区二区精品| 久久九九全国免费精品观看| 亚洲综合精品一区二区| 欧美一级专区免费大片| 亚洲一区免费在线观看| 欧美91大片| 欧美高清在线视频| 激情久久久久| 国产精品进线69影院| 亚洲精品一区二区在线| 羞羞漫画18久久大片| 亚洲综合精品自拍| 欧美视频中文在线看| 最新69国产成人精品视频免费| 一区久久精品| 久久久91精品国产一区二区三区| 久久精品国产久精国产爱| 国产嫩草一区二区三区在线观看| 久久香蕉精品| 午夜视频一区在线观看| 欧美日韩亚洲一区三区| 亚洲人成在线影院| 日韩午夜电影av| 欧美激情第五页| 亚洲精品国产精品久久清纯直播| 亚洲精品欧美激情| 欧美日本三区| 一区二区三区四区五区视频| 亚洲影院免费| 国产伦理精品不卡| 欧美一级淫片播放口| 久久精品首页| 在线看片成人| 欧美激情综合五月色丁香小说| 亚洲区第一页| 国产精品国产三级国产普通话蜜臀 | 欧美视频在线免费| 亚洲自拍偷拍麻豆| 久久久噜噜噜久久中文字免| 欧美在线1区| 在线亚洲国产精品网站| 亚洲欧洲av一区二区| 国产字幕视频一区二区| 欧美香蕉大胸在线视频观看| 一区二区三区欧美日韩| 午夜精品一区二区三区在线播放| 国产区亚洲区欧美区| 久久人人爽人人爽| 日韩视频免费观看| 久久激情五月婷婷| 亚洲欧洲午夜| 国产精品一区二区在线| 久久综合九色综合久99| 一区二区国产在线观看| 久久在线视频在线| 亚洲手机成人高清视频| 激情五月婷婷综合| 欧美特黄a级高清免费大片a级| 久久精品亚洲一区二区三区浴池| 亚洲精品久久久久久久久久久久久 | 久久久水蜜桃av免费网站| 亚洲日本成人网| 久久夜色精品| 亚洲欧美日产图| 午夜在线电影亚洲一区| 国内久久视频| 国产精品久久久久91| 男人的天堂亚洲| 欧美一区二区私人影院日本| 亚洲精品一级| 欧美激情亚洲| 久久亚洲国产成人| 亚洲欧美日韩在线一区| 日韩亚洲不卡在线| 在线观看国产成人av片| 亚洲精品综合久久中文字幕| 欧美电影资源| 久久久久在线| 欧美一区二区视频网站| 亚洲一区二区av电影| 亚洲精品久久久久久一区二区 | 亚洲视频1区2区| 亚洲第一福利视频| 久久人人97超碰人人澡爱香蕉| 亚洲欧美怡红院| 在线亚洲激情| 亚洲伦理在线|