转载 https://blog.csdn.net/xbgprogrammer/article/details/7353921
1. 创建Com对象MathObj,线程模型为单元,没有注册PS dll(即不支持列集散集)。客户端为控制台程序,有一全局接口指针,在主线程中创建单元套间,并创建Com对象,而后在另一线程中调用此对象,工作正常,以下为示例代码(但必须说明的是,此种调用方法不符合Com规范)
#include "stdafx.h" #include <iostream> #include <Windows.h> #include <atlbase.h> #include "../MathSvrLib/MathSvrLib.h" #include "../MathSvrLib/MathSvrLib_i.c" using namespace std; CComPtr<IMathObj> pMathObj; unsigned __stdcall ThreadFun(void *) { HRESULT hr; LONG a = 20; LONG b = 34; LONG sum; hr = pMathObj->Add(a,b,&sum); cout<<a<<"+"<<b<<"="<<sum<<endl; return 0; } int _tmain(int argc, _TCHAR* argv[]) { CoInitializeEx(NULL,COINIT_MULTITHREADED); HRESULT hr; hr = pMathObj.CoCreateInstance(CLSID_MathObj); LONG a = 10; LONG b = 34; LONG sum; hr = pMathObj->Add(a,b,&sum); cout<<a<<"+"<<b<<"="<<sum<<endl; //创建另外线程调用接口原始指针 HANDLE hThread = (HANDLE)_beginthreadex(NULL,NULL,ThreadFun,NULL,NULL,NULL); WaitForSingleObject(hThread,INFINITE); pMathObj.Release(); CoUninitialize(); return 0; }
2. 创建Com对象MathObj,线程模型为单元,注册PS dll(若不注册PS dll,IGlobalInterfaceTable.GetInterfaceFromGlobal返回E_UNEXPECTED)。客户端为控制台程序,含有消息循环处理(若没有消息循环处理,IGlobalInterfaceTable.GetInterfaceFromGlobal及通过散集指针调用Com方法会阻塞,因为以上调用会向创建此Com对象的线程发送消息),有一接口指针,在主线程中创建单元套间,创建Com对象,并且在全局接口表对象注册接口,而后在另一线程中通过全局接口表对象调用此对象,工作正常,以下为示例代码
// Client.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> #include <Windows.h> #include <atlbase.h> #include "../MathSvrLib/MathSvrLib.h" #include "../MathSvrLib/MathSvrLib_i.c" using namespace std; CComPtr<IGlobalInterfaceTable> g_pGIT; DWORD g_dwCookie; CComPtr<IMathObj> pMathObj; unsigned __stdcall ThreadFun(void *) { //这是必须的,否则g_pGIT->GetInterfaceFromGlobal会提示 //尚未调用CoInitialize CoInitialize(NULL); HRESULT hr; LONG a = 20; LONG b = 34; LONG sum; CComPtr<IMathObj> pCalPtr; //因为g_pGIT->GetInterfaceFromGlobal会向创建此Com的单元套间发送消息,所以要求 //创建此Com对象的单元套间有消息处理,若没有,则GetInterfaceFromGlobal阻塞 //若Com接口不支持列集散集,则hr = E_UNEXPECTED hr = g_pGIT->GetInterfaceFromGlobal(g_dwCookie,IID_IMathObj,(void**)&pCalPtr); hr = pCalPtr->Add(a,b,&sum); cout<<a<<"+"<<b<<"="<<sum<<endl; CoUninitialize(); return 0; } int _tmain(int argc, _TCHAR* argv[]) { CoInitializeEx(NULL,COINIT_APARTMENTTHREADED); HRESULT hr; hr = pMathObj.CoCreateInstance(CLSID_MathObj); // 创建全局接口表对象 hr = g_pGIT.CoCreateInstance(CLSID_StdGlobalInterfaceTable,NULL,CLSCTX_INPROC_SERVER); // 注册接口 hr = g_pGIT->RegisterInterfaceInGlobal(pMathObj,IID_IMathObj,&g_dwCookie); LONG a = 10; LONG b = 34; LONG sum; hr = pMathObj->Add(a,b,&sum); cout<<a<<"+"<<b<<"="<<sum<<endl; //创建另外线程调用接口原始指针 HANDLE hThread = (HANDLE)_beginthreadex(NULL,NULL,ThreadFun,NULL,NULL,NULL); //消息处理 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } pMathObj.Release(); CoUninitialize(); return 0; }
3. 创建Com对象MathObj,线程模型为单元,注册PS dll(因为要跨套间创建Com对象)。客户端为控制台程序,在主线程中创建多线程套间,并创建Com对象(请注意,此时已得到Com对象的代理指针,而非原始指针),发现进程内多了几个线程(可以判断此时Com设施在背后创建了线程支持单元Com对象调用),而调用此对象,工作正常,并可调试发现方法的调用非主线程,而是Com设施创建的一个线程。若要在另外的线程调用此Com对象,还应该通过列集散集创建Com对象时得到的指针去调用,否则方法调用会返回(hr = 0x8001010e
应用程序调用一个已为另一线程整理的接口。 )。若以下为示例代码
// Client.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> #include <Windows.h> #include <atlbase.h> #include "../MathSvrLib/MathSvrLib.h" #include "../MathSvrLib/MathSvrLib_i.c" using namespace std; CComPtr<IGlobalInterfaceTable> g_pGIT; DWORD g_dwCookie; CComPtr<IMathObj> pMathObj; unsigned __stdcall ThreadFun(void *) { //这是必须的,否则g_pGIT->GetInterfaceFromGlobal会提示 //尚未调用CoInitialize CoInitialize(NULL); HRESULT hr; LONG a = 20; LONG b = 34; LONG sum; CComPtr<IMathObj> pCalPtr; //因为g_pGIT->GetInterfaceFromGlobal会向创建此Com的单元套间发送消息,所以要求 //创建此Com对象的单元套间有消息处理,若没有,则GetInterfaceFromGlobal阻塞 //若Com接口不支持列集散集,则hr = E_UNEXPECTED hr = g_pGIT->GetInterfaceFromGlobal(g_dwCookie,IID_IMathObj,(void**)&pCalPtr); //Error:以下语句会返回hr = 0x8001010e 应用程序调用一个已为另一线程整理的接口。 //hr = pMathObj->Add(a,b,&sum); //正确的方法 hr = pCalPtr->Add(a,b,&sum); cout<<a<<"+"<<b<<"="<<sum<<endl; CoUninitialize(); return 0; } int _tmain(int argc, _TCHAR* argv[]) { CoInitializeEx(NULL,COINIT_MULTITHREADED); HRESULT hr; hr = pMathObj.CoCreateInstance(CLSID_MathObj); // 创建全局接口表对象 hr = g_pGIT.CoCreateInstance(CLSID_StdGlobalInterfaceTable,NULL,CLSCTX_INPROC_SERVER); // 注册接口 hr = g_pGIT->RegisterInterfaceInGlobal(pMathObj,IID_IMathObj,&g_dwCookie); LONG a = 10; LONG b = 34; LONG sum; hr = pMathObj->Add(a,b,&sum); cout<<a<<"+"<<b<<"="<<sum<<endl; //创建另外线程调用接口原始指针 HANDLE hThread = (HANDLE)_beginthreadex(NULL,NULL,ThreadFun,NULL,NULL,NULL); WaitForSingleObject(hThread,INFINITE); pMathObj.Release(); CoUninitialize(); return 0; }