1. 程式人生 > >NI LabWindows CVI 中呼叫 DLL 的幾種方法

NI LabWindows CVI 中呼叫 DLL 的幾種方法

        這幾日上網發現CVI的討論者多了,也發現有很多CVI友們提出了一些困惑,比如用CVI載入別的程式語言寫的DLL時遇到的無法使用的問題。

        首先是   extern "C",CVI中無法載入有此類宣告的DLL(有一些人發表的關於CVI載入DLL的文章中居然說必需有extern "C"宣告,CVI才能用DLL)。然後用CVI生成的有“DLLSTDCALL”字樣的DLL VC不認識!i_f34.gif。難到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的工程j_0003.gif

這樣對於在CVI中使用DLL我們又有了一個新的思路,把作好的CVI用VC2005開啟,然後在VC中載入DLL給CVI使用!但是實際作了以 後,你會發現當你在VC2005中在CVI的標頭檔案中“#include "mydll.h" ”後,編譯器會給出與CVI下同樣的錯誤提示!i_f09.gif

        解決的辦法也有:我們可以在VC2005內先載入CVI工程,可以看到都是“*.h   *.c”檔案,用“Add new file to Item”在工程內新加一個“*.cpp”及“*.h”,現在在新加的檔案裡再呼叫之前的標頭檔案及DLL看看結果如何?

w_0040.gifw_0040.gifw_0040.gifw_0040.gifw_0040.gifw_0040.gifw_0040.gifw_0040.gifw_0040.gifw_0040.gifw_0040.gifw_0040.gifw_0040.gif

        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!