您的位置:首页 > 编程语言 > C语言/C++

Calling C and C++ from IDL (二)——变量传递

2016-04-10 20:43 423 查看
1、创建DLM

首先使用VS2013创建一个DLL项目,然后添加IDL安装目录../external下的export.h到项目中,并添加到头文件中,以及../bin.x86下的idl.lib到项目中,设置链接器附加库目录以及附加依赖项idl.lib。

然后为项目添加DLM文件,并命名为IDLtoC.dlm。文件内容如下:

MODULE IDLtoC
DESCRIPTION example programs IDL to C
VERSION 1.0
SOURCE DuanYaxin
BUILD_DATE April 2016
FUNCTION IDLTOC_SINGLEINT 1 1
FUNCTION IDLTOC_FINALSCALAR 4 4
PROCEDURE IDLTOC_DOUBLEINT 2 2


2、创建头文件IDLtoC.h

该文件中主要包括如下几部分:

消息代码

宏定义

startup Function 和 exit handler

#ifndef IDL_C_H
#define IDL_C_H
//#include "export.h"
/*this must match the corresponding entries in IDLtoC.c*/
/*message numbers...*/
#define IDLtoC_ERROR 0
#define IDLtoC_NOSTRINGARRAY -1
#define ARRLEN(arr) (sizeof(arr)/sizeof(arr[0]))

extern IDL_MSG_BLOCK msg_block;
/*define the startup function that adds the C function to IDL and the Exit handler*/
/*IDLtoPVMscalarExamples.c*/
extern void IDLtoC_scalarExample_exit_handler(void);
extern int IDLtoC_scalarExampleStartup(void);
#endif


其中最后两个函数需要解释一下,当IDL关闭时将会调用IDLtoC_scalarExample_exit_handler

当IDL第一次调用函数时,将会调用IDLtoC_scalarExampleStartup

3、创建IDLtoC.c文件

该文件的编写要结合上步创建的头文件。

首先是定义一个消息数组,里面包含两个元素,这两个元素又是IDL_MSG_DEF类型的结构体,该结构体包含两个成员,一个是名称,一个是格式说明format。

然后定义一个IDL_MSG_BLOCK类型的变量 msg_block,我的理解可能是表示一个消息框。

接着是IDL_Load函数,该函数是必须的,用来填充上面的消息框,并且调用IDLtoC_scalarExampleStartup函数

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "export.h"
#include "IDLtoC.h"

static IDL_MSG_DEF msg_arr[]=
{
{"IDLtoC_ERROR","%NError: %s."},
{"IDLtoC_NOSTRINGARRAY","%Nstring arrays not allowed %s."},
};
/*The load function files in this message block handle with the
opaque handle to the message block used for this module.the other
routines can then use it to throw errors from this block.
*/
IDL_MSG_BLOCK msg_block;

int IDL_Load(void)
{
/*define the message block*/
if (!(msg_block = IDL_MessageDefineBlock("IDLtoC", ARRLEN(msg_arr), msg_arr)))
{
return IDL_FALSE;
}
/*Call the startup function to add the routine to IDL*/
if (!IDLtoC_scalarExampleStartup())
{
IDL_MessageFromBlock(msg_block, IDLtoC_ERROR, IDL_MSG_RET, "Unable to initialize C scalar example");
}
return IDL_TRUE;
}


4、 创建IDLtoCscalarExamples.c文件

该文件可以说是核心部分,里面定义了供IDL调用的函数或过程的具体实现。

首先定义函数原型,函数都是以extern IDL_VPTR IDL_CDECL开始,过程是以extern void IDL_CDECL开始。

接着将这些函数添加到IDL系统函数当中,主要用到了IDL_SYSFUN_DEF2结构体。

然后就是实现头文件中定义的启动函数和exit handler。在启动函数中,使用IDL_SysRtnAdd将函数和过程添加到IDL中,并注册exit handler

最后,就是各个函数的实现部分。其中有几个函数需要特别说明一下:

IDL_ENSURE_SCALAR()获取参数,并确保它是标量,否则报错

IDL_LONGSCALAR()类型转换,因为IDL与C类型有细微的差异

IDL_GettemLong()获取参数,分配内存,传递给IDL,释放内存

IDL_EXCLUDE_EXR()确保参数在IDL已经命名的变量

IDL_STORESCALAR()将值输入给输出参数

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "export.h"
#include "IDLtoC.h"

/*globals here*/
static char statusBuffer[256];
/*function protos*/
extern IDL_VPTR IDL_CDECL IDLtoC_singleInt(int argc, IDL_VPTR argv[], char * argk);
extern void IDL_CDECL IDLtoC_doubleInt(int argc, IDL_VPTR argv[], char * argk);
extern IDL_VPTR IDL_CDECL IDLtoC_finalScalar(int argc, IDL_VPTR argv[], char * argk);
/*define the function*/
static IDL_SYSFUN_DEF2 IDLtoC_functions[]=
{
{ IDLtoC_singleInt, "IDLTOC_SINGLEINT",1,1,0,0 },
{IDLtoC_finalScalar,"IDLTOC_FINALSCALAR",4,4,0,0},
};
static IDL_SYSFUN_DEF2 IDLtoC_procedures[] =
{
{ (IDL_SYSRTN_GENERIC)IDLtoC_doubleInt, "IDLTOC_DOUBLEINT", 2, 2, 0, 0 },
};
/*check which system we are on*/
#ifdef WIN32
#include <Windows.h>
#endif

/*startup call when DLM is loaded*/
int IDLtoC_scalarExampleStartup(void)
{
if (!IDL_SysRtnAdd(IDLtoC_functions, TRUE, ARRLEN(IDLtoC_functions)))
{
return IDL_FALSE;
}
if (!IDL_SysRtnAdd(IDLtoC_procedures, FALSE, ARRLEN(IDLtoC_procedures)))
{
return IDL_FALSE;
}
/*Register the exit handler*/
IDL_ExitRegister(IDLtoC_scalarExample_exit_handler);
return (IDL_TRUE);
}
/*called when IDL is shutdown*/
void IDLtoC_scalarExample_exit_handler(void)
{
//nothing special to do in this case
}
IDL_VPTR IDL_CDECL IDLtoC_singleInt(int argc, IDL_VPTR argv[], char * argk)
{
/*
Called in IDL as value=IDLtoC_singleInt(input)
*/
int value, input;
IDL_ENSURE_SCALAR(argv[0]);//will catch any improper calls
input = IDL_LongScalar(argv[0]);//will do type conversion
value = input * 10;
return (IDL_GettmpLong(value));
}
void IDL_CDECL IDLtoC_doubleInt(int argc, IDL_VPTR argv[], char * argk)
{
/*
Called in IDL as IDLtoC_doubleInt,input,output
*/
int input, output;
IDL_ENSURE_SCALAR(argv[0]);
IDL_EXCLUDE_EXPR(argv[1]);
input = IDL_LongScalar(argv[0]);

output = input * 10;
IDL_StoreScalar(argv[1], IDL_TYP_LONG, (IDL_ALLTYPES*)&output);
}
IDL_VPTR IDL_CDECL IDLtoC_finalScalar(int argc, IDL_VPTR argv[], char * argk)
{
double input1, input2, output1, result;
int i, output2;
IDL_VPTR ivReturn = IDL_Gettmp();
ivReturn->type = IDL_TYP_DOUBLE;
for ( i = 0; i < 4; i++)
{
IDL_ENSURE_SCALAR(argv[i]);
}
IDL_EXCLUDE_EXPR(argv[2]);
IDL_EXCLUDE_EXPR(argv[3]);
/*now convert the first two parameters to double*/
input1 = IDL_DoubleScalar(argv[0]);
input2 = IDL_DoubleScalar(argv[1]);
result = input1 + input2;
output1 = input1*3.14;
/*store the result as the correct type*/
IDL_StoreScalar(argv[2], IDL_TYP_DOUBLE, (IDL_ALLTYPES *)&output1);
IDL_StoreScalar(argv[3], IDL_TYP_LONG, (IDL_ALLTYPES *)&output2);
/*load result into the double part of value*/
ivReturn->value.d = result;
return ivReturn;

}


5、项目中添加.def文件

LIBRARY IDLtoC
EXPORTS
IDL_Load @ 1


6、编译,并将生成的dll文件以及dlm文件复制到IDL安装目录../bin.x86下,然后在IDL命令行中进行测试。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  IDL