Calling C and C++ from IDL (一)
怒了,最近写毕业论文用到了IDL与C++混合编程,刚开始使用IDL自带的命令Call_External调用C++编写的动态链接库DLL,一切都准备就绪,发现在IDL 与C++之间传递数据,特别是一些比较复杂的数据(数组、结构体)时出现了问题。就拿传递数组来说,需要在IDL中为数组开辟内存,但是数组的大小只有在调用完DLL之后才可以确定,之后各种百度,百度不行用谷歌,发现了一本比较有用的书《Calling C from idl》,于是开始阅读这本书的电子版(English)。遂决定一边阅读一边写一些心得体会。
DLM基础
一个IDL DLM需要两个文件的支持,分别为ASCII模块描述文件(以.dlm扩展名结尾),还有一个就是库文件(DLL)包含被调用的函数代码。在Windows平台下,还需要为链接库指定一个模块定义文件(.def)。
模块描述文件说明
一个模块描述文件是IDL启动后需要读取的简单文本文件,里面包含了IDL需要加载的例程的相关信息。它的语法规则如下:
MODULE name DESCRIPTION description VERSION version SOURCE source BUILD_DATE date FUNCTION name arg1 arg2 PROCEDURE name arg1 arg2
分别表示模块名称、描述、版本、作者、日期、函数名以及最少参数最多参数个数、过程名以及最少参数最多参数个数。
一个简单的例子
开发环境为VS2013 ,操作系统为Windows8.1
步骤1:首先使用VS2013创建一个DLL空项目(此处略去),名称为simpleExample
步骤2:将IDL ../external目录下的export.h文件以及 ../bin.x86目录下的idl.lib库一起复制到该项目目录下,为连接器配置附加库目录以及附加依赖项,将export.h添加到项目头文件目录中。
步骤3:创建一个头文件simpleExample.h,代码如下:
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #include "export.h" #define ARRLEN(arr) (sizeof(arr)/sizeof(arr[0])) //函数原型 extern void IDL_CDECL simpleProcedure(int argc, IDL_VPTR argv[], char* argk); extern IDL_VPTR IDL_CDECL simpleFunction(int argc, IDL_VPTR argv[], char* argk);
这两个函数原型中都包含三个参数,他们分别代表参数个数,指针数组,里面的元素是IDL定义的IDL_VPTR指针,指向参数,argk表示关键字。步骤4:创建相应的源文件simpleExample.c。代码如下:
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #include "export.h" #include "simpleExample.h" IDL_VPTR IDL_CDECL simpleFunction(int argc, IDL_VPTR argv[], char* argk) { IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "simpleFunction called"); return (IDL_GettmpLong(0)); } void IDL_CDECL simpleProcedure(int argc, IDL_VPTR argv[], char* argk) { IDL_Message(IDL_M_NAMED_GENERIC, IDL_MSG_INFO, "simpleProcedure called"); }
步骤5:创建IDL_Load.c源文件。所有的自定义的库文件中都必须包含一个名为IDL_Load函数,该函数没有参数,返回类型为int ,返回0 表示失败,1表示成功#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #include "export.h" #include "simpleExample.h" int IDL_Load(void) { static IDL_SYSFUN_DEF2 procedure_addr[]= { { (IDL_SYSRTN_GENERIC)simpleProcedure,"SIMPLEPROCEDURE",0,0,0,0 }, }; static IDL_SYSFUN_DEF2 function_addr[]= { { simpleFunction, "SIMPLEFUNCTION",0,0,0,0 }, }; return IDL_SysRtnAdd(function_addr, IDL_TRUE, ARRLEN(function_addr)) && IDL_SysRtnAdd(procedure_addr, IDL_FALSE, ARRLEN(procedure_addr)); }
其中IDL_SYSFUN_DEF2是一个结构体,他的定义为:typedef struct{ IDL_SYSRTN_GENERIC funct_addr; char* name; usigned short arg_min; usigned short arg_max; int flags; void * extra; }IDL_SYSFUN_DEF2
步骤6:创建模块定义文件.defLIBRARY "simpleExample" EXPORTS IDL_Load @ 1
步骤7:创建一个DLM文件MODULE simpleExample DESCRIPTION very simple Example VERSION 1.0 SOURCE Duan Yaxin BUILD_DATE NOVEMBER 2000 FUNCTION SIMPLEFUNCTION 0 0 PROCEDURE SIMPLEPROCEDURE 0 0
步骤8:编译生成dll.步骤9:将生成的dll文件和dlm文件复制到IDL安装目录下的 ../bin.x86下。
步骤10:启动IDL,在命令中进行测试:
至此,一个简单的IDL C++混合编程完成。如有漏洞或疏忽的地方欢迎指出。