zoukankan      html  css  js  c++  java
  • 获得COM组建接口的几种方法总结(不包含自动化)

    声明:下面的内容和代码均改自于杨老师写的“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;		// 智能指针 IUnknown
    CComQIPtr < IFun > spFun;		// 智能指针 IFun
    HRESULT 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 <atlbase.h>
    #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 ) );	// 使用 CLSID
    ASSERT( 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") );
    }
  • 相关阅读:
    linux
    linux
    linux
    linux
    linux
    linux
    linux
    idea插件篇之java内存分析工具(JProfiler)
    Jmeter(线程组+http请求+汇总报告)
    ZK客户端zkClient.bat
  • 原文地址:https://www.cnblogs.com/liuyuxi/p/1914845.html
Copyright © 2011-2022 走看看