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

大龍的博客

常用鏈接

統(tǒng)計

最新評論

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

  上一章其實(shí)只是概括性的介紹,下面開始才是真正的細(xì)節(jié)所在。在進(jìn)入點(diǎn)函數(shù)里面要完成ServiceMain的初始化,準(zhǔn)確點(diǎn)說是初始化一個SERVICE_TABLE_ENTRY結(jié)構(gòu)數(shù)組,這個結(jié)構(gòu)記錄了這個服務(wù)程序里面所包含的所有服務(wù)的名稱和服務(wù)的進(jìn)入點(diǎn)函數(shù),下面是一個SERVICE_TABLE_ENTRY的例子:

SERVICE_TABLE_ENTRY service_table_entry[] =
{
  { "MyFTPd" , FtpdMain },
  { "MyHttpd", Httpserv},
  { NULL, NULL },
};

  第一個成員代表服務(wù)的名字,第二個成員是ServiceMain回調(diào)函數(shù)的地址,上面的服務(wù)程序因為擁有兩個服務(wù),所以有三個SERVICE_TABLE_ENTRY元素,前兩個用于服務(wù),最后的NULL指明數(shù)組的結(jié)束。

  接下來這個數(shù)組的地址被傳遞到StartServiceCtrlDispatcher函數(shù):

BOOL StartServiceCtrlDispatcher(
LPSERVICE_TABLE_ENTRY lpServiceStartTable
)

  這個Win32函數(shù)表明可執(zhí)行文件的進(jìn)程怎樣通知SCM包含在這個進(jìn)程中的服務(wù)。就像上一章中講的那樣,StartServiceCtrlDispatcher為每一個傳遞到它的數(shù)組中的非空元素產(chǎn)生一個新的線程,每一個進(jìn)程開始執(zhí)行由數(shù)組元素中的lpServiceStartTable指明的ServiceMain函數(shù)。

  SCM啟動一個服務(wù)程序之后,它會等待該程序的主線程去調(diào)StartServiceCtrlDispatcher。如果那個函數(shù)在兩分鐘內(nèi)沒有被調(diào)用,SCM將會認(rèn)為這個服務(wù)有問題,并調(diào)用TerminateProcess去殺死這個進(jìn)程。這就要求你的主線程要盡可能快的調(diào)用StartServiceCtrlDispatcher。

  StartServiceCtrlDispatcher函數(shù)則并不立即返回,相反它會駐留在一個循環(huán)內(nèi)。當(dāng)在該循環(huán)內(nèi)時,StartServiceCtrlDispatcher懸掛起自己,等待下面兩個事件中的一個發(fā)生。第一,如果SCM要去送一個控制通知給運(yùn)行在這個進(jìn)程內(nèi)一個服務(wù)的時候,這個線程就會激活。當(dāng)控制通知到達(dá)后,線程激活并調(diào)用相應(yīng)服務(wù)的CtrlHandler函數(shù)。CtrlHandler函數(shù)處理這個服務(wù)控制通知,并返回到StartServiceCtrlDispatcher。StartServiceCtrlDispatcher循環(huán)回去后再一次懸掛自己。

  第二,如果服務(wù)線程中的一個服務(wù)中止,這個線程也將激活。在這種情況下,該進(jìn)程將運(yùn)行在它里面的服務(wù)數(shù)減一。如果服務(wù)數(shù)為零,StartServiceCtrlDispatcher就會返回到入口點(diǎn)函數(shù),以便能夠執(zhí)行任何與進(jìn)程有關(guān)的清除工作并結(jié)束進(jìn)程。如果還有服務(wù)在運(yùn)行,哪怕只是一個服務(wù),StartServiceCtrlDispatcher也會繼續(xù)循環(huán)下去,繼續(xù)等待其它的控制通知或者剩下的服務(wù)線程中止。

  上面的內(nèi)容是關(guān)于入口點(diǎn)函數(shù)的,下面的內(nèi)容則是關(guān)于ServiceMain函數(shù)的。還記得以前講過的ServiceMain函數(shù)的的原型嗎?但實(shí)際上一個ServiceMain函數(shù)通常忽略傳遞給它的兩個參數(shù),因為服務(wù)一般不怎么傳遞參數(shù)。設(shè)置一個服務(wù)最好的方法就是設(shè)置注冊表,一般服務(wù)在
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Service\ServiceName\Parameters
子鍵下存放自己的設(shè)置,這里的ServiceName是服務(wù)的名字。事實(shí)上,可能要寫一個客戶應(yīng)用程序去進(jìn)行服務(wù)的背景設(shè)置,這個客戶應(yīng)用程序?qū)⑦@些信息存在注冊表中,以便服務(wù)讀取。當(dāng)一個外部應(yīng)用程序已經(jīng)改變了某個正在運(yùn)行中的服務(wù)的設(shè)置數(shù)據(jù)的時候,這個服務(wù)能夠用RegNotifyChangeKeyValue函數(shù)去接受一個通知,這樣就允許服務(wù)快速的重新設(shè)置自己。

  前面講到StartServiceCtrlDispatcher為每一個傳遞到它的數(shù)組中的非空元素產(chǎn)生一個新的線程。接下來,一個ServiceMain要做些什么呢?MSDN里面的原文是這樣說的:The ServiceMain function should immediately call the RegisterServiceCtrlHandler function to specify a Handler function to handle control requests. Next, it should call the SetServiceStatus function to send status information to the service control manager. 為什么呢?因為發(fā)出啟動服務(wù)請求之后,如果在一定時間之內(nèi)無法完成服務(wù)的初始化,SCM會認(rèn)為服務(wù)的啟動已經(jīng)失敗了,這個時間的長度在Win NT 4.0中是80秒,Win2000中不詳...

  基于上面的理由,ServiceMain要迅速完成自身工作,首先是必不可少的兩項工作,第一項是調(diào)用RegisterServiceCtrlHandler函數(shù)去通知SCM它的CtrlHandler回調(diào)函數(shù)的地址:

SERVICE_STATUS_HANDLE RegisterServiceCtrlHandler(
LPCTSTR lpServiceName, //服務(wù)的名字
LPHANDLER_FUNCTION lpHandlerProc //CtrlHandler函數(shù)地址
)


  第一個參數(shù)指明你正在建立的CtrlHandler是為哪一個服務(wù)所用,第二個參數(shù)是CtrlHandler函數(shù)的地址。lpServiceName必須和在SERVICE_TABLE_ENTRY里面被初始化的服務(wù)的名字相匹配。RegisterServiceCtrlHandler返回一個SERVICE_STATUS_HANDLE,這是一個32位的句柄。SCM用它來唯一確定這個服務(wù)。當(dāng)這個服務(wù)需要把它當(dāng)時的狀態(tài)報告給SCM的時候,就必須把這個句柄傳給需要它的Win32函數(shù)。注意:這個句柄和其他大多數(shù)的句柄不同,你無需關(guān)閉它。

  SCM要求ServiceMain函數(shù)的線程在一秒鐘內(nèi)調(diào)用RegisterServiceCtrlHandler函數(shù),否則SCM會認(rèn)為服務(wù)已經(jīng)失敗。但在這種情況下,SCM不會終止服務(wù),不過在NT 4中將無法啟動這個服務(wù),同時會返回一個不正確的錯誤信息,這一點(diǎn)在Windows 2000中得到了修正。

  在RegisterServiceCtrlHandler函數(shù)返回后,ServiceMain線程要立即告訴SCM服務(wù)正在繼續(xù)初始化。具體的方法是通過調(diào)用SetServiceStatus函數(shù)傳遞SERVICE_STATUS數(shù)據(jù)結(jié)構(gòu)。

BOOL SetServiceStatus(
SERVICE_STATUS_HANDLE hService, //服務(wù)的句柄
SERVICE_STATUS lpServiceStatus //SERVICE_STATUS結(jié)構(gòu)的地址
)

  這個函數(shù)要求傳遞給它指明服務(wù)的句柄(剛剛通過調(diào)用RegisterServiceCtrlHandler得到),和一個初始化的SERVICE_STATUS結(jié)構(gòu)的地址:

typedef struct _SERVICE_STATUS
{
DWORD dwServiceType;
DWORD dwCurrentState;
DWORD dwControlsAccepted;
DWORD dwWin32ExitCode;
DWORD dwServiceSpecificExitCode;
DWORD dwCheckPoint;
DWORD dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;

  SERVICE_STATUS結(jié)構(gòu)含有七個成員,它們反映服務(wù)的現(xiàn)行狀態(tài)。所有這些成員必須在這個結(jié)構(gòu)被傳遞到SetServiceStatus之前正確的設(shè)置。

  成員dwServiceType指明服務(wù)可執(zhí)行文件的類型。如果你的可執(zhí)行文件中只有一個單獨(dú)的服務(wù),就把這個成員設(shè)置成SERVICE_WIN32_OWN_PROCESS;如果擁有多個服務(wù)的話,就設(shè)置成SERVICE_WIN32_SHARE_PROCESS。除了這兩個標(biāo)志之外,如果你的服務(wù)需要和桌面發(fā)生交互(當(dāng)然不推薦這樣做),就要用“OR”運(yùn)算符附加上SERVICE_INTERACTIVE_PROCESS。這個成員的值在你的服務(wù)的生存期內(nèi)絕對不應(yīng)該改變。

  成員dwCurrentState是這個結(jié)構(gòu)中最重要的成員,它將告訴SCM你的服務(wù)的現(xiàn)行狀態(tài)。為了報告服務(wù)仍在初始化,應(yīng)該把這個成員設(shè)置成SERVICE_START_PENDING。在以后具體講述CtrlHandler函數(shù)的時候具體解釋其它可能的值。

  成員dwControlsAccepted指明服務(wù)愿意接受什么樣的控制通知。如果你允許一個SCP去暫停/繼續(xù)服務(wù),就把它設(shè)成SERVICE_ACCEPT_PAUSE_CONTINUE。很多服務(wù)不支持暫停或繼續(xù),就必須自己決定在服務(wù)中它是否可用。如果你允許一個SCP去停止服務(wù),就要設(shè)置它為SERVICE_ACCEPT_STOP。如果服務(wù)要在操作系統(tǒng)關(guān)閉的時候得到通知,設(shè)置它為SERVICE_ACCEPT_SHUTDOWN可以收到預(yù)期的結(jié)果。這些標(biāo)志可以用“OR”運(yùn)算符組合。

  成員dwWin32ExitCode和dwServiceSpecificExitCode是允許服務(wù)報告錯誤的關(guān)鍵,如果希望服務(wù)去報告一個Win32錯誤代碼(預(yù)定義在WinError.h中),它就設(shè)置dwWin32ExitCode為需要的代碼。一個服務(wù)也可以報告它本身特有的、沒有映射到一個預(yù)定義的Win32錯誤代碼中的錯誤。為了這一點(diǎn),要把dwWin32ExitCode設(shè)置為ERROR_SERVICE_SPECIFIC_ERROR,然后還要設(shè)置成員dwServiceSpecificExitCode為服務(wù)特有的錯誤代碼。當(dāng)服務(wù)運(yùn)行正常,沒有錯誤可以報告的時候,就設(shè)置成員dwWin32ExitCode為NO_ERROR。

  最后的兩個成員dwCheckPoint和dwWaitHint是一個服務(wù)用來報告它當(dāng)前的事件進(jìn)展情況的。當(dāng)成員dwCurrentState被設(shè)置成SERVICE_START_PENDING的時候,應(yīng)該把dwCheckPoint設(shè)成0,dwWaitHint設(shè)成一個經(jīng)過多次嘗試后確定比較合適的數(shù),這樣服務(wù)才能高效運(yùn)行。一旦服務(wù)被完全初始化,就應(yīng)該重新初始化SERVICE_STATUS結(jié)構(gòu)的成員,更改dwCurrentState為SERVICE_RUNNING,然后把dwCheckPoint和dwWaitHint都改為0。

  dwCheckPoint成員的存在對用戶是有益的,它允許一個服務(wù)報告它處于進(jìn)程的哪一步。每一次調(diào)用SetServiceStatus時,可以增加它到一個能指明服務(wù)已經(jīng)執(zhí)行到哪一步的數(shù)字,它可以幫助用戶決定多長時間報告一次服務(wù)的進(jìn)展情況。如果決定要報告服務(wù)的初始化進(jìn)程的每一步,就應(yīng)該設(shè)置dwWaitHint為你認(rèn)為到達(dá)下一步所需的毫秒數(shù),而不是服務(wù)完成它的進(jìn)程所需的毫秒數(shù)。

  在服務(wù)的所有初始化都完成之后,服務(wù)調(diào)用SetServiceStatus指明SERVICE_RUNNING,在那一刻服務(wù)已經(jīng)開始運(yùn)行。通常一個服務(wù)是把自己放在一個循環(huán)之中來運(yùn)行的。在循環(huán)的內(nèi)部這個服務(wù)進(jìn)程懸掛自己,等待指明它下一步是應(yīng)該暫停、繼續(xù)或停止之類的網(wǎng)絡(luò)請求或通知。當(dāng)一個請求到達(dá)的時候,服務(wù)線程激活并處理這個請求,然后再循環(huán)回去等待下一個請求/通知。

  如果一個服務(wù)由于一個通知而激活,它會先處理這個通知,除非這個服務(wù)得到的是停止或關(guān)閉的通知。如果真的是停止或關(guān)閉的通知,服務(wù)線程將退出循環(huán),執(zhí)行必要的清除操作,然后從這個線程返回。當(dāng)ServiceMain線程返回并中止時,引起在StartServiceCtrlDispatcher內(nèi)睡眠的線程激活,并像在前面解釋過的那樣,減少它運(yùn)行的服務(wù)的計數(shù)。

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


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   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>
            亚洲国产成人高清精品| 久久久99精品免费观看不卡| 欧美亚洲一区二区在线| 一区二区三区久久| 99综合视频| 亚洲欧美日韩一区二区在线| 午夜视频在线观看一区二区三区 | 日韩一二三区视频| 在线一区二区三区四区| 亚洲一区二区四区| 欧美在线地址| 欧美国产成人在线| 99伊人成综合| 欧美在线观看一区二区三区| 牛人盗摄一区二区三区视频| 欧美人与性动交α欧美精品济南到| 欧美视频一区二区| 国产日韩欧美在线播放不卡| 亚洲欧洲精品一区二区精品久久久| 99re亚洲国产精品| 亚洲一区在线播放| 免费在线观看一区二区| 日韩亚洲欧美中文三级| 午夜久久久久| 欧美精品一区二| 国内精品视频久久| 亚洲一区二区三区精品视频| 快播亚洲色图| 亚洲欧美激情四射在线日| 美日韩精品视频| 国产欧美丝祙| 亚洲综合国产激情另类一区| 亚洲成人在线视频播放| 亚洲人人精品| 久久午夜电影| 亚洲一区中文| 91久久在线观看| 久久久.com| 国产区精品视频| 久久爱另类一区二区小说| 国外精品视频| 欧美在线免费视屏| 亚洲少妇一区| 欧美日韩理论| 亚洲美女精品成人在线视频| 老司机精品导航| 欧美一区二区三区另类| 欧美激情中文字幕乱码免费| 亚洲大片免费看| 久久这里只有| 久久精品国产一区二区三| 国产欧美日韩一区二区三区在线 | 欧美在线观看视频一区二区三区| 亚洲日产国产精品| 女主播福利一区| 在线免费观看成人网| 久久九九精品| 欧美一区二区三区婷婷月色 | 亚洲自拍三区| 国产精品国产三级国产aⅴ浪潮 | 亚洲精品一区二区三区婷婷月| 久久黄色级2电影| 国产日本亚洲高清| 午夜精品久久久久久久久| 中文日韩在线| 国产欧美日韩综合一区在线观看| 国产丝袜一区二区| 性欧美精品高清| 欧美一区二区三区视频免费播放| 国产亚洲人成网站在线观看| 久久人人看视频| 久久亚洲综合色| 亚洲毛片在线观看| 在线亚洲国产精品网站| 国产精品一级二级三级| 久久国产精品久久久| 欧美在线观看天堂一区二区三区| 一区二区在线免费观看| 亚洲动漫精品| 欧美视频一区| 久久香蕉国产线看观看av| 久久婷婷一区| 在线亚洲欧美视频| 亚洲免费在线| 亚洲国产你懂的| 中文有码久久| 伊人久久噜噜噜躁狠狠躁| 91久久精品国产91性色| 国产精品夜夜夜| 欧美搞黄网站| 国产精品久久久久久久久久免费看| 久久精品中文字幕一区二区三区| 久久尤物视频| 一区二区成人精品| 欧美一区久久| 国产精品99久久久久久久vr| 性8sex亚洲区入口| 亚洲免费av电影| 欧美影院成年免费版| 99精品视频免费全部在线| 午夜精品视频在线| 一区二区三区**美女毛片| 欧美在线高清视频| 亚洲激情在线观看视频免费| 999在线观看精品免费不卡网站| 国产一区av在线| 亚洲精选视频免费看| 好看的av在线不卡观看| 一区二区三区久久网| 亚洲第一区在线观看| 在线视频欧美日韩精品| 亚洲欧洲三级电影| 亚洲欧美国产三级| 亚洲香蕉伊综合在人在线视看| 久久九九热re6这里有精品| 亚洲小少妇裸体bbw| 欧美第一黄网免费网站| 狂野欧美激情性xxxx欧美| 国产美女精品免费电影| 日韩亚洲欧美中文三级| 亚洲精选成人| 久久久噜噜噜久久中文字幕色伊伊| 亚洲在线一区| 国内精品美女av在线播放| 国产精品麻豆va在线播放| 亚洲欧美日韩专区| 欧美成人午夜影院| 亚洲视屏一区| 欧美第一黄网免费网站| 日韩午夜在线电影| 亚洲一区二区三区免费在线观看| 99国产麻豆精品| 99伊人成综合| 国产视频综合在线| 久久久久免费视频| 久久蜜桃精品| 亚洲精品无人区| 欧美制服丝袜| 欧美成人第一页| 午夜精品久久一牛影视| 亚洲午夜在线视频| 一区二区三区国产在线| 欧美午夜精品久久久久久孕妇| 亚洲在线中文字幕| 久久久久久高潮国产精品视| 免费不卡在线视频| 亚洲一区3d动漫同人无遮挡| 这里只有精品在线播放| 一区二区三区在线不卡| 久久久亚洲精品一区二区三区| 久久精品道一区二区三区| 在线播放亚洲一区| 亚洲桃花岛网站| 一区二区三区精密机械公司 | 亚洲精美视频| 香蕉成人久久| 亚洲免费在线电影| 男男成人高潮片免费网站| 久久av资源网站| 欧美日一区二区三区在线观看国产免| 亚洲一区二区免费看| 蜜臀91精品一区二区三区| 亚洲一区免费| 亚洲精品中文字幕在线观看| 一区二区视频欧美| 亚洲国产日韩精品| 在线播放不卡| 亚洲免费一区二区| 久久福利视频导航| 国语精品中文字幕| 日韩午夜三级在线| 国产一区二区电影在线观看| 亚洲黄网站在线观看| 在线一区二区三区四区五区| 性欧美大战久久久久久久久| 久久精品一区二区三区四区| 激情五月婷婷综合| 欧美日韩一区综合| 久久国产手机看片| 加勒比av一区二区| 另类酷文…触手系列精品集v1小说| 模特精品在线| 国产精品一区二区男女羞羞无遮挡| 久久在线免费观看| 蜜臀av一级做a爰片久久| 亚洲欧美日韩系列| 亚洲国产一成人久久精品| 欧美午夜视频一区二区| 久久久www| 午夜影院日韩| 亚洲午夜精品网| 在线不卡中文字幕| 国产精品免费aⅴ片在线观看| 亚洲国产日韩在线| 99人久久精品视频最新地址| 欧美精品色综合| 久久人人97超碰人人澡爱香蕉| 亚洲国产精彩中文乱码av在线播放| 久久免费午夜影院| 亚洲黄网站在线观看|