VC调用COM组件实例

项目需求与文件清单

项目需求:使用通信接口模块从免疫助手客户端获取接种登记信息的相关信息

  1. EpiDBServiceV4.dll

  2. EpiDBServiceV4.tlb

  3. 金苗免疫助手接种登记信息获取接口.doc

操作流程与COM接口

操作流程简述:

1 调用接口中ConnectDB函数。连接数据库。

2 连接数据库成功后,调用接口中 QueryBatchShotInfo 函数。获取受种者接种信息。

3 获取信息后,调用接口中Disconnect函数。断开数据库连接。

模块CLSID参数:

Class ID (CLSID):EpiDBServiceV4.TEpiDBServiceV4

三个接口:

  1. 连接数据库:ConnectDB(ADatabaseFile);

    输入参数ADatabaseFile为数据库连接字符串。示例:127.0.0.1:E:\MyData\EpiDB.fdb

  2. 获取受种者接种信息:QueryBatchShotInfo(AUpdateID, ATokenID, AResult);

    输入参数:AUpdateID, 前次调用时数据包中提供的最大UpdateID值。第一次调用时,值为-1。

              ATokenID, 8C92806D-604A-4332-91B3-1351535D8E83

    输出参数:AResult,数据包格式见 3.1。

  3. 断开数据库连接:Disconnect();

COM组件注册

通信接口模块EpiDBServiceV4.DLL 使用 COM 接口,使用 regsvr32 命令注册。

注册指令:

regsvr32 D:\Lnhoo.Device.Driver\01_build\COMClient\EpiDBServiceV4.dll

注销指令:

regsvr32 EpiDBServiceV4.dll /u

.NET平台注册指令:

cd C:\Windows\Microsoft.NET\Framework\v4.0.30319\
C:
regasm E:\user\desktop\现场文档\客户端服务接口\CSCOM\debug\EpiDBServiceV4.dll

注销指令:

regasm E:\user\desktop\现场文档\客户端服务接口\CSCOM\debug\EpiDBServiceV4.dll  /u

启动FB数据库

启动FB: D:\Lnhoo.Device.Driver\01_build\COMClient\firebird\bin\EpiJMLoader.exe

预备动作

在工程中导入组件或类型库:
#include "stdafx.h"
#include "COM_CCOMPTR.h"
#include <stdlib.h>
#include "objbase.h"
#include "atlbase.h"

#import "EpiDBServiceV4.dll" named_guids raw_interfaces_only
using namespace  EpiDBServiceV4;
//或: #import "组件所在目录/myCom.dll" no_namespace

方法1

CoInitialize(NULL);
CLSID clsid;
CLSIDFromProgID(OLESTR("EpiDBServiceV4.TEpiDBServiceV4"),&clsid);
CComPtr<IEpiDBServiceV4> pCComPtr;//智能指针
pCComPtr.CoCreateInstance(clsid);
pCComPtr->ConnectDB("");
pCComPtr.Release();//小心哦!!请看最后的“注意”
CoUninitialize();

COM中的智能指针实际上是重载了->的类,目的是为了简化引用记数,几不需要程序员显示的调用AddRef()和Release(),但是为什么我们在Method 1中pGetRes.Release(),问题在与,我们的智能指针pGetRes生命周期的结束是在CoUninitialize()之后,CoInitialize所开的套间在CoUninitialize()后已经被关闭,而pGetRes此时发生析构,导致了程序的崩溃,解决这个问题的另一个方法是

CoInitialize(NULL);
CLSID clsid;
CLSIDFromProgID(OLESTR("myCom.GetRes"),&clsid);
{
	CComPtr<IGetRes> pGetRes;//智能指针
	pGetRes.CoCreateInstance(clsid);
	pGetRes->Hello();
}
CoUninitialize();

方法2

CoInitialize(NULL);
CLSID clsid;
HRESULT hr=CLSIDFromProgID(OLESTR("EpiDBServiceV4.TEpiDBServiceV4"),&clsid);
IEpiDBServiceV4 *ptr;
hr=CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,
			  __uuidof(IEpiDBServiceV4),(LPVOID*)&ptr);
ptr->ConnectDB("");
CoUninitialize();

方法3

CoInitialize(NULL);
HRESULT hr;
CLSID clsid;
hr=CLSIDFromProgID(OLESTR("EpiDBServiceV4.TEpiDBServiceV4"),&clsid);
IEpiDBServiceV4* ptr;
//使用CoCreateClassObject创建一个组件(特别是mutilThreads)的多个对象的时候,效率更高.
IClassFactory* p_classfactory;
hr=CoGetClassObject(clsid,CLSCTX_INPROC_SERVER,
                  NULL,IID_IClassFactory, 
                  (LPVOID*)&p_classfactory);
p_classfactory->CreateInstance(NULL,__uuidof(IEpiDBServiceV4), (LPVOID*)&ptr);
ptr->ConnectDB("");
//IEpiDBServiceV4Ex* ptrEx;
//p_classfactory->CreateInstance(NULL,__uuidof(IEpiDBServiceV4Ex), (LPVOID*)&ptrEx);
//ptrEx->HelloEx();
CoUninitialize();

方法4

extern "C" const GUID __declspec(selectany) LIBID_EpiDBServiceV4 =
    {0xf6fc6833,0x1e8e,0x4b65,{0x92,0xf4,0x12,0x46,0x1d,0x91,0x4f,0xf9}};
extern "C" const GUID __declspec(selectany) IID_IEpiDBServiceV4 =
    {0x559cce40,0x22c5,0x4e98,{0xb1,0x3e,0x2f,0x82,0xf9,0x7c,0xcf,0x17}};
extern "C" const GUID __declspec(selectany) CLSID_TEpiDBServiceV4 =
    {0xe86c7e26,0x9590,0x4549,{0xa1,0xf1,0xc3,0x7b,0xc4,0x48,0xba,0xa0}};
 
typedef HRESULT (__stdcall * pfnFun1)(REFCLSID,REFIID,void**);
pfnFun1 fnFun1= NULL;
HINSTANCE hdllInst = LoadLibrary("EpiDBServiceV4.dll");
fnFun1=(pfnFun1)GetProcAddress(hdllInst,"DllGetClassObject");
if (fnFun1 != 0)
{
	IClassFactory* pcf = NULL;
	HRESULT hr=(fnFun1)(CLSID_TEpiDBServiceV4, IID_IClassFactory,(void**)&pcf);
	if (SUCCEEDED(hr) && (pcf != NULL))
	{
		IEpiDBServiceV4* pEpiDBServiceV4 = NULL;
		hr = pcf->CreateInstance(NULL, IID_IEpiDBServiceV4, (void**)&pEpiDBServiceV4);
		if (SUCCEEDED(hr)   && (pEpiDBServiceV4 != NULL))
		{
			pEpiDBServiceV4->ConnectDB("");
			pEpiDBServiceV4->Release();
		}
			pcf->Release();
	}
} 
FreeLibrary(hdllInst);

方法5

通过ClassWizard利用类型库生成包装类,不过前提是com组件的接口必须是派生自IDispatch,具体方法:调出添加类向导(.NET中),选择类型库中MFC类,打开,选择"文件",选择"EpiDBServiceV4.dll"或"EpiDBServiceV4.tlb",接下来会出来该EpiDBServiceV4.dll中的所有接口,选择你想生成的接口包装类后,向导会自动生成相应的.h文件.这样你就可以在你的MFC中像使用普通类那样使用组件了.(CreateDispatch("EpiDBServiceV4.TEpiDBServiceV4") 中的参数就是ProgID通过Clsid在注册表中可以查询的到:

CoInitialize(NULL);
IEpiDBServiceV4imp m_episerverimp;
if (m_episerverimp.CreateDispatch("EpiDBServiceV4.TEpiDBServiceV4") == 0)
{		   
 MessageBox("CreateDispatch失败!Exiting.\n","异常");
 return 1;
}

char szDBPath[MAX_PATH] = "127.0.0.1:D:\Lnhoo.Device.Driver\01_build\COMClient\EpiDB.FDB";
_bstr_t DBPath = _bstr_t(szDBPath);
m_episerverimp.ConnectDB(DBPath); 

VARIANT v;
V_VT(&v) = VT_UNKNOWN;
VariantInit(&v);
_bstr_t ATokenID = _bstr_t("8C92806D-604A-4332-91B3-1351535D8E83");	
char szATokenID [MAX_PATH] = {0};
strcpy(szATokenID,static_cast<char*>(ATokenID));  

char szAUpdateID[MAX_PATH] = "-1";	 
int nAUpdateID = atoi(szAUpdateID);

//调用COM组件
m_episerverimp.QueryBatchShotInfo(nAUpdateID, ATokenID,  &v);
_bstr_t bs(v);
//static_cast( (_bstr_t)v )
_bstr_t bstr = v; 
strcpy(szContent,static_cast<char*>(bstr)); 	//	strcpy(szResult,static_cast<char*>(bs));   
int iFileSize = strlen(szContent);
szContent[iFileSize] = 0x00;

m_episerverimp.ReleaseDispatch();
CoUninitialize();

以上就是COM的5中方法,当然具体怎么使用还是在于程序的环境,加以琢磨