很久没有涉及COM组件的内容了,这两天有个已有的产品需要更新涉及了COM的处理,小组人员对这个不是很熟悉,给小组人员交流了一下,把主要的内容记录一下,对于快速理解和上手提供一些指导,当然对于具体的工作原理和更多的内容参考具体的图书进行学习。
初步分三篇总结一下:
Ø C++中的COM组件
Ø C#中的COM组件
Ø C++实例和部署
基础和参考资料
All-In-One Code Framework http://cfx.codeplex.com/ 这个项目中有使用C# C++建立一个COM组件[DLL EXE]等的详细步骤。
COM本质论和 潘爱民编写的COM原理和应用 是非常出色的参考书籍
C++中的COM组件
以一个例子进行说明
COM组件
建立一个最简单的形式说明,这个组件接口名称为IMyKit ,方法就一个DoWork,参数一个传入,一个传出,具体如下
interface IMyKit : IDispatch{
[id(1)] HRESULT DoWork([in] BSTR text, [out] BSTR* msg);
};
[
uuid(87BF6309-28B6-40FA-AD26-5175D884D28E),
version(1.0),
]
library ComPlugLib
{
importlib("stdole2.tlb");
[
uuid(D7D0B2E8-1795-4E23-96BF-F07EC28FB44C)
]
coclass MyKit
{
[default] interface IMyKit;
};
};
STDMETHODIMP CMyKit::DoWork(BSTR text, BSTR* msg)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CString t = text;
AfxMessageBox(t);
CString r = _T("out text");
*msg = r.AllocSysString();
return S_OK;
}
C++使用以上组件的方法
首先引入定义
#ifdef _DEBUG
#import "../Debug/ComPlug.dll" no_namespace raw_interfaces_only
#else
#import "../Release/ComPlug.dll" no_namespace raw_interfaces_only
#endif
初始化
|
// 必须调用这个初始化 CoInitialize (NULL);
/*COM组件参数有:in out/ret几种,空间分配原则: in: 调用者负责申请和释放 out:COM组件负责申请,调用者负责释放 违反上述原则会出现内存泄漏 */
|
使用形式1
在纯WIN32项目用,其他偶尔用
|
HRESULT hr; ///纯Win32应用时的方法 IMyKit* pKit; hr = ::CoCreateInstance (__uuidof(MyKit),NULL,CLSCTX_INPROC_SERVER, __uuidof(IMyKit),(void**)&pKit); if(SUCCEEDED(hr)) { BSTR t = ::SysAllocString(L"hello"); BSTR r; pKit->DoWork(t, &r); MessageBoxW(NULL, r, NULL, MB_OK); ///字符串的转换支持,同类有一系列函数,空间分配在栈上,不要释放 USES_CONVERSION; LPSTR p = W2A(r); MessageBoxA(NULL, p, NULL, MB_OK); ::SysFreeString(t); ::SysFreeString(r); pKit->Release(); pKit = NULL; }
|
使用形式2
常用
|
//和MFC、ATL库结合起来使用,这个是最常用的情况 //还用一类comutil.h中_bstr_t 的封装 IMyKitPtr kit; hr = kit.CreateInstance(__uuidof(MyKit)); if(SUCCEEDED(hr)) { /*COM中的基本类型如VARIANT比较复杂,一般情况下不要直接使用 常用的几个变量 简化COM类型的Variant的调用 COleSafeArray COleVariant CComBSTR */ COleVariant vTrue=COleVariant((short)true), vFalse=COleVariant((short)false), vOpt=COleVariant((long)DISP_E_PARAMNOTFOUND, VT_ERROR), vNull=(COleVariant)(_T("")), vOne=COleVariant((short)1); CComBSTR text, msg; text = _T("in text"); kit->DoWork(text, &msg); CString str =msg; AfxMessageBox(str); kit = NULL; }
|
使用形式3
有些复杂,不太常用
|
///动态调用 CComPtr<IDispatch> pCF; CLSID clsid; const LPOLESTR guid = L"{D7D0B2E8-1795-4E23-96BF-F07EC28FB44C}"; CLSIDFromString(guid, &clsid); HRESULT result = CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IDispatch, (void**)&pCF); if (result== S_OK) { DISPPARAMS dispparams; memset(&dispparams, 0, sizeof dispparams); dispparams.cArgs = 2; dispparams.cNamedArgs = 0; VARIANTARG* pvarg = new VARIANTARG[dispparams.cArgs]; dispparams.rgvarg = pvarg; memset(pvarg, 0, sizeof(VARIANTARG) * dispparams.cArgs); CComBSTR t="dynamic", r; //和函数的声明相反的顺序 pvarg[0].vt = VT_BSTR|VT_BYREF; pvarg[0].pbstrVal = &r; pvarg[1].vt = VT_BSTR; pvarg[1].bstrVal = t; DISPID id = 1;//函数的标号 result = pCF->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, NULL, NULL); for(UINT i=0; i< dispparams.cArgs; i++) { VariantClear(&dispparams.rgvarg[i]); } delete []pvarg;
|
结束
|
CoUninitialize();
|