NI LabWindows CVI 中呼叫 DLL 的幾種方法
這幾日上網發現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!