NI LabWindows CVI 中调用 DLL 的几种方法

       NI LabWindows CVI 是一个很好的编程工具,用它的人门槛要求不是很高(比VC++好多了 )漂亮的立体界面,标准C的编程语言……。当我转向它的时候,我发现这就是传说中真正的RAD工具,但国内关于这方面的书不多,遇到问题后连个能商量的人都没几个,却是同并快乐着。

        这几日上网发现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!

你可能感兴趣的:(NI LabWindows CVI 中调用 DLL 的几种方法)