Com组件编程多线程访问(推荐方法3)

转载 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;

}

 
原文地址:https://www.cnblogs.com/profession/p/12149396.html