博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
获得COM组建接口的几种方法总结(不包含自动化)
阅读量:6364 次
发布时间:2019-06-23

本文共 6088 字,大约阅读时间需要 20 分钟。

声明:下面的内容和代码均改自于杨老师写的“COM 组件设计与应用”。

先写出测试用组件的接口描述

[	object,	uuid(9C0330E2-D53F-43E3-B899-97B94BF76B64),	helpstring("IFun 范例接口"),	pointer_default(unique)]interface IFun : IUnknown{	[helpstring("Add 加法")] HRESULT Add([in] LONG n1, [in] LONG n2, [out,retval] LONG* pVal);};[	uuid(A7F9A697-9F48-41AE-A697-3A9BE77582CC),	version(1.0),	helpstring("Simple 1.0 类型库")]library Simple2Lib{	importlib("stdole2.tlb");	[		uuid(CA61C492-9AD3-469F-B75A-C021E03F21FB),		helpstring("Fun Class")	]	coclass Fun	{		[default] interface IFun;	};};

下面是GUID的声明

MIDL_DEFINE_GUID(IID, IID_IFun,0x9C0330E2,0xD53F,0x43E3,0xB8,0x99,0x97,0xB9,0x4B,0xF7,0x6B,0x64); MIDL_DEFINE_GUID(IID, LIBID_SimpleLib,0xA7F9A697,0x9F48,0x41AE,0xA6,0x97,0x3A,0x9B,0xE7,0x75,0x82,0xCC); MIDL_DEFINE_GUID(CLSID, CLSID_Fun,0xCA61C492,0x9AD3,0x469F,0xB7,0x5A,0xC0,0x21,0xE0,0x3F,0x21,0xFB);

 

现在开始进入正题:

一、使用COM声明的最基本的方法

#include "..\Simple\simple2.h"#include "..\Simple\Simple2_i.c"::CoInitialize( NULL );IUnknown* pUnk = NULL;IFun* pFun = NULL;HRESULT hr;try{	hr = ::CoCreateInstance(    //获得指向IUnknow接口的指针		CLSID_Fun,		NULL,		CLSCTX_INPROC_SERVER,  // 以进程内组件 DLL 方式加载		IID_IUnknown,			// 想要取得 IUnknown 接口指针		(LPVOID *) &pUnk);	if( FAILED( hr ) )	throw( _T("没注册吧?") );	hr = pUnk->QueryInterface(    // 从 IUnknown 得到其它接口指针		IID_IFun, // 想要取得 IFun 接口指针		(LPVOID *)&pFun );	if( FAILED( hr ) )	throw( _T("居然没有接口?") );	long nSum;	hr = pFun->Add( 1, 2, &nSum );	// IFun::Add()	if( SUCCEEDED( hr ) )	{		CString sMsg;		sMsg.Format( _T("1 + 2 = %d"), nSum );		AfxMessageBox( sMsg );	}	BSTR s1 = ::SysAllocString( L"Hello" );	BSTR s2 = ::SysAllocString( L" world" );	BSTR s3 = NULL;	hr = pFun->Cat( s1, s2, &s3 );	// IFun::Cat()	if( SUCCEEDED( hr ) )	{		CString sMsg( s3 );		AfxMessageBox( sMsg );	}			// IFun::Cat() 最后一个参数是 [out] 方向属性,因此需要调用者释放	if( s3 ) ::SysFreeString( s3 );}catch( LPCTSTR lpErr ){	AfxMessageBox( lpErr );}if( pUnk )	pUnk->Release();if( pFun )	pFun->Release();::CoUninitialize();

 

二.使用智能指针CComPtr<>

首先在程序初始化时调用AfxOleInit()

AfxOleInit();

使用时候

// COM 初始化 以 AfxOleInit() 函数调用,放在了 CUse2App::InitInstance() 中了。CComPtr < IUnknown > spUnk;		// 定义 IUnknown 智能指针CComPtr < IFun > spFun;			// 定义 IFun 智能指针HRESULT hr;try{	// 可以用 CLSID 启动组件,也可以用 ProgID	hr = spUnk.CoCreateInstance( CLSID_Fun );	if( FAILED( hr ) )	throw( _T("没有注册组件吧?") );	hr = spUnk.QueryInterface( &spFun );	if( FAILED( hr ) )	throw( _T("居然没有接口?") );	long nSum;	hr = spFun->Add( 1, 2, &nSum );	if( SUCCEEDED( hr ) )	{		CString sMsg;		sMsg.Format( _T("1 + 2 = %d"), nSum );		AfxMessageBox( sMsg );	}	CComBSTR s1( "Hello" ), s2( " world" ), s3;	hr = spFun->Cat( s1, s2, &s3 );	if( SUCCEEDED( hr ) )	{		CString sMsg( s3 );		AfxMessageBox( sMsg );	}}catch( LPCTSTR lpErr ){	AfxMessageBox( lpErr );}// 智能接口指针的最大好处是,我们不用负责释放

 

三.CComPtr<> 和 CComQIPtr<> 混合的使用方法

CComPtr < IUnknown > spUnk;		// 智能指针 IUnknownCComQIPtr < IFun > spFun;		// 智能指针 IFunHRESULT hr;try{	// 使用 ProgID 启动组件	hr = spUnk.CoCreateInstance( L"Simple2.fun.1" );	if( FAILED( hr ) )	throw( _T("没有注册吧?") );	spFun = spUnk;	// CComQIPtr 会帮我们自动调用 QueryInterface	if( !spFun )	throw( _T("居然没有接口?") );	// 成功与否可以判断 非NULL	long nSum;	hr = spFun->Add( 1, 2, &nSum );	if( SUCCEEDED( hr ) )	{		CString sMsg;		sMsg.Format( _T("1 + 2 = %d"), nSum );		AfxMessageBox( sMsg );	}	CComBSTR s1( "Hello" ), s2( " world" ), s3;	hr = spFun->Cat( s1, s2, &s3 );	if( SUCCEEDED( hr ) )	{		CString sMsg( s3 );		AfxMessageBox( sMsg );	}}catch( LPCTSTR lpErr ){	AfxMessageBox( lpErr );}

 

四. CComQIPtr<> 的使用方法

//不必获得IUnknow指针CComQIPtr < IFun, &IID_IFun > spFun;		// 定义 IFun 智能指针HRESULT hr;try{	hr = spFun.CoCreateInstance( L"Simple2.fun.1" );	if( FAILED( hr ) )	throw( _T("没有注册组件 或 没有找到接口") );	long nSum;	hr = spFun->Add( 1, 2, &nSum );	if( SUCCEEDED( hr ) )	{		CString sMsg;		sMsg.Format( _T("1 + 2 = %d"), nSum );		AfxMessageBox( sMsg );	}	CComBSTR s1( "Hello" ), s2( " world" ), s3;	hr = spFun->Cat( s1, s2, &s3 );	if( SUCCEEDED( hr ) )	{		CString sMsg( s3 );		AfxMessageBox( sMsg );	}}catch( LPCTSTR lpErr ){	AfxMessageBox( lpErr );}

 

五.智能指针的释放

#include 
#include "..\Simple2\simple2.h"#include "..\Simple2\Simple2_i.c"::CoInitialize( NULL ); // 如果在这里进行 COM 初始化,要注意智能指针的释放CComQIPtr < IFun, &IID_IFun > spFun;HRESULT hr = spFun.CoCreateInstance( CLSID_Fun );ASSERT( SUCCEEDED( hr ) );// 为了简单起见,不再使用 if 判断 HRESULT 了。IFun::Add() 也没有调用CComBSTR s1( "Hello" ), s2( " world" ), s3;hr = spFun->Cat( s1, s2, &s3 );ASSERT( SUCCEEDED( hr ) );CString sMsg( s3 );AfxMessageBox( sMsg );//spFun->Release(); // 大错特错!!!spFun.Release(); // 正解::CoUninitialize();

 

六.包装的智能指针 IxxxPtr、_bstr_t、_variant_t 的使用方法和异常处理

首先在程序初始化时使用AfxOleInit()

AfxOleInit();

在包含头文件中加入#import后编译,产生.tlh智能指针包装类。#import 使用了 no_namespace 表示不使用命名空间。智能指针的包装形式是:IxxxPtr,xxx 表示接口名

#ifdef _DEBUG	#import "..\Simple2\Debug\Simple2.tlb" no_namespace#else	#import "..\Simple2\Release\Simple2.tlb" no_namespace#endif

最后实现代码

IFunPtr spFun;HRESULT hr = spFun.CreateInstance( L"Simple2.fun.1" );	// 使用 ProgID//HRESULT hr = spFun.CreateInstance( __uuidof( Fun ) );	// 使用 CLSIDASSERT( SUCCEEDED( hr ) );try{	long nSum = spFun->Add( 1, 2 );	CString sMsg;	sMsg.Format( _T("1+2=%d"), nSum );	AfxMessageBox( sMsg );	_bstr_t sCat = spFun->Cat( _T("Hello"), _T(" world") );	AfxMessageBox( sCat );}catch( _com_error &e ){// 在这里可以取得详细的错误信息// 如果支持ISupportErrorInfo 接口//	e.Description();//	e.ErrorMessage();//	e.ErrorInfo();//	......	AfxMessageBox( _T("Error") );}

 

七.包装类中使用命名空间

首先在程序初始化时使用AfxOleInit()

AfxOleInit();

在包含头文件中加入#import后编译,这里不是用no_namespace标记

#ifdef _DEBUG	#import "..\Simple2\Debug\Simple2.dll"#else	#import "..\Simple2\Release\Simple2.dll"#endif

最后实现代码

// 命名空间叫 SimpleLib ,这个名称是组件 IDL 文件 Library 指定的try{	// 这次使用智能指针的构造函数启动组件,书写简单。	// 但也有缺点,因为如果失败的话,不知道错误原因	//Simple2Lib::IFunPtr spFun( L"Simple2.fun.1" );  ProgID 方式	Simple2Lib::IFunPtr spFun( __uuidof(Simple2Lib::Fun) );// CLSID 方式	long nSum = spFun->Add( 1, 2 );	CString sMsg;	sMsg.Format( _T("1+2=%d"), nSum );	AfxMessageBox( sMsg );	_bstr_t sCat = spFun->Cat( _T("Hello"), _T(" world") );	AfxMessageBox( sCat );}catch( _com_error &e ){	e;	AfxMessageBox( _T("Error") );}

转载于:https://www.cnblogs.com/liuyuxi/archive/2010/12/23/1914845.html

你可能感兴趣的文章
UIScrollView 大概是如何实现的,它是如何捕捉、响应手势的?
查看>>
asp.net MVC中实现调取web api
查看>>
keepalived实现服务高可用
查看>>
iOS模型以及使用
查看>>
NSString 去除空格
查看>>
swift - 网络请求数据处理 - 协议处理
查看>>
[BZOJ1588]营业额统计(Splay)
查看>>
[BZOJ 4869][SHOI&SXOI2017]相逢是问候(扩展欧拉定理+线段树)
查看>>
2017-08-13
查看>>
条件语句优化面面观
查看>>
集成友盟微信登录没有回调
查看>>
在CentOS Linux系统上,添加新的端口,启用ssh服务
查看>>
dbcp数据库连接池简单使用
查看>>
leetcode-38-Count and Say
查看>>
从零开始写一个node爬虫(上)—— 数据采集篇
查看>>
java调用远程服务器shell脚本
查看>>
贪吃蛇
查看>>
aardio单行的edit控件响应回车按键消息
查看>>
UVA 221 Urban Elevations
查看>>
[windows] gcc编译器
查看>>