1. 程式人生 > >程序外元件免註冊COM通訊的實現

程序外元件免註冊COM通訊的實現

最近在搞程序外元件通訊的東西,寫了個demo,免註冊的,一直沒調通,其實就是兩個問題卡了好幾天,也沒找到有用的資料,試了好幾天終於才解決,現簡單記錄下來,免得大家跟我走一樣的彎路。下面com端名稱簡寫為com.exe

遇到的問題:1. 呼叫 CoGetClassObject, 返回hr = 0x80040154 沒有註冊類  (原回:註冊版的未註冊,免註冊版的未執行)

                         2. IClassFactory::CreateInstance(),返回hr = 0x80029c4a 載入型別庫/DLL 時出錯。(兩個exe不在同一目錄或與manifest中指定的路徑不一致)

實現 :

1.需要新增*.exe.manifest檔案, Add進工程,Build. 

注: manifest中填寫的com端exe路徑必須是com exe 的真實存放路徑(預設在同級目錄下),可設定相對路徑(如Other\\ComExeDemo.exe),可嵌入到exe,不必放在exe同級目錄。

manifest檔案例:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <file name="Other\\com.exe"
hashalg="SHA1">
    <typelib tlbid="{F8311364-981D-4237-A33E-6738DCD1457B}" version="1.0" helpdir="" flags="HASDISKIMAGE"></typelib>
  </file>
  <comInterfaceExternalProxyStub name="IMyEvent" iid="{871965EB-D4BC-4131-9F97-2714105F9E76}" tlbid="{F8311364-981D-4237-A33E-6738DCD1457B}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
</assembly>
2. #import "*.tlb" ,目錄隨意,不必放在exe同級目錄。

3.客戶端與com端必須以相同許可權執行。如:同為管理員許可權或同為一般許可權,否則失敗。可在呼叫端使用CreatProcess(Other\\ComExeDemo.exe)保證是統一許可權。

4.客戶端獲取com端介面前必須保證com.exe 在執行狀態,這個執行的com.exe必須是manifest檔案中指定路下的(一般與呼叫端exe放在同級),且與呼叫端許可權統一
客戶端獲取介面程式碼例 :

//初始化
AfxOleInit();
或::CoInitialize(NULL);

//啟動com端程序(許可權統一哦)
//非必須-----------------------------------------
STARTUPINFO si;
PROCESS_INFORMATION pi;
::ZeroMemory( &si,sizeof(STARTUPINFO) );
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
BOOL b = ::CreateProcess(_T("E:\\CodeExercise\\vs2005\\COMDemo1Client\\debug\\11\\ComExeDemo.exe"),NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
//非必須-----------------------------------------

//獲取介面
CComPtr<IClassFactory> pFactory;
HRESULT hr = CoGetClassObject(CLSID_MyEvent, CLSCTX_LOCAL_SERVER, NULL, __uuidof(pFactory), reinterpret_cast<void**>(&pFactory));
IMyEventPtr pResult ;

hr = pFactory->CreateInstance(NULL, __uuidof(IMyEvent), reinterpret_cast<void**>(&pResult));

其實註冊版和免註冊版的區別就是一個用登錄檔,一個用manifest代替登錄檔,註冊版的在build時在登錄檔裡寫死了com.exe的絕對路徑(可修改rgs檔案使其不註冊),但免註冊版就得注意在編寫manifest檔案時保證com.exe的路徑問題了。許可權問題兩種版本都一樣,得統一!