ActiveX .idl与.odl的区别

本文深入探讨了ODL和IDL在COM框架中的应用,解释了两者之间的功能相似性和区别,并通过示例展示了如何在写法上进行区分。
.odl和.idl在com中的功能相同. 
前者是ActiveX中的 后者是ATL中. 

可在前者的文件中 用 #import "XXXXX.idl" 的方式包含后者. 反过来没有试过. 
2.
When using IDL, you must declare the interfaces that will generate the C++ source files outside of the library declaration. For the ODL, this step is not necessary. Other than a few minor language differences, the IDL and ODL are identical in terms of syntax and organization. 
3.
ODL是Microsoft对IDL的扩展
4.
odl ---对象描述语言 
idl ---接口描述语言 
其实是一个功能就是在写法上有些不同,eg: 
odl: 

uuid(3C591B20-1F13-101B-B826-00DD01103DE1), // LIBID_Lines. 
helpstring("Lines 1.0 Type Library"), 
lcid(0x09), 
version(1.0) 

library Lines 

importlib("stdole.tlb"); 


uuid(3C591B25-1F13-101B-B826-00DD01103DE1), // IID_Ipoint. 
helpstring("Point object."), 
oleautomation, 
dual 

interface IPoint : IDispatch 

[propget, helpstring("Returns and sets x coordinate.")] 
HRESULT x([out, retval] int* retval); 
[propput, helpstring("Returns and sets x coordinate.")] 
HRESULT x([in] int Value); 

[propget, helpstring("Returns and sets y coordinate.")] 
HRESULT y([out, retval] int* retval); 
[propput, helpstring("Returns and sets y coordinate.")] 
HRESULT y([in] int Value); 


uuid(3C591B21-1F13-101B-B826-00DD01103DE1), // CLSID_Lines. 
helpstring("Lines Class"), 
appobject 

coclass Lines 

[default] interface IPoint; 
interface IDispatch; 


idl: 


uuid(3C591B25-1F13-101B-B826-00DD01103DE1), // IID_Ipoint. 
helpstring("Point object."), 
oleautomation, 
dual 

interface IPoint : IDispatch 

[propget, helpstring("Returns and sets x coordinate.")] 
HRESULT x([out, retval] int* retval); 
[propput, helpstring("Returns and sets x coordinate.")] 
HRESULT x([in] int Value); 

[propget, helpstring("Returns and sets y coordinate.")] 
HRESULT y([out, retval] int* retval); 
[propput, helpstring("Returns and sets y coordinate.")] 
HRESULT y([in] int Value); 


uuid(3C591B20-1F13-101B-B826-00DD01103DE1), // LIBID_Lines. 
helpstring("Lines 1.0 Type Library"), 
lcid(0x09), 
version(1.0) 

library Lines 

importlib("stdole32.tlb"); 
importlib("stdole2.tlb"); 


uuid(3C591B21-1F13-101B-B826-00DD01103DE1), // CLSID_Lines. 
helpstring("Lines Class"), 
appobject 

coclass Lines 

[default] interface IPoint; 
interface IDispatch; 

}
使用MIDL在C++中定义接口以对应给定的C#接口,创建 `SetConfigCallback.idl` 文件的具体操作如下: ### 创建 `SetConfigCallback.idl` 文件 首先,创建一个新的文本文件,将其命名为 `SetConfigCallback.idl`。该文件用于定义COM接口,以下是文件的详细内容: ```idl import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(AF420672-D2F5-42A5-A7C0-88F3FF2100F2), dual, oleautomation ] interface ISetConfigCallback : IDispatch { [id(1), helpstring("SetConfig method")] HRESULT SetConfig([in] VARIANT_BOOL usePC); }; ``` - `import "oaidl.idl";` 和 `import "ocidl.idl";`:这两行代码导入了必要的类型定义,`oaidl.idl` 包含了OLE自动化的类型定义,`ocidl.idl` 包含了COM接口的类型定义。 - `[object]`:表示这是一个COM对象接口。 - `uuid(AF420672-D2F5-42A5-A7C0-88F3FF2100F2)`:指定接口的唯一标识符,必须C#接口中的 `Guid` 属性值一致。 - `dual`:表示该接口是双接口,既支持早期绑定(通过 `IDispatch`),也支持晚期绑定(直接调用接口方法)。 - `oleautomation`:表示该接口支持OLE自动化。 - `interface ISetConfigCallback : IDispatch`:定义了接口的名称 `ISetConfigCallback`,并继承自 `IDispatch` 接口。 - `[id(1), helpstring("SetConfig method")] HRESULT SetConfig([in] VARIANT_BOOL usePC);`:定义了接口的方法 `SetConfig`,`[id(1)]` 对应C#接口中的 `[DispId(1)]`,`[in]` 表示该参数是输入参数,`VARIANT_BOOL` 对应C#中的 `bool` 类型,`HRESULT` 是COM方法的返回类型。 ### 编译 `SetConfigCallback.idl` 文件 完成 `SetConfigCallback.idl` 文件的编写后,需要使用MIDL编译器将其编译成C++头文件和类型库文件。打开命令提示符,导航到 `SetConfigCallback.idl` 文件所在的目录,然后运行以下命令: ```sh midl SetConfigCallback.idl ``` 该命令将生成 `SetConfigCallback.h`、`SetConfigCallback_i.c` 和 `SetConfigCallback.tlb` 等文件。`SetConfigCallback.h` 文件包含了接口的C++定义,可以在C++代码中包含该头文件来使用接口。 ### 在C++中实现接口 在生成的 `SetConfigCallback.h` 文件基础上,可以在C++代码中实现 `ISetConfigCallback` 接口。以下是一个简单的实现示例: ```cpp #include <windows.h> #include "SetConfigCallback.h" class CSetConfigCallback : public ISetConfigCallback { private: ULONG m_refCount = 0; public: // IUnknown methods STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) { if (riid == IID_IUnknown || riid == IID_IDispatch || riid == __uuidof(ISetConfigCallback)) { *ppvObject = this; AddRef(); return S_OK; } return E_NOINTERFACE; } STDMETHODIMP_(ULONG) AddRef() { return ++m_refCount; } STDMETHODIMP_(ULONG) Release() { ULONG refCount = --m_refCount; if (refCount == 0) { delete this; } return refCount; } // IDispatch methods STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { *pctinfo = 0; return S_OK; } STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { *ppTInfo = nullptr; return E_NOTIMPL; } STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { return E_NOTIMPL; } STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) { if (dispIdMember == 1) { if (pDispParams->cArgs == 1 && pDispParams->rgvarg[0].vt == VT_BOOL) { VARIANT_BOOL usePC = pDispParams->rgvarg[0].boolVal; SetConfig(usePC); return S_OK; } } return DISP_E_MEMBERNOTFOUND; } // ISetConfigCallback method STDMETHODIMP SetConfig(VARIANT_BOOL usePC) { // 实现具体的逻辑 if (usePC == VARIANT_TRUE) { // 使用PC的逻辑 } else { // 不使用PC的逻辑 } return S_OK; } }; ``` ### 注册COM组件 将上述代码编译成动态链接库(DLL),然后使用 `regsvr32` 命令进行注册: ```sh regsvr32 SetConfigCallback.dll ``` ### 调用示例 ```cpp #include <windows.h> #include "SetConfigCallback.h" int main() { HRESULT hr = CoInitialize(NULL); if (SUCCEEDED(hr)) { ISetConfigCallback* pCallback = nullptr; // 这里需要实现创建实例的函数 // hr = CreateSetConfigCallback(&pCallback); if (SUCCEEDED(hr)) { VARIANT_BOOL usePC = VARIANT_TRUE; hr = pCallback->SetConfig(usePC); pCallback->Release(); } CoUninitialize(); } return 0; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值