• <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>

            大龍的博客

            常用鏈接

            統(tǒng)計

            最新評論

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

                現(xiàn)在我們還剩下一個函數(shù)可以在細(xì)節(jié)上討論,那就是服務(wù)的CtrlHandler函數(shù)。

              當(dāng)調(diào)用RegisterServiceCtrlHandler函數(shù)時,SCM得到并保存這個回調(diào)函數(shù)的地址。一個SCP調(diào)一個告訴SCM如何去控制服務(wù)的Win32函數(shù),現(xiàn)在已經(jīng)有10個預(yù)定義的控制請求:

             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.  

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

              當(dāng)CtrlHandler函數(shù)收到一個SERVICE_CONTROL_STOP、SERVICE_CONTROL_PAUSE、
            SERVICE_CONTROL_CONTINUE控制代碼的時候,SetServiceStatus必須被調(diào)用去確認(rèn)這個代碼,并指定你認(rèn)為服務(wù)處理這個狀態(tài)變化所需要的時間。

              例如:你的服務(wù)收到了停止請求,首先要把SERVICE_STATUS結(jié)構(gòu)的dwCurrentState成員設(shè)置成SERVICE_STOP_PENDING,這樣可以使SCM確定你已經(jīng)收到了控制代碼。當(dāng)一個服務(wù)的暫?;蛲V共僮髡趫?zhí)行的時候,必須指定你認(rèn)為這種操作所需要的時間:這是因?yàn)橐粋€服務(wù)也許不能立即改變它的狀態(tài),它可能必須等待一個網(wǎng)絡(luò)請求被完成或者數(shù)據(jù)被刷新到一個驅(qū)動器上。指定時間的方法就像我上一章說的那樣,用成員dwCheckPoint和dwWaitHint來指明它完成狀態(tài)改變所需要的時間。如果需要,可以用增加dwCheckPoint成員的值和設(shè)置dwWaitHint成員的值去指明你期待的服務(wù)到達(dá)下一步的時間的方式周期性的報告進(jìn)展情況。

              當(dāng)整個啟動的過程完成之后,要再一次調(diào)用SetServiceStatus。這時就要把SERVICE_STATUS結(jié)構(gòu)的dwCurrentState成員設(shè)置成SERVICE_STOPPED,當(dāng)報告狀態(tài)代碼的同時,一定要把成員dwCheckPoint和dwWaitHint設(shè)置為0,因?yàn)榉?wù)已經(jīng)完成了它的狀態(tài)變化。暫?;蚶^續(xù)服務(wù)的時候方法也一樣。

              當(dāng)CtrlHandler函數(shù)收到一個SERVICE_CONTROL_INTERROGATE控制代碼的時候,服務(wù)將簡單的將dwCurrentState成員設(shè)置成服務(wù)當(dāng)前的狀態(tài),同時,把成員dwCheckPoint和dwWaitHint設(shè)置為0,然后再調(diào)用SetServiceStatus就可以了。

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

              當(dāng)CtrlHandler函數(shù)收到任何用戶定義的代碼時,它應(yīng)該執(zhí)行期望的用戶自定義行動。除非用戶自定義的行動要強(qiáng)制服務(wù)去暫停、繼續(xù)或停止,否則不調(diào)SetServiceStatus函數(shù)。如果用戶定義的行動強(qiáng)迫服務(wù)的狀態(tài)發(fā)生變化,SetServiceStatus將被調(diào)用去設(shè)置dwCurrentState、dwCheckPoint和dwWaitHint,具體控制代碼和前面說的一樣。

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

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

            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是一個標(biāo)示SCM數(shù)據(jù)庫的句柄,可以簡單的通過調(diào)用OpenSCManager得到。

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

              lpMachineName是目標(biāo)機(jī)器的名字,還記得我在第一章里說過可以在其它的機(jī)器上面安裝服務(wù)嗎?這就是實(shí)現(xiàn)的方法。對方機(jī)器名字必須以“\\”開始。如果傳遞NULL或者一個空的字符串的話就默認(rèn)是本機(jī)。

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

              dwDesiredAccess是SCM數(shù)據(jù)庫的訪問權(quán)限,具體值見下表:

            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. 


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

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

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

              dwServiceType是指你的服務(wù)是否和其它的進(jìn)程相關(guān)聯(lián),一般是SERVICE_WIN32_OWN_PROCESS,表示不和任何進(jìn)程相關(guān)聯(lián)。如果你確認(rèn)你的服務(wù)需要和某些進(jìn)程相關(guān)聯(lián),就設(shè)置成SERVICE_WIN32_SHARE_PROCESS。當(dāng)你的服務(wù)要和桌面相關(guān)聯(lián)的時候,需要設(shè)置成SERVICE_INTERACTIVE_PROCESS。

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

              dwErrorControl決定服務(wù)如果在系統(tǒng)啟動的時候啟動失敗的話要怎么辦。

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


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

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

              lpdwTagId是應(yīng)用了上面的參數(shù)之后要指定的值,專用于驅(qū)動程序,與本文內(nèi)容無關(guān)。傳遞NULL。

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

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

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

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

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

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


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久精品国产99久久香蕉| 性欧美丰满熟妇XXXX性久久久 | 久久se精品一区二区| 潮喷大喷水系列无码久久精品| 国产V亚洲V天堂无码久久久| 久久成人精品| 久久亚洲私人国产精品| 国产精品99久久不卡| 久久精品成人欧美大片| 中文精品久久久久国产网址| 亚洲精品无码专区久久久| 国产精品成人99久久久久91gav| 久久99热这里只频精品6| 91亚洲国产成人久久精品| 中文字幕无码av激情不卡久久| 国产午夜免费高清久久影院| 亚洲午夜精品久久久久久浪潮 | 精品久久8x国产免费观看| 久久精品一区二区三区中文字幕| 国产精品久久婷婷六月丁香| 久久国产免费| 99国内精品久久久久久久| 久久综合九色综合网站| av色综合久久天堂av色综合在| 久久久久亚洲AV无码专区网站| 日本福利片国产午夜久久| 久久久一本精品99久久精品66| 久久久久亚洲精品日久生情| 日本久久中文字幕| 久久久久一级精品亚洲国产成人综合AV区 | 久久久91人妻无码精品蜜桃HD| 77777亚洲午夜久久多喷| 久久精品国产亚洲77777| 久久婷婷五月综合97色| 伊人久久大香线蕉综合影院首页| 亚洲精品无码专区久久同性男| 精品久久人人做人人爽综合| 久久久久亚洲AV无码去区首| 国产亚洲美女精品久久久| 久久久久久国产a免费观看不卡 | 精品熟女少妇a∨免费久久|