MIDL示例【转】

MIDL示例
2007-11-29 02:01

IDL是接口定义语言。MIDL是Microsoft的IDL编译器。在用IDL对接口和组件进行了描述后,可以用MIDL进行编译,生成相应的代理和存根DLL的C代码。


import “unknown.idl”
///Interface IX
[
       object,
       uuid(32bb8323-b41b-11cf-a6bb-0080c7b2d682),
       helpstring(“IX Interface”),
       pointer_default(unique)
]


interface IX:IUnknown
{

       HRESULT FxStringIn([in,string]wchar_t* szIn);
       HRESULT FxStringOut([out,string]wchar_t* szout);

}

import

用于将其他idl文件中的定义包含到当前文件中。

 

object:

      表示所定义的接口是一个COM接口,关键字object是Microsoft对于IDL的一种扩展;

uuid(32bb8323-b41b-11cf-a6bb-0080c7b2d682):

       表示相应的IID;

helpstring(“IX Interface”):

       将一个帮助串放到一个类型库中;

pointer_default(unique) :

       告诉MIDL编译器在没有为指针指定其他属性的时候如何处理该指针;可以当作引用、指针或空等,具体参见《COM技术内幕》第204页;

 

in关键字告诉MIDL需要将此参数值从客户传递给组件,存根代码不需要送回任何值。

out关键字告诉MIDL参数仅被用来从组件向客户传回有关的数据,

COM对字符串的标准约定是Unicode字符(即wchar_t);IDL文件可以定义C和C++风格的结构,并可用它们作为函数的参数。


当IDL文件中有一个library时,MIDL将生成一个类型库。L为接口生成相应的代理和存根的C代码。
为得到一个代理/存根DLL,需要编译和链接MIDL生成的C文件。
宏REGISTER_PROXY_DLL将完成代理/存根DLL在注册表中的注册操作。
有了IDL和MIDL我们就可以象调用进程内组件那样进行跨进程边界的函数调用,并对参数进行列集。

当IDL文件定义了library的时候,MIDL将会生成一个类型库,该类型库包括了在library block中每个元素的定义,以及在block外定义但在该bloack中引用元素的定义。

You can use a single IDL file to generate both the proxy stubs and header files for marshaling code, and a type library. You do this by defining an interface outside the library block and then referencing that interface from inside the library block.

 

 MIDL编译器将生成XX.H XX_.C XX_P.C DLLDATA.C几个文件,其作用分别为:
XX.H        一个同C和C++兼容的,包含IDL中所描述的所有接口声明的头文件;
XX_.C      一个定义有IDL文件中所用的所有GUID的C文件
XX_P.C      一个实现IDL文件中接口的代理及残根的C文件
DLLDATA.C 一个包含代理和残根的DLL的C文件
---------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
import "unknwn.idl"; 
[ object,uuid(9955EBD9-C24D-4b18-9D88-D6049ADDCBC8) ]
interface ICalculator : IUnknown {
HRESULT Add ( [in] long v1, [in] long v2, [out, retval] long* pVal );
HRESULT Subtract ( [in] long v1, [in] long v2, [out, retval] long* pVal );
HRESULT Multiply ( [in] long v1, [in] long v2, [out, retval] long* pVal );
HRESULT Divide ( [in] long v1, [in] long v2, [out, retval] long* pVal );
}
 
[ uuid(F1B9F274-5B16-4033-BECD-9C05BB6072AE) ]
library CalcualtorLib
{
[ uuid(0A6C37B3-3577-48a7-9485-5F10ED190ECF) ]
coclass CCalculator
{
   interface ICalculator;
}
};
笔者在编译上面的IDL文件时,产生下列错误:
D:/Work/Math/Calculator.idl(3) : error MIDL2311 : statements outside library block are illegal in mktyplib compatability mode : [ Interface 'ICalculator'  ]
D:/Work/Math/Calculator.idl(3) : error MIDL2096 : duplicated attribute : [uuid] [ Interface 'ICalculator' ]
Error executing midl.exe.
察看MSDN,发现原因是:
      
           需要在project中将IDL文件的MIDL/mktyplib203选项去掉. 
      

 

【示例2】

所有数据、方法、接口、类和库的特性都由属性信息来描述。属性信息中由括号括起来,作为它们描述的对象的前缀。

[in] : 告诉MIDL编译器生成代码时,只是把从客户到对象的数据列集,没必要把同样的数据列集送回给客户

[out] : 让一段数据从对象返回到客户。
-------------------------------------------------------------------------
IUnknown接口定义
import "unknwn.idl";
[ local,object
   uuid(FAEAE6B7-67BE-42a4-A318-3256781E945A),
   pointer_default(unique)
]
interface IUnknown
{
    typedef(unique) IUnknown *LPUNKNOWN

    cpp_quote("/////////////////////////////////////////////")
    cpp_quote("//IID_IUnknown和其他所有的系统IID都是由UUID.LIB提供的")
    cpp_quote("//把这个函数库与你的代理、客户和服务链接起来")
    cpp_quote("/////////////////////////////////////////////")

    HRESULT QueryInterface( [in] REFIID iid,
                            [out,iid_is(riid)] void **ppObject );

    ULONG AddRef();
    ULONG Release();
}
-----------------------------------------------------------------------------
[object] : 指定接口是一个com接口。如果遗漏这个属性信息,那IOcr接口只是一个简单的MS RPC接口;如果没有这个属性信息,所生成的列集代码将与COM函数库(运行时)提供的标准列集代码不兼容。

[UUID] : 这是IOcr接口静态的和唯一的IID,它是一个在时间上和空间上独一无二的机器生成数字。

[local] : 告诉MIDL编译器,不要生成接口代理和存根。

[pointer_default()] : 设定了所有还没有显示限定的嵌入式指针(embedded pointer)的默认指针属性信息。嵌入式指针(embedded pointer)包括结构体(structrue)、联合体(union)、数组(array)的成员指针.

   unique属性信息:1)[ref]指针是引用指针(reference pointer),不能为空。
                            2)[unique]指针是简单指针(simple pointer),可以为空。但是代理不提供对重复指针探测的支持。例如,若ptr1/ptr2都

                               指向同一个数据,那个数据的两份相同的副本会被送往远程对象。
                            3)[ptr]指针是完全指针(full pointer)。若ptr1/ptr2都指向同一个数据,只有一个副本会被送往远程对象。

cpp_quote:指导MIDL编译器将限定了的字符串转换成生成的头文件。具体来说,这四行会在MIDL编译器生成的头文件中做出C++的注释。

[iid_is()] : 这是一个指针属性,它与[ptr][ref][unique]相似,只适用于指针。iid_is(riid)属性列集器关心,实际上,存根需要准确地知道正在调度的接口指针(riid,某种IID)

[size_is()] : 显示地告诉列集器,指针实际指向一些字节的块。列集器根据这个块的大小分配内存。

[string] : 提示列集器:修饰的本参数是一个字符串,是以null终止的。

### 如何在MFC目中添加或配置MIDL支持 要在MFC目中集成或使用MIDLMicrosoft Interface Definition Language)编译器,需要按照特定的步骤来完成配置。以下是详细的说明: #### 1. 启用MIDL编译器的支持 为了使MIDL编译器能够处理`.idl`文件并生成相应的接口定义和存根代码,在目的属性设置中启用MIDL是非常重要的。 - 打开Visual Studio中的MFC目。 - 右键单击目名称,选择 **“属性”** 菜单。 - 导航至 **“配置属性 -> 中间语言 (IDL) 文件”** 或者直接搜索 `MIDL` 关键字[^4]。 - 将 **“中间语言 (IDL)”** 设置为 **“是 (/IDl)”**,这表示启用了MIDL编译器的功能。 #### 2. 添加 `.idl` 文件到目中 如果尚未创建任何`.idl`文件,则需手动编写或者通过其他方式获取这些文件,并将其加入当前目结构下。 - 在解决方案资源管理器窗口右键点击 **“源文件”** 或 **“头文件”** 文件夹。 - 选择 **“添加现有...”** 并浏览找到目标`.idl`文件路径后导入进来。 一旦成功加载了`.idl`文件,那么之前提到过的关于激活MIDL编译过程就会自动触发作用于新引入的内容上。 #### 3. 配置附加依赖关系以及库目录 由于某些情况下的`.idl`文件可能还会涉及到额外所需的静态链接库(`.lib`)或者其他动态链接库(.dll),因此还需要进一步调整如下几个方面的参数设定: ##### a). 修改附加依赖(Additional Dependencies) 进入 **“配置属性->链接器(Linker)->输入(Input)”**, 然后编辑框内追加必要的`.lib`文件名列表, 这样做类似于写入预处理器指令的形式:#pragma comment(lib,"abc.lib") [^2]. 例如对于COM组件开发而言经常需要用到Rpcrt4.lib这样的通用运行时支持模块. ##### b). 更新包含目录(Includes Directories) 和 库目录(Library Directories) 同样地也需要确认是否已经正确指定了所有涉及的相关头文件位置以及对应的二进制档案所在磁盘分区地址信息. 可以通过访问 **“配置属性->VC++ 目录”** 来分别指定上述两类不同的物理存储区域范围.[^3] 最后记得保存所做的全部更改操作以便后续构建流程能顺利执行下去而不会因为缺少关键要素而出错提示. ```python # 示例 Python 伪代码展示如何调用 COM 对象 import win32com.client excel = win32com.client.Dispatch("Excel.Application") workbook = excel.Workbooks.Add() worksheet = workbook.Sheets["Sheet1"] cell_value = worksheet.Cells(1, 1).Value print(cell_value) excel.Quit() # 结束 Excel 实例 ``` 以上脚本片段展示了利用Python绑定Windows API的方式实例化了一个新的 Microsoft Office Excel 工作簿对象并通过其方法读取单元格数据再打印出来作为演示用途而已并非实际关联到了某个具体的 IDL 定义之上不过它确实反映了借助第三方工具包实现跨平台互操作性的可能性之一即基于标准协议规范所描述的服务端点暴露机制从而允许客户端程序轻松连接远程服务器上的功能特性集合体形成无缝衔接的整体架构体系设计思路方向指引参考价较高得深入研究探讨学习实践应用推广普及开来让更多开发者受益匪浅收获满满成果累累成就辉煌未来可期前景光明无限广阔天地大有作为也! ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值