Com线程模型测试

 

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;
}


以上总计可推理至多线程Com对象

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值