织梦CMS - 轻松建站从此开始!

罗索

当前位置: 主页>杂项技术>VC(MFC)>

IDL与VC的接口技术研究

jackyhwei 发布于 2010-10-23 16:05 点击:次 
本文研究了最新第四代可视化交互数据语言IDL6.3与VC的接口技术。从而实现了IDL6.3与VC之间的相互调用以及两种语言的资源共享,为应用系统的研发提供了一种新的方法。最后,通过实例给出了IDL6.3与VC之间相互调用的具体实现方法。
TAG:

摘要 本文研究了最新第四代可视化交互数据语言IDL6.3与VC的接口技术。从而实现了IDL6.3与VC之间的相互调用以及两种语言的资源共享,为应用系统的研发提供了一种新的方法。最后,通过实例给出了IDL6.3与VC之间相互调用的具体实现方法。
正文  

1.引言
美国RSI公司于2005年9月推出的最新交互数据语言IDL6.3(Interactive Data Language)作为第四代语法简单的面向矩阵运算的计算机语言,拥有高级图象处理能力、交互式二维和三维图形技术、面向对象的编程方式、OpenGL图形加速、量化可视化表示、集成数学与统计算法、灵活的数据输入输出方式、图形用户界面工具包、跨平台大型应用开发、连接ODBC兼容数据库和多种外部程序扩展工具。在实际应用中,使用其它语言需要几十条、几百条甚至上千条语句才能实现的功能,而使用IDL只需简单的几个语句;正是因为IDL操作简单、功能齐全、海量复杂数据的快速可视化交互分析处理能力,使得IDL在世界范围内开始流行;同时在数据交互可视化分析、图像处理、图像分析、图像理解和体绘制等方面得到了广泛的应用,成为主流产品。让用户的数据处理、科学研究和商用开发真正做到快捷有效。因此IDL是进行交互数据分析和可视化应用工程跨平台开发的高效软件和理想工具。
Visual C是微软推出的非常有影响,运行非常稳定的专业级程序设计和数据处理语言。使用灵活、高效的Visual C语言具有良好的集成开发环境、方便整洁的界面开发功能,开发者能方便地利用Windows资源或MFC类库,开发出功能强大的Win32应用程序。
为了实现IDL与Visual C的相互调用,从而扩充二者的数据处理能力和编程能力,实现二者的资源共享,IDL语言提供了与Visual C的应用程序接口API技术。通过IDL的应用程序接口API,用户可以很方便快捷的实现IDL与VB、VC、JAVA和Fortran等语言之间的相互调用,共享多种语言的资源,实现高效的混合编程,快速跨平台研发功能强大的应用系统。
2.IDL调用VC
利用IDL与VC的API,可以方便的实现在IDL中调用Visual C的可执行文件、函数和程序。在IDL中调用VC可以使用三种方法:SPAWN方法、CALL_EXTERNAL方法和LINKIMAGE方法。
2.1 基于SPAWN的VC调用
利用SPAWN方法可以在IDL中直接调用VC的可执行文件,具体用法是只需要把由VC编译生成的可执行应用程序文件,放在SPAWN命令的后面,即SPAWN,可执行程序名。如果直接运行不带参数的SPAWN命令,将调用Windows的DOS Shell命令窗口。
2.2 基于CALL_EXTERNAL的VC调用
一、基本调用方法
在IDL中,利用API函数CALL_EXTERNAL调用VC函数和程序的基本思路:
(1)在IDL中创建与VC函数中定义的数据结构相匹配的数据结构(需要精确匹配)。说明:对于非结构数据的传输,可以省略该步骤。对于结构数据的传输,如果能够确保结构数据的正确性,不需要对结构数据进行检测,也可以省略该步骤。IDL数据结构的定义格式为:
PRO MyStructure__define
s1={MyStructure1, var1: value1, ... , varn: valuen }
……
s2={MyStructuren, var1: value1, ... , varn: valuen }
END
(2)在VC中编写被IDL调用的VC函数。
(3)在IDL中利用过程MAKE_DLL编译VC的函数和程序,生成在IDL中可以使用的动态连接库DLL。其用法为:
MAKE_DLL,InputFiles[,OutputFile],ExportedRoutineNames[,COMPILE_DIRECTORY=path][,DLL_PATH=variable][, INPUT_DIRECTORY=path] [, OUTPUT_DIRECTORY=path]
其中:InputFiles给出包含VC函数的源代码程序MyVCPrg.c。扩展名可以省略。OutputFile给出编译VC函数后,生成的动态连接库的名称。ExportedRoutineNames给出编译后生成的过程的名称。该名称一般与VC源代码程序中函数名同名。COMPILE_DIRECTORY=path给出用于存放动态连接库的目录路径;如果省略该选项,则存放动态连接库的目录为系统内存变量!MAKE_DLL. COMPILE_DIRECTORY中指定的目录路径;用户可以改变!MAKE_DLL.COMPILE_DIRECTORY的值,重新指定新路径。DLL_PATH=variable用于存放动态连接库的目录和名称。 INPUT_DIRECTORY =path给出VC函数的源代码程序所在的目录。OUTPUT_DIRECTORY=path给出用于存放动态连接库的目录路径;一般与COMPILE_DIRECTORY=path和DLL_PATH=variable配合使用。
(4)在IDL中利用函数CALL_EXTERNAL,通过动态连接库调用VC的函数。其用法为:
Result = CALL_EXTERNAL(Image, Entry [, P0, ..., PN-1] [, /B_VALUE | , /D_VALUE | , /F_VALUE | , /I_VALUE | , /L64_VALUE |, /S_VALUE | , /UI_VALUE | , /UL_VALUE | , /UL64_VALUE] [, /CDECL][, RETURN_TYPE=value][, COMPILE_DIRECTORY=string]
其中:Image给出动态连接库DLL路径和名称。Entry给出调用VC函数所对应的过程名。P0, ..., PN-1给出调用VC函数时,需要传递的数据。/B_VALUE | , /D_VALUE | , /F_VALUE | , /I_VALUE | , /L64_VALUE |, /S_VALUE | , /UI_VALUE | , /UL_VALUE | , /UL64_VALUE指定函数调用后返回值的类型。/CDECL用于指出使用Windows系统提供的两种数据传递标准的哪一种。/STDCALL用于VB与IDL的数据传输;/CDECL用于VC与IDL的数据传输。RETURN_TYPE=value用类型代码的形式指定函数调用后返回值的类型。COMPILE_DIRECTORY=string指出动态连接库DLL的所在路径。
二、具体实现方法
下面通过传输包含多个变量和数组的结构变量的完整示例,详细说明IDL调用VC的方法。
编写VC程序IDLToVCStruct.c,要求输入字节型、长整型、浮点型、双精度型和含有两个元素的整型数组,返回它们的值加20。并设计IDL程序IDLToVCStruct.pro调用VC函数。数据的默认值:0b、0L、0.0、0.0D和(0,0)。具体实现方法为:
(1)在IDL中创建与VC函数中定义的数据结构相匹配并且精确匹配的数据结构。
PRO IDLToVCStructAStructure__define
s = { IDLToVCStructAStructure,zero:0B, one:0L, two:0.0, three:0.0D, four:[0,0] }
END
(2)在VC中编写被IDL调用的VC程序IDLToVCStruct.c。
#include
#include "idl_export.h"
typedef struct {unsigned char zero; IDL_LONG one;
float two; double three;short four[2];} ASTRUCTURE;
int IDLToVCStructNatural(ASTRUCTURE *mystructure, IDL_LONG n)
{for (; n--; mystructure++) {
mystructure->zero+=20; mystructure->one+=20;
mystructure->two+=20; mystructure->three+=20;
mystructure->four[0]+=20; mystructure->four[1]+=20;}
return 1;}
int IDLToVCStruct(int argc, void *argv[])
{if (argc != 2) return 0;
return IDLToVCStructNatural((ASTRUCTURE*) argv[0], (IDL_LONG) argv[1]);}
(3)在IDL中利用过程MAKE_DLL编译VC的函数和程序,生成在IDL中可以使用的动态连接库DLL。其用法为:
function IDLToVCStructGetLib
common GET_EXLIB_BLK, IDLToVCStructShLib
; 测试共享库是否存在。若存在直接调用;否则创建
build_lib = n_elements(IDLToVCStructShLib) eq 0
if (not build_lib) then build_lib = not FILE_TEST(DLToVCStructShLib, /READ)
if (build_lib) then begin
; 定位CALL_EXTERNAL调用C函数所在的目录
call_ex_dir='D:\RSI\IDL62\' & source = [ 'IDLToVCStruct' ]
export_rtns=[ 'IDLToVCStructNatural', 'IDLToVCStruct']
; 创建动态连接库的目录
FILE_MKDIR, 'D:\RSI\IDL62\IDLToVCStructDLL'
!MAKE_DLL.COMPILE_DIRECTORY='D:\RSI\IDL62\IDLToVCStructDLL'
; 编译C语言函数,创建动态连接库
MAKE_DLL, source, 'IDLToVCStructDLLLib', export_rtns, $
INPUT_DIR=call_ex_dir, DLL_PATH=IDLToVCStructShLib
endif
return, IDLToVCIncrStructShLib
end
(4)在IDL中利用函数CALL_EXTERNAL,通过DLL调用VC的函数。调用程序为:
PRO IDLToVCStruct, s_arr
; 检查s_arr的数据类型是否为结构类型
CASE SIZE(s_arr, /TYPE) OF
0 : s_arr = replicate({IDLToVCStructAStructure},2)
8 : IF TAG_NAMES(s_arr,/STRUCTURE_NAME) NE $
'IDLToVCStructAStructure' THEN MESSAGE,'structure type error'
ELSE: MESSAGE, 'S_ARR must be a structure'
ENDCASE
N = N_ELEMENTS(s_arr)
PRINT, s_arr; 输出调用前数据
func = 'IDLToVCStruct'
DLLLib = IDLToVCStructGetLib()
Result = CALL_EXTERNAL(DLLLib, func, s_arr, n, VALUE=[0, 1], /CDECL)
PRINT, s_arr; 输出调用后数据
END
2.3 基于LINKIMAGE的VC调用
在IDL中,还可以利用API函数LINKIMAGE调用VC函数和程序,其用法与CALL_EXTERNAL类似。具体用法为:LINKIMAGE,Name,Image,[,Type]。其中,Name代表IDL要调用的函数或过程名;Image代表包含程序代码的文件名;Type给出被调用程序的类型,0代表过程,1代表函数,2代表设备驱动。其更详细的用法请参阅帮助文档edg.pdf。使用LINKIMAGE调用其它语言程序,程序开发者需要有丰富的IDL系统内部的知识,该方法不适合一般的程序开发者使用,RSI公司也不推荐用户使用LINKIMAGE,建议使用CALL_EXTERNAL。另外,用VC进行DLL设计时,应注意IDL的数据类型与VC的数据类型之间的对应转换关系。在头文件idl_export.h中包含了数据类型和宏的全部定义。需要注意的是,在IDL程序中不能释放使用VC生成的DLL中分配的内存空间。因此在设计DLL时,可以使用静态数据解决这一问题,否则会造成内存溢出。
3.VC调用IDL
3.1 基本调用方法
利用IDL的API,可以方便的实现在VC中调用IDL的命令、过程和函数。其基本方法是:
(1)设置VC调用IDL的工作环境。复制IDL的DLL到VC环境中。
(2)利用IDL_Win32Init()初始化IDL。在VC调用IDL之前,必须先利用IDL_Win32Init()对IDL进行一次初始化。该函数的用法为:int IDL_Win32Init(0, void *hinstExe, void *hwndExe, NULL);其中:hinstExe是调用IDL的应用程序句柄;hwndExe是应用程序的窗口句柄。如果IDL初始化成功,则返回“TRUE”,否则返回“FALSE”。
(3)输出内容的定向。在基于GUI的应用程序中,所有输出均在一个逻辑窗口中。当调用IDL后,默认的输出函数将自动被IDL的函数取代。通过IDL_ToutPush()和IDL_ToutPop()可以改变IDL的输出结果到指定的函数中。在IDL中,可以通过IDL_ToutPush()和IDL_ ToutPop()控制结果信息的进栈和出栈。其中从堆栈中弹出的输出结果均为字符串。
(4)设计输出函数。设计输出调用IDL结果信息的函数。函数的类型如下:
typedef void (* IDL_TOUT_OUTF)(int flags, char *buf, int buf);
其中:flags的取值为IDL_TOUT_F_STDERR或者IDL_TOUT_F_NLPOST,用来确定输出文本数据的方式;buf是输出的字符串;n是buf中要输出的字符数。
(5)在VC中调用并执行IDL命令、过程或者函数。通过IDL的API函数IDL_ExecuteStr()或者IDL_Execute()调用并执行IDL的命令、过程或者函数。这两个函数的用法为:
int IDL_Execute(int argc, char *argv[]);
其中: argc是指在argv[]中的命令数;argv[]是由IDL命令字符串组成的字符串数组。
int IDL_ExecuteStr(char *cmd);其中: cmd是一个IDL命令字符串。
(6)关闭IDL。在VC调用IDL完成后,需要通过调用关闭函数IDL_Cleanup()关闭IDL。该函数用法为:int IDL_Cleanup(int just_cleanup);
其中:just_cleanup的取值为TRUE(关闭并不退出)和FALSE(关闭并退出(默认值))。
3.2 直接实现方法
下面通过应用程序VCToIDL,详细说明VC调用IDL的实现方法。
设计GUI如图1的应用程序VCToIDL。实现在GUI下方的编辑窗口中输入IDL命令后;IDL命令的运行结果在GUI上方的编辑窗口中输出。其详细实现方法如下:
(1)在VC中创建基于对话框的工程VCToIDL。
(2)建立如图1的GUI界面。其控件和属性:
多行Edit Box;ID:IDC_EDIT_LOG;添加CEdit类型变量m_LogWindow。
单行Edit Box;ID:IDC_EDIT_CMD;添加CEdit类型变量m_Command。
标签Static Text;ID:IDC_STATIC;Caption:IDL>
(3)把IDL环境下的头文件idl_export.h、系统库IDL32.LIB和IDL32.DLL等DLL复制到工程的所在目录,并添加到工程VCToIDL中。
(4)初始化IDL。在CVCToIDLApp中申请指向GUI窗口的全程指针变量pMyDlg,并在CVCToIDLApp::InitInstance()中“int nResponse = dlg.DoModal();”的前面添加:
pMyDlg = &dlg;
IDL_ToutPush(OutFunction); //输出函数OutFunction进栈
if(!IDL_Win32Init(0,m_pMainWnd, m_pMainWnd->m_hWnd, NULL)) return FALSE;//初始化IDL
(5)设计结果信息输出函数。在CVCToIDLApp中添加输出函数OutFunction():
void OutFunction(int flags, char *buf, int n)
{if(n>0) pMyDlg->OutPutLog(0, buf); // 若IDL有信息输出,则输出到文本框
if(flags & IDL_TOUT_F_NLPOST) pMyDlg->OutPutLog(0, "\r\n\0"); // 换行输出IDL信息}
(6)调用并执行IDL命令、函数和程序。在CVCToIDLDlg中为IDC_EDIT_CMD添加响应函数OnOK():
void CVCToIDLDlg::OnOK()
{LPSTR lpCommand, lpOut; //定义传递命令的字符串变量
lpCommand = (LPSTR)new char[256];
lpOut = (LPSTR)new char[256];
if (!lpCommand || !lpOut) return;
m_Command.GetWindowText(lpCommand, 255); //获取编辑框输入的IDL命令
m_Command.SetWindowText(""); //清空编辑框
lstrcpy(lpOut, "\r\nIDL> "); lstrcat(lpOut, lpCommand);
OutFunction(IDL_TOUT_F_NLPOST, lpOut, strlen(lpOut));//输出IDL的信息
IDL_ExecuteStr(lpCommand); //执行IDL命令
delete lpCommand; delete lpOut;}
(7)结果信息的定向。把IDL的信息定向输出到编辑框IDC_EDIT_LOG,并进行滚动显示。因此在CVCToIDLDlg中添加输出函数OutPutLog():
void CVCToIDLDlg::OutPutLog(int flags, char *buf)
{::SendMessage(pMyDlg->m_LogWindow, EM_SETREADONLY, FALSE, 0L);
::SendMessage(pMyDlg->m_LogWindow, WM_SETREDRAW, FALSE, 0L);
::SendMessage(pMyDlg->m_LogWindow, EM_REPLACESEL, 0, LPARAM(buf));//输出信息
::SendMessage(pMyDlg->m_LogWindow, WM_SETREDRAW, TRUE, 0L);
::SendMessage(pMyDlg->m_LogWindow, EM_SETREADONLY, TRUE, 0L);}
(8)关闭IDL。在CVCToIDLDlg中添加关闭消息(WM_CLOSE)响应函数,并在CVCToIDLDlg::OnClose()中“CDialog: : OnClose()”前加添加:IDL_Cleanup(TRUE);。
3.3 IDLDrawWidget间接实现方法
在VC中调用IDL的命令、过程和函数,还可以使用IDLDrawWidget ActiveX Control来更直接方便的实现,同时在IDLDrawWidget中支持对象绘图。下面通过工程IDLDrawX3VCToIDL,详细说明VC调用IDL的实现方法。
设计GUI如图2的工程IDLDrawX3VCToIDL。实现在GUI下方的编辑窗口中输入IDL命令后;IDL命令的运行结果在GUI上方的编辑窗口中输出;在绘图区可以交互操作对象。实现方法:
(1)在VC中创建基于对话框的工程IDLDrawX3VCToIDL。
(2)建立如图2的GUI界面。其控件和属性:
绘图区IDC_IDLDRAWWIDGET1;ID:IDC_IDLDRAWWIDGET1;添加CIDLDrawX3类型变量m_IDLDrawWidget。
多行Edit Box;ID:IDC_IDLOutputLog;添加CEdit类型变量m_ IDLOutputLog。
单行Edit Box;ID:IDC_IDLCommand;添加CString类型变量m_IDLCommand。
标签Static Text;ID:IDC_STATIC;Caption:IDL>
(3)设计操作绘图区对象的IDL程序,并把它们复制到工程的目录中。如果不需要交互控制绘图区,则可以省去该步骤。
(4)初始化IDL。使用绘图对象的的InitIDL方法初始化IDL。在CIDLDrawX3VCToIDLDlg:: OnInitDialog()中“return TRUE”语句的前面添加:
CString strVal; RECT Rect;
m_IDLDrawWidget.GetWindowRect(&Rect);
m_IDLDrawWidget.SetXsize(Rect.right - Rect.left);
m_IDLDrawWidget.SetYsize(Rect.bottom - Rect.top);
m_IDLDrawWidget.SetXviewport(Rect.right - Rect.left);
m_IDLDrawWidget.SetYviewport(Rect.bottom - Rect.top);
m_IDLDrawWidget.SetOutputWnd((long) m_IDLOutputLog.m_hWnd);
m_IDLDrawWidget.InitIDL((long) m_hWnd);
long i = m_IDLDrawWidget.CreateDrawWidget();
if (i == -1) return TRUE;
(5)设计结果信息输出函数和结果信息的定向。在CIDLDrawX3VCToIDLDlg中,为IDC_IDLOutputLog添加EN_UPDATE响应函数OnUpdateIDLOutputLog() :
void CIDLDrawX3VCToIDLDlg::OnUpdateIDLOutputLog()
{int nLines = m_IDLOutputLog.GetLineCount();
int nUpperLimit = m_IDLOutputLog.LineIndex(nLines - 1);
if (nUpperLimit > 10000) {
int nLowerLimit = m_IDLOutputLog.LineIndex(20);
m_IDLOutputLog.SetReadOnly(FALSE);
m_IDLOutputLog.SetSel(nLowerLimit, nUpperLimit, TRUE);
m_IDLOutputLog.Cut();m_IDLOutputLog.SetSel(0,-1,TRUE);
m_IDLOutputLog.Paste(); m_IDLOutputLog.SetReadOnly(TRUE);
m_IDLOutputLog.UpdateWindow();}}
(6)创建调用函数。在CIDLDrawX3VCToIDLDlg中添加整型全程调用函数ExecuteStr():
int CIDLDrawX3VCToIDLDlg::ExecuteStr(CString cCommand)
{VARIANT vDrawID; VariantInit(&vDrawID);
V_VT(&vDrawID) = VT_I4;
vDrawID.lVal = m_IDLDrawWidget.GetDrawId();
m_IDLDrawWidget.SetNamedData("IDLDrawWidget1", vDrawID);
int iStat = m_IDLDrawWidget.ExecuteStr(cCommand);
return (iStat);}
(7)调用并执行IDL命令。在CIDLDrawX3VCToIDLDlg中添加为IDC_IDLCommand添加响应函数OnOK():
void CIDLDrawX3VCToIDLDlg::OnOK()
{int iExit;int iSemicolon;
CString s_IDLCommand;UpdateData(TRUE);
ExecuteStr((CString)
"PRINT, 'IDL> ' + \"" + m_IDLCommand + "\"");
ExecuteStr(m_IDLCommand.GetBuffer(100));
s_IDLCommand = m_IDLCommand;
s_IDLCommand.MakeUpper();
if ((iExit = s_IDLCommand.Find("EXIT")) != -1) {
if ((iSemicolon = s_IDLCommand.Find(';')) != -1){
if (iSemicolon >> iExit) {ExecuteStr("RETALL");
m_IDLDrawWidget.DoExit(); exit(1);}
} else {ExecuteStr("RETALL");
m_IDLDrawWidget.DoExit(); exit(1);}}
m_IDLCommand = ""; UpdateData(FALSE);}
4.结论
本文深入研究了最新第四代可视化交互数据语言IDL6.3与VC的接口技术。从而实现了IDL6.3与VC之间的相互调用以及两种语言的资源共享,为应用系统的研发提供了一种新的思路和方法。最后,通过实例给出了IDL6.3与VC之间相互调用的具体实现方法。
如果需要本文IDL与VC接口的完整程序源代码,请与作者联系。
参 考 文 献
[1] RSI. IDL Reference Guide [M]. American:RSI,First Edition,2005.6.
[2] RSI. External Development Guide [M]. American:RSI,First Edition,2005.6.

(韩培友)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201010/10353.html]
本文出处:百度博客 作者:韩培友
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容