这几日上网发现CVI的讨论者多了,也发现有很多CVI友们提出了一些困惑,比如用CVI加载别的编程语言写的DLL时遇到的无法使用的问题。
首先是 extern "C",CVI中无法加载有此类声明的DLL(有一些人发表的关于CVI加载DLL的文章中居然说必需有extern "C"声明,CVI才能用DLL)。然后用CVI生成的有“DLLSTDCALL”字样的DLL VC不认识!。难到CVI这东西真是好用不便宜???
我以前也遇到过同样的问题,今天把我总结的一些解决办法拿出来与大家分享。
1、和盘托出
简单点说就是把你的CVI工程编成DLL,由其它(如VC)去调用。有些朋友会问:CV作的DLL中能用界面吗,如何作?
当然是可以有界面的,先Build->Target Type->Dynamic Link Library,再Build->Target Setting->Embed project .UIRs。这样就能把你的UIR也打包进去了。
例程如下:
#include <cvirte.h>
//这是CVI标准DLL MAIN函数
static int panelHandle;
int __stdcall DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
if (InitCVIRTE (hinstDLL, 0, 0) == 0)
return 0; /* out of memory */
break;
case DLL_PROCESS_DETACH:
CloseCVIRTE ();
break;
}
return 1;
}
int __stdcall DllEntryPoint (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
/* Included for compatibility with Borland */
return DllMain (hinstDLL, fdwReason, lpvReserved);
}
//注意下面的代码
void __stdcall RunDllUI (void)
{
panelHandle = LoadPanelEx (0, "dlluir.uir", PANEL, __CVIUserHInst);//这里你应该看明白了吧!
DisplayPanel (panelHandle);
RunUserInterface ();
}
int CVICALLBACK CloseUICallback (int panel, int control, int event, //在DLL中控件的回调函数
void *callbackData, int eventData1, int eventData2) //正常使用
{
switch (event) {
case EVENT_COMMIT:
HidePanel(panelHandle);
DiscardPanel(panelHandle);
QuitUserInterface(0);
break;
}
return 0;
}
//……………………
2、拖泥带水
在DLL中是可以加载其它DLL的,那些用VC作的不是给CVI用的DLL我们当然无法使用(VC中有太多的关键字CVI中无法识别),不过用VC识别它 自已的程序还是没问题的,我们用VC新建一个DLL工程,然后加载那些我们想用的DLL,在新工程里写几个CVI能用的函数实现对其它DLL的通讯接口, 编译,过关!
3、孤注一掷
有些朋友会说:VC 不会!我连VC的IDE界面都不认识!
那么我们就只能在CVI内部解决DLL的问题了!
请看例程:
#include <windows.h>//我们需要WINDOWS的API函数
#include <cvirte.h>
#include <formatio.h>
#include <userint.h>
//请注意,在以上的“#include”语句中,我们没有加入DLL的头文件
//因为就是加了才无法通过编译,这里我们用一种处理无头案的方法来解决那些非我族类的DLL
int status;
char message[80];
int main (int argc, char *argv[])
{
/*请注意以下几个声明,它们可是很重要的!!!*/
HMODULE hinstLib;
DLLCdeclFunction DLLFunction;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
/*-------------------------------------------------------------------------------------------------------*/
if (InitCVIRTE (0, argv, 0) == 0) /* Needed if linking in external compiler; harmless otherwise */
return -1; /* out of memory */
/*-------------------------------------------------------------------------------------------------------*/
// Get a handle to the DLL module.
//装载动态链接库mydll.dll
hinstLib = LoadLibrary("mydll.dll");
// If the handle is valid, try to get the function address.
if (hinstLib != NULL)//成功装载动态链接库mydll.dll
{
DLLFunction = (DLLCdeclFunction)GetProcAddress(hinstLib, (LPCSTR)"MyDLLCdeclFunction");
//取函数指针地址
// If the function address is valid, call the function.
if (fRunTimeLinkSuccess = (DLLFunction != NULL)) //dll中有函数MyDLLCdeclFunction()
{
Fmt(message, "message via DLL function/n");
status = (long int)DLLFunction (message);//调用dll函数!!!
}
// Free the DLL module
fFreeResult = FreeLibrary(hinstLib);//卸载动态链接库mydll.dll
}
// If unable to call the DLL function, use an alternative
if (! fRunTimeLinkSuccess)
{
MessagePopup ("Function Load Error");
}
/*-------------------------------------------------------------------------------------------------------*/
return 0;
}
通过以上的代码你应该明白它是如何工作的了吧!
这是MyDLLCdeclFunction的函数原形:
extern "C" long int DLLIMPORT MyDLLCdeclFunction(char * dummycharname);
DLLFunction 是指向函数的指针
message 是传给该函数的参数
status 是该函数的返回值
4、乘龙快婿
新出的CVI 8.5有了一个新特性:可以用在Visual.Studio.2005的VC中新建、添加CVI的工程
这样对于在CVI中使用DLL我们又有了一个新的思路,把作好的CVI用VC2005打开,然后在VC中加载DLL给CVI使用!但是实际作了以 后,你会发现当你在VC2005中在CVI的头文件中“#include "mydll.h" ”后,编译器会给出与CVI下同样的错误提示!
解决的办法也有:我们可以在VC2005内先加载CVI工程,可以看到都是“*.h *.c”文件,用“Add new file to Item”在工程内新加一个“*.cpp”及“*.h”,现在在新加的文件里再调用之前的头文件及DLL看看结果如何?
5、移情别恋
JAVA中有一种JNI技术可以在JAVA中调用DLL,也同样可以把JAVA作成DLL。我们看一下在JAVA中调用DLL的方法:
我们要在JAVA中调用hello.dll
JAVA代码:
class HelloWorld {
public native void displayHelloWorld();
static {
System.loadLibrary("hello");//此句重要
}
public static void main(String[] args) {
new HelloWorld().displayHelloWorld();
}
}
编译!
javac HelloWorld.java
//得到HelloWorld.class
javah HelloWorld
// 得到 HelloWorld.h
这个h文件相当于我们在java里面的接口,这里声明了一个Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject);方法,然后在我们的本地方法里面实现这个方法,也就是说我们在编写C/C++程序的时候所使用的方法名必须和这里的一致
VC代码:
#include <jni.h>
2 #include "HelloWorld.h"
3 #include <stdio.h>
4 JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj)
{
printf("Hello world!/n");
return;
}
生成动态库!
运行程序
java HelloWorld
屏幕输出:Hello world!