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

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

COM---EXE中的服務器

2019-11-08 02:48:23
字體:
來源:轉載
供稿:網友

調整:將函數調用的參數從一個進程的地址空間傳到另一個進程的地址空間。

代理:同另外一個組件行為相同的組件,必須是DLL形式的,因為需要訪問客戶進程的地址空間以便對接口數據進行調整。

殘根:對客戶傳過來的數據進行反調整。

IDL(接口定義語言)

定義IX接口

//// Server.idl - IDL source for Server.dll//// The MIDL compiler generates PRoxy/stub code and a type library// from this file.////// Interface descr使用IX接口

//COM對于字符串的標準約定是使用Unicode字符,即wchar_t wchar_t* szOut = NULL ; hr = pIX->FxStringIn(L"This is the test.") ; assert(SUCCEEDED(hr)) ; //大多數COM函數返回的均為HRESULT值 //若某個函數需要返回一個非HRESULT類型的值,在FxStringOut中定義了 //一個輸出參數,以從組件中得到一個返回串 hr = pIX->FxStringOut(&szOut) ; assert(SUCCEEDED(hr)) ; // Display returned string. ostrstream sout ; sout << "FxStringOut returned a string: " << szOut << ends ; trace(sout.str()) ; // 釋放內存 ::CoTaskMemFree(szOut) ;

定義IY接口

// Interface IY// 在客戶和數組之間傳遞數組的接口的IDL描述[ object, uuid(32bb8324-b41b-11cf-a6bb-0080c7b2d682), helpstring("IY Interface"), pointer_default(unique)]interface IY : IUnknown{ HRESULT FyCount([out] long* sizeArray) ; //size_is告訴MIDL數組中元素個數將被保存在sizeIn中 HRESULT FyArrayIn([in] long sizeIn, [in, size_is(sizeIn)] long arrayIn[]) ; //函數將用內部數組填充arrayOut,將psizeInOut設為實際填充到數組中 //元素個數 HRESULT FyArrayOut([out, in] long* psizeInOut, [out, size_is(*psizeInOut)] long arrayOut[]) ;} ;

使用IY接口

// Send an array to the component. long arrayIn[] = { 22, 44, 206, 76, 300, 500 } ; long sizeIn = sizeof(arrayIn) / sizeof(arrayIn[0]) ; hr = pIY->FyArrayIn(sizeIn, arrayIn) ; assert(SUCCEEDED(hr)) ; // Get the array back from the component. // Get the size of the array. long sizeOut = 0 ; hr = pIY->FyCount(&sizeOut) ; assert(SUCCEEDED(hr)) ; // Allocate the array. long* arrayOut = new long[sizeOut] ; // Get the array. hr = pIY->FyArrayOut(&sizeOut, arrayOut) ; assert(SUCCEEDED(hr)) ; // Display the array returned from the function. ostrstream sout ; sout << "FyArray returned " << sizeOut << " elements: " ; for (int i = 0 ; i < sizeOut ; i++) { sout << " " << arrayOut[i] ; } sout << "." << ends ; trace(sout.str()) ; // Cleanup trace("Release IY.") ; delete [] arrayOut ;

定義接口IZ

// Structure for interface IZ// IDL中也可定義C和C++風格的結構,并可用它們作為函數的參數typedef struct { double x ; double y ; double z ;} Point3d ;// Interface IZ[ object, uuid(32bb8325-b41b-11cf-a6bb-0080c7b2d682), helpstring("IZ Interface"), pointer_default(unique)]interface IZ : IUnknown{ HRESULT FzStructIn([in] Point3d pt) ; HRESULT FzStructOut([out] Point3d* pt) ;} ;

編寫好IDL文件后,可用MIDL編譯器進行編譯,生成相應文件,比如可以將server.idl生成iface.h、guids.c、proxy.c、dlldata.c、server.tlb

通過makefile文件,應同時生成server.dll和server.exe

代理DLL

MIDL編譯器

這里寫圖片描述

代理DLL的建立

編譯和鏈接MIDL生成的頭文件后,MAIDL將為組件生成相應的代理和殘根的代碼,還需寫一個DEF文件生成DLL

LIBRARY Proxy.dllDESCRIPTION 'Proxy/Stub DLL'EXPORTS DllGetClassObject @1 PRIVATE DllCanUnloadNow @2 PRIVATE GetProxyDllInfo @3 PRIVATE DllRegisterServer @4 PRIVATE DllUnregisterServer @5 PRIVATE

代理/殘根的登記

生成代理DLL后將DLL登記,查看: 運行regedit.exe 這里寫圖片描述

本地服務器的實現

EXE提供組件不同于DLL,需對CUnkown和CFactory進行相應修改,但組件不需要變化。

示例程序運行

先點擊server.exe,然后點擊client.exe,選擇2 這里寫圖片描述

client.cpp部分代碼:

int main(){ cout << "To which server do you want to connect?/r/n" << "1) In-proc Server/r/n" << "2) Local Server/r/n:" ; int i = 0 ; cin >> i ; D
Word clsctx ; if (i == 1) { clsctx = CLSCTX_INPROC_SERVER ; //連接到進程中服務器 trace("Attempt to create in-proc component.") ; } else { clsctx = CLSCTX_LOCAL_SERVER ; //連接到進程外服務器 trace("Attempt to create local component.") ; } ... ...}

可以看到server.exe輸出: 這里寫圖片描述

去掉入口點函數

EXE無法輸出函數,進程中服務器依賴如下輸出函數: DllGetClassObject DllRegisterServer DllUnregisterServer DllCanUnloadNow

EXE可自己對生命期進行控制,不需要DllCanUnloadNow 。 EXE可通過命令含參數RegServer、UnRegServer完成自登記,不需要DllRegisterServer、DllUnregisterServer。 DllGetClassObject的替換會比較麻煩一些。

類廠的啟動

CoCreateInstance調用CoGetClassObject,CoGetClassObject調用DllGetClassObject,DllGetClassObject返回一個IClassFactory指針。但exe不輸出DllGetClassObject,需要另想辦法獲得IClassFactory指針。

COM解決的辦法是維護一個被登記的類廠的內部表格,根據客戶請求的CLISD得到相應的類廠。若找不到相應類廠,COM將在注冊表中查找并啟動相應的EXE,此EXE可調用COM函數CoRegisterClassObject完成類廠的登記,以便COM能找到它們。

可對CFactory增加一個新的 靜態成員函數StartFactories,對每個組件調用CoRegisterClassObect。

CFactory.cpp

//// Start factories//BOOL CFactory::StartFactories(){ CFactoryData* pStart = &g_FactoryDataArray[0] ; const CFactoryData* pEnd = &g_FactoryDataArray[g_cFactoryDataEntries - 1] ; for(CFactoryData* pData = pStart ; pData <= pEnd ; pData++) { // 初始化類廠指針和cookie. //以下兩個成員變量為CFactory新增加的 //保存與m_pCLSID相應的類ID的運行時類廠 pData->m_pIClassFactory = NULL ; //保存此類廠的cookie pData->m_dwRegister = NULL ; // 創建類廠 IClassFactory* pIFactory = new CFactory(pData) ; // 注冊類廠 //對于第2、3個參數,若EXE的單個實例只能提供單個組件,應該為 //CLSCTX_LOCAL_SERVER,REGCLS_SINGLEUSER //否則,可為CLSCTX_LOCAL_SERVER,REGCLS_MULTI_SEPARATE //為了將一個EXE服務器作為它自己的進程中服務器登記,可將 //CLSCTX_LOCAL_SERVER 和 CLSTX_INPROC_SERVER組合使用 //如果使用REGCLS_MULTIPLEUSE,出現 CLSCTX_LOCAL_SERVER時自動 //設置CLSTX_INPROC_SERVER DWORD dwRegister ; HRESULT hr = ::CoRegisterClassObject( *pData->m_pCLSID, static_cast<IUnknown*>(pIFactory), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, // REGCLS_MULTI_SEPARATE, //@Multi &dwRegister) ; //傳回一個cookie,注銷時用到 if (FAILED(hr)) { pIFactory->Release() ; return FALSE ; } // 設置數據 pData->m_pIClassFactory = pIFactory ; pData->m_dwRegister = dwRegister ; } return TRUE ;}

類廠的釋放

服務器被關閉時,必須刪除相應類廠。CFactory成員函數StopFactories將為EXE所支持的所有類廠調用CoRevokeClassObeject。

CFactory.cpp

//// Stop factories// 當服務器被關閉時,為所有EXE所支持的所有類廠調用CoRevokeClassObject//void CFactory::StopFactories(){ CFactoryData* pStart = &g_FactoryDataArray[0] ; const CFactoryData* pEnd = &g_FactoryDataArray[g_cFactoryDataEntries - 1] ; for (CFactoryData* pData = pStart ; pData <= pEnd ; pData++) { // 得到 magic cookie 并停止類廠 // 將從CoRegisterClassObject得到的cookie傳給CoRevokeClassObject DWORD dwRegister = pData->m_dwRegister ; if (dwRegister != 0) { ::CoRevokeClassObject(dwRegister) ; } // 釋放類廠 IClassFactory* pIFactory = pData->m_pIClassFactory ; if (pIFactory != NULL) { pIFactory->Release() ; } }}

對LockServet的修改

// LockServer// 保證客戶在創建組件時,需要的服務器在內存中HRESULT __stdcall CFactory::LockServer(BOOL bLock) { if (bLock) { ::InterlockedIncrement(&s_cServerLocks) ; } else { ::InterlockedDecrement(&s_cServerLocks) ; } // If this is an out-of-proc server, check to see // whether we should shut down. // dll無法控制自己的生命期,因為裝載和卸載是在另外一個exe中的, // 但exe可以 CloseExe() ; //@local return S_OK ;}//// Destructor//CUnknown::~CUnknown(){ ::InterlockedDecrement(&s_cActiveComponents) ; // If this is an EXE server, shut it down. // 向程序的消息循環發散WM_QUIT消息 CFactory::CloseExe() ;}// 標示出同本地服務器相關的部分(當定義此宏時)// 或同進程中服務器相關的部分(未定義此宏時)#ifdef _OUTPROC_SERVER_ // // Out-of-process server support // static BOOL StartFactories() ; static void StopFactories() ; static DWORD s_dwThreadID ; // Shut down the application. // 將給應用程序的消息循環發送一條WM_QUIT消息 static void CloseExe() { if (CanUnloadNow() == S_OK) { ::PostThreadMessage(s_dwThreadID, WM_QUIT, 0, 0) ; } }#else // CloseExe doesn't do anything if we are in process. static void CloseExe() { /*Empty*/ } #endif

消息循環:

為不致使EXE退出,應加上一個消息循環,可以是Windows消息循環,在名為outproc.cpp中,只有在建立進程外服務器是需要被編譯和連接。

遠程訪問能力

運行DCOMCNFG.EXE可使本地服務器變成一個遠程服務器。

這里寫圖片描述 這里寫圖片描述

在程序中訪問某個遠程服務器

需要用CoCreateInstanceEX體會CoCreateInstance

這里寫圖片描述

MULTI_QI:

跨網絡時,函數的調用的開銷比較大,為減少QueryInterface調用的影響,DCOM(分布式COM)建立MULTI_QI的新結構,同時查詢多個接口時,降低開銷。

CoCreateInstanceEX退出時,若能查詢到MULTI_QI中的所有接口,返回S_OK;部分接口,CO_S_NOTALLNTERFACES;無法查詢任何接口,E_NO_INTERFACE。

MULTI_QI聲明如下 這里寫圖片描述

IMultiQI的實現由組件的遠程代理“免費”提供。

還需要確定DCOM是否可用,這里不再列出,詳見書中內容。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 教育| 同德县| 湘阴县| 阿城市| 盐城市| 和静县| 兰西县| 沁阳市| 修文县| 家居| 贞丰县| 南漳县| 通海县| 渝中区| 珠海市| 亳州市| 赤城县| 曲靖市| 宣恩县| SHOW| 桃江县| 历史| 遵义市| 岐山县| 平陆县| 朔州市| 孝义市| 清原| 凉城县| 清苑县| 唐河县| 定边县| 英吉沙县| 肃宁县| 文山县| 永和县| 邢台县| 长沙市| 织金县| 龙川县| 故城县|