多语言COM程序设计
外观
C与C++ MFC调用COM接口的示例
[编辑]预处理器指令#import
用于包含一个类型库的信息。类型库的内容被转化为C++的若干类,大部分描述为COM的interface。预处理器指令#import
创建两个头文件:
- 主头文件(.TLH):类似于MIDL编译器产生的文件,但还包含编译器产生的代码与数据。包含7个部分(除了头尾的boilerplate,其他部分被包含在IDL文件library语句指定的命名空间中):
- Heading boilerplate: 最开始的注释为呢子、#include <comdef.h>(定义了一些标准的宏), 其他初始化信息.
- Forward references 与 typedefs: 包括了结构的生命,typedef、枚举类型声明
- Smart pointer declarations: 模板类 _com_ptr_t 是智能指针实现,封装了interface指针,不再需要调用AddRef, Release, QueryInterface函数。此外,还隐藏了调用CoCreateInstance函数创建一个新的COM对象。在这部分,使用宏语句_COM_SMARTPTR_TYPEDEF创建COM interface的 _com_ptr_t特化模板类的类型定义(typedef)。
- Type library items(Typeinfo declarations): 主要包含类的定义,由ITypeLib:GetTypeInfo函数返回的类型项。枚举类型的定义。
- Optional old-style GUID definition: 包含命名的GUID常量的初始化。
#include
次要头文件- Footer boilerplate: #pragma pack(pop).
- 次要头文件(.TLI):包含编译器产生的成员函数的实现。主头文件包含(
#include
)次要头文件。
这2个头文件使用类型库文件的时间戳,预处理器在执行#import
时会检查头文件时间戳以避免不必要的操作。编译器会读和编译这2个头文件,如同主头文件被用#include
包含。
#include <comdef.h>
#import "D:\\MyPrograms\\C Sharp\\ClassLibrary1\\ClassLibrary1\\bin\\Debug\\ClassLibrary1.tlb"
using namespace ClassLibrary1;
//在这个COM类库中,定义了COM接口AddComInterface,包含了成员函数iadd
int main()
{
// 方法零:
int dresult;
CString strResult;
CoInitialize(NULL);//NULL 换成0 也可以
AddComInterfacePtr p_Add(__uuidof(AddComService));//AddComInterfacePtr是由#import预编译指令创建的*.tlh中定义的智能指针。参数是CoClass_ID
dresult = p_Add->iadd(1, 2);
//方法一:
CLSID clsid;
CLSIDFromProgID(OLESTR("ClassLibrary1.AddComInterface.1"), &clsid);
CComPtr<AddComInterface> pGetRes;//COM接口的智能指针
pGetRes.CoCreateInstance(clsid); //参数是CoClass_ID
int k = pGetRes->iadd(1, 2);
pGetRes.Release();//
//方法二:
//CLSID clsid;
CLSIDFromProgID(OLESTR("ClassLibrary1.AddComInterface.1"), &clsid);
AddComInterface* ptr;//COM接口的指针
HRESULT hr = ::CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, __uuidof(AddComInterface), (LPVOID*)&ptr);
k = ptr->iadd(1, 2);
//方法三:
//CLSID clsid;
CLSIDFromProgID(OLESTR("ClassLibrary1.AddComInterface.1"), &clsid);
//AddComInterface* ptr;//COM接口的指针
IClassFactory* p_classfactory;
hr = ::CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (LPVOID*)&p_classfactory);
p_classfactory->CreateInstance(NULL, __uuidof(AddComInterface), (LPVOID*)&ptr);
k = ptr->iadd(1, 2);
//方法四:
//直接从dll中得到DllGetClassObject,接着生成类对象及类实例(这方法可以使组件不用在注册表里注册)
typedef HRESULT(__stdcall * pfnHello)(REFCLSID, REFIID, void**);
pfnHello fnHello = NULL;
HINSTANCE hdllInst = LoadLibrary("D:\\MyPrograms\\C Sharp\\ClassLibrary1\\ClassLibrary1\\bin\\Debug\\ClassLibrary1.dll");
fnHello = (pfnHello)GetProcAddress(hdllInst, "DllGetClassObject");
if (fnHello != 0)
{
//CLSID clsid;
CLSIDFromProgID(OLESTR("ClassLibrary1.AddComInterface.1"), &clsid);
IClassFactory* pcf = NULL;
HRESULT hr = (fnHello)(clsid,IID_IClassFactory,(void**)&pcf);
if (SUCCEEDED(hr) && (pcf != NULL))
{
AddComInterface* pGetRes = NULL;
hr = pcf->CreateInstance(NULL, __uuidof(AddComInterface), (void**)&pGetRes);
if (SUCCEEDED(hr) && (pGetRes != NULL))
{
k = ptr->iadd(1, 2);
pGetRes->Release();
}
pcf->Release();
}
}
FreeLibrary(hdllInst);
//方法五:
//通过添加COM类型库的MFC包装类,前提是必须是MFC项目且COM组件的接口必须是派生自IDispatch,具体方法:
//Add-->Class...--->MFC--->MFC Class From TypeLib, 选择"我的模板库.tlb", 选择想生成的接口的包装类
//或者Project-->Class Wizard-->Add Class--->MFC Class From TypeLib--->Available type libraries / File
//选择需要调用的Interfaces,就会自动生成相应的.h文件.就可以在MFC应用程序中使用COM组件了.
//主要关注7个接口:_Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range、Font
//对上述的接口的.h文件,注释掉#import "C:\\Program Files (x86)\\Microsoft Office\\Office15\\EXCEL.EXE" no_namespace
//如果crange.h(335): error C2059: syntax error : ',' 那么把代码VARIANT DialogBox()改名如VARIANT DialogBox_(),再次编译通过
CAddComInterface getRest;
if (getRest.CreateDispatch("ClassLibrary1.AddComInterface.1") != 0)
{
k = getRest.iadd(1, 2);
getRest.ReleaseDispatch();
}
CoUninitialize();
return 0;
}