Archived: How to Integrate 32-Bit LabWindows/CVI 4.0 Libraries into Microsoft Visual C/C++

Publish Date: Jun 27, 2018 | 25 Ratings | 3.72 out of 5 | Print | 1 Customer Review | Submit your review

Overview

This document has been archived and is no longer updated by National Instruments.

C/C++ programmers comfortable with their current 32-bit development environment do not need to migrate to the LabWindows/CVI development environment to take advantage of the power of the LabWindows/CVI Run-Time Engine. Graphical user interfaces that have been created in the LabWindows User Interface Editor can be used in third-party compilers by using the LabWindows/CVI Exportable Libraries. This document describes how a graphical user interface created in LabWindows/CVI can be used in the Microsoft Visual C++ and the Borland C++ compilers under Windows 95/NT.

Table of Contents

  1. LabWindows/CVI Function Callbacks in Third-Party Compilers
  2. Creating New Projects in Microsoft Visual C++ and Borland C++
  3. Option 1. Using Third-Party Compilers to Define User Interface Callback Functions
  4. Option 2. Using a DLL Created in LabWindows/CVI to Define User Interface Callback Functions

1. LabWindows/CVI Function Callbacks in Third-Party Compilers

LabWindows/CVI graphical user interfaces require the use of callback functions to respond to user interface events. There are two options a programmer can select for using callback functions in third-party compilers.

Option 1. Define the user interface callback functions in the external third-party compiler.

Option 2. Define the user interface callback functions in LabWindows/CVI and compile it as a DLL to be linked into the external compiler code.

This application note includes examples of the exact steps required to perform either of these options. First, you will design a user interface to be used with all examples. Then this note will explain the steps required to define the user interface callbacks in Microsoft Visual C++ and Borland C++ (Option 1). Finally, this note will explain how to create a DLL in LabWindows/CVI that contains the callback functions and how to use that DLL in these third-party compilers (Option 2).

The example application you will build should have a front panel that has a LED that is turned on and off by using a horizontal switch. The following picture shows what it might look like.




Defining the User Interface
First, we need to define a user interface to be used in the third-party compiler.

1. In CVI create a new user interface in a new project.

2. Create a panel in the user interface editor and give it a constant name of PANEL. Label the panel “On Off Panel”.

3. On the panel create a command button and give it a constant name of QUIT_BUTTON. Label it “Quit” and give it a callback function name of “Quit”.

4. Create a toggle switch control and give it a constant name of ON_OFF_SWITCH. Label it “Switch” and give it a callback function name of “On_Off_Switch”.

5. Create a LED, give it a constant name of LED, and give it no label.

6. Save the UIR file as OnOff.uir.

7. Add this UIR file to the LabWindows/CVI project and save the project as OnOff.prj

You should now have a user interface that we can use for the examples that follow. Before you move on to the first option for integrating LabWindows/CVI code into one of these compiler environments, you should prepare a new project within that environment. The following section will guide you through the necessary steps to prepare your environment for the examples in this application note.

Back to Top

2. Creating New Projects in Microsoft Visual C++ and Borland C++


The following examples require knowledge of creating new projects and adding source code to projects in the Microsoft Visual C++ and Borland C++ development environments. If you are unfamiliar with this process, go through the following steps for your specific compiler.

Creating a New Project in Microsoft Visual C++

1. Start the Microsoft Developer Studio and choose New from the File Menu.

2. From the New dialog box, click on Project Workspace and click the OK button.

3. Click on Application in the Type: box. Type in the path in the Location: control, and then type in the name of your project in the Name: control. You should then click the Create button. This will be the project where you can develop the following exercise.

4. To create and add source code files into the project, click New under the File menu item. Choose Text File. Type in the source code in the new text file. Save the file by clicking Save under the File menu item. You then must add the file to the project by selecting Files Into Project from the bmenu.

5. You must select the source file, and click the Add button. At this point the source file is part of the project and should be seen in the project workspace.

Creating a New Project in Borland C++
1. Start the Borland C++ development environment and choose New: Project under the File menu item. You will see the following dialog box.




2. Uncheck the OWL option the Frameworks. Choose Application [.exe] in the Target Type: control.

3. Under Libraries, seletct Static.

4. You should then type in the project path and name along with the target name in the appropriate controls.

5. Then click the Advanced button.

6. Uncheck the .rc and .def options and click OK. Click OK in the b dialog box. At this point you will have a project where you can do the following exercise.

7. You should be able to double click on the .cpp file in the project and type in the source code in the new text file. Save the file by clicking Save under the File menu item.

8. To create a new source code file and add it to a project, choose the New: Text Edit under the b menu item. Add your code to the source window. Save the file. Right click on the .exe file in the project window and choose Add Node. You will see the following dialog box.

9. You must select the source file, and click the Open button. At this point the source file is part of the project and should be seen in the project window.

Back to Top

3. Option 1. Using Third-Party Compilers to Define User Interface Callback Functions


When you link your programs in the LabWindows/CVI environment, LabWindows/CVI keeps a table of the nonstatic functions that are in your project. Upon loading a panel or menu bar (using LoadPanel or LoadMenuBar, respectively), the User Interface Library uses this table to find callback functions associated with the objects loaded from the UIR file.

No such table is available when you link using an external compiler. Thus, callback functions written in the external compiler will not be recognized by UIRs unless this special table is created. LabWindows/CVI can create an object file containing this table that can be used in an external compiler.

Creating the Object Table File
To create the object file containing this table for the user interface we created earlier, do the following.

1. With the OnOff.prj loaded, select External Compiler Support from the Build menu of the LabWindows/CVI project window. You will see the following dialog box.




2. Check the UIR Callbacks Object File: check box.

3. Type the pathname and OnOff.obj in the UIR Callbacks Object File control.

4. Click on the Create button.

5. Click the Done Button.

Once the object file is created, you can include it in an external compiler project. The object file that is created is for use with the compiler that is specified in the current compatibility mode. If another compiler is desired, the current compatibility mode must be changed by running the LabWindows/CVI setup program and choosing another compatibility mode.

Defining the Callback Functions
At this point, you should add the following source code to a new project in the development environment of your choice.

#include <cvirte.h>       /* Needed if linking in external compiler; harmless
otherwise */
#include <userint.h>
#include "OnOff.h"

static int panelHandle;

int main (int argc, char *argv[])
{
    if (InitCVIRTE (0, argv, 0) == 0) /* Needed if linking in external
compiler; harmless otherwise */
       return -1;  /* out of memory */
    if ((panelHandle = LoadPanel (0, "OnOff.uir", PANEL)) < 0)
       return -1;
    DisplayPanel (panelHandle);
    RunUserInterface ();
    return 0;
}

int CVICALLBACK Quit (int panel, int control, int event,
       void *callbackData, int eventData1, int eventData2)
{
    switch (event) {
       case EVENT_COMMIT:
              QuitUserInterface (0);
              break;
    }
    return 0;
}

int CVICALLBACK On_Off_Switch (int panel, int control, int event,
       void *callbackData, int eventData1, int eventData2)
{
    switch (event) {
       case EVENT_COMMIT:
       {
              int val;
              GetCtrlVal (panel, PANEL_ON_OFF_SWITCH, &val);
              if(val)
                    SetCtrlVal(panel, PANEL_LED, 1);
              else
                    SetCtrlVal(panel, PANEL_LED, 0);

              break;
       }
    }
    return 0;
}

At this point, you should follow the directions for the compiler of your choice below.

Microsoft Visual C++
1. Choose Files Into Project from the Insert menu.



2. You should then go to the cvi\extlib\ directory, select cvirt.lib, cvisupp.lib, and cviwmain.lib, then click on the Add button. You will then be able to see the files in the project.

3. Next, Choose the Files Into Project from the Insert menu again, and go to the directory where you saved the OnOff.obj file created in LabWindows/CVI, and insert the object file into the Microsoft Visual C++ project.

4. Then select Options... under the Tools menu.

5. Click on the Directories property tab.

6. Select Include files in the Show directories for: list box.

7. Insert the path to the cvi\include directory into the Directories: list and click OK.




8. At this point you should be able to compile and run the project.

  • It is very important to note that when the executable is run, it needs to use the UIR file. Thus, you must copy the UIR file into the directory where the executable is located. Microsoft Visual C++, by default, creates Debug\ and Release\ directories to store executables for debug and release builds. You must copy the UIR file into the Debug\ and Release\ directories.
  • Also, make sure that the header (.h) file for the user interface is in the same directory (your parent directory) as your .c or .cpp file.


Borland C++
1. In a new project in the Borland C++ environment, right click on the .exe file in the Project window.

2. Select Add Node. You will see the following dialog box.



3. You should then go to the cvi\extlib\ directory, select cvirt.lib, cvisupp.lib, and cviwmain.lib, then click on the OK button. You will then be able to see the files in the project.

4. Next, you should choose Add Node again, and go to the directory where you saved the OnOff.obj file created in LabWindows/CVI, and insert it into the Borland C++ project.

5. Then select Project under the Options menu and you will see the following dialog box.




6. Select Directories under the Topics: list, and add the path to the cvi\include directory and click OK. You need to separate the paths by using a semicolon.



7. At this point you should be able to compile and run the project.

  • It is very important to note that when the executable is run, it needs to use the UIR file. Thus, you must copy the UIR file into the directory where the executable is located. Also, the header (.h) file must be in the same directory as the .cpp file.

    Back to Top

    4. Option 2. Using a DLL Created in LabWindows/CVI to Define User Interface Callback Functions

Creating a DLL is not any more difficult than creating a static C library or object. Although they behave differently (DLLs are linked at run time while static libraries are linked when the build occurs), the source code can be identical. For example, you should be able to take an existing source file, change the target in LabWindows/CVI to Dynamic Link Library, and build the DLL.

One difference, in source code, is that a DLL can contain a DllMain function. The DllMain function is called when an application loads and unloads the DLL. With this function, you have a mechanism to do initializations when the DLL is first loaded (similar to a constructor in C++) and to free system resources when the DLL is unloaded (similar to a destructor in C++). If you do not explicitly define a DllMain, LabWindows/CVI will create a default one that does nothing.

In addition to the source code, you should create a header file containing the prototypes of the functions you want exported from the DLL. You need to let the compiler know which functions to export because DLLs can have many functions, some of which are used internally by the DLL and not exposed to any calling program. All exported functions can be called by external modules.

Example of How to Create a DLL in LabWindows/CVI
An example of how to create a DLL for our example program follows.

1. Use the project where the user interface file exists. Select Target: Dynamic Link Library from the Build menu in the project window.



2. Create a new source file and define the callback functions of the dll by typing in the following code.

  • You can automate most of the process of generating the following code by using CodeBuilder (Code>Generate>All code) in the UIR editor window.


#include <cvirte.h>  /* Needed if linking in external compiler; harmless 
                      otherwise */
#include <userint.h>
#include "OnOff.h"

int InitUIForDLL (void);
void DiscardUIObjectsForDLL (void);

static int panelHandle;

int __stdcall DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID
lpvReserved)
{
    switch (fdwReason) {
       case DLL_PROCESS_ATTACH:
          if (InitCVIRTE (hinstDLL, 0, 0) == 0) /* Needed if linking in 
                                                 external compiler; harmless 
                                                 otherwise */
             return 0;   /* out of memory */
          break;
       case DLL_PROCESS_DETACH:
          DiscardUIObjectsForDLL ();       /* Discard the panels loaded in
                                           InitUIForDLL */
          CloseCVIRTE ();            /* Needed if linking in external compiler;
                                     harmless otherwise */
          break;
    }

    return 1;
}

int __stdcall DllEntryPoint (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID
lpvReserved)
{
    /* Included for compatibility with Borland */

     return DllMain (hinstDLL, fdwReason, lpvReserved);
}

int __stdcall InitUIForDLL (void)
{
    /* Call this function from the appropriate place in your code */
    /* to load and display startup panels.            */

    if ((panelHandle = LoadPanelEx (0, "OnOff.uir", PANEL, __CVIUserHInst)) < 
       0)
       return -1;
    DisplayPanel (panelHandle);

    /* Uncomment this call to RunUserInterface or call it from elsewhere */
    /* in your code to begin issuing user interface events to panels   */
    /* RunUserInterface (); */
    return 0;

}

void __stdcall DiscardUIObjectsForDLL (void)
{
   /* Discard the panels loaded in InitUIForDLL */

   if (panelHandle > 0)
      DiscardPanel (panelHandle);
}

int CVICALLBACK Quit (int panel, int control, int event,
      void *callbackData, int eventData1, int eventData2)
{
   switch (event) {
      case EVENT_COMMIT:
         QuitUserInterface (0);
         break;
   }
   return 0;
}

int CVICALLBACK On_Off_Switch (int panel, int control, int event,
      void *callbackData, int eventData1, int eventData2)
{
   switch (event) {
      case EVENT_COMMIT:
      {
         int val;
         GetCtrlVal (panel, PANEL_ON_OFF_SWITCH, &val);
         if(val)
            SetCtrlVal(panel, PANEL_LED, 1);
         else
            SetCtrlVal(panel, PANEL_LED, 0);

         break;
      }
   }
   return 0;
}

  • Note that DllMain has the __stdcall keyword before it. This defines the calling convention for the function. In Windows 95/NT, there are two calling conventions, the C calling convention denoted by __cdecl, and the standard call convention denoted by __stdcall. The standard call replaced the Pascal calling convention used in Windows 3.1 and the Pascal calling convention is now an obsolete keyword.
  • You must know the calling convention that is set up in LabWindows/CVI. When you take the library file to the external compiler. If the calling convention is not the same, then the external compiler will not be able to determine which calling convention was used, and will not be able to recognize your function calls. To get around this problem you can hard code the calling convention in the source code like the example above. In this example the __stdcall calling convention was used. Thus, when the external compiler tries to link to the library file, it will know which calling convention was used.
  • If you are using Code Builder, make sure that you have uncommented RunUserInterface ().


3. Save the file and add it to the project by selecting Add File to Project from the menu.


4. Create a new .h file, named export.h, and add the following code to it.

#ifdef __cplusplus
extern "C" {
#endif

int __stdcall InitUIForDLL (void);  /* make sure that
                                       InitUIForDLL has the same calling
                                       conventions in the .c file*/

#ifdef __cplusplus
}
#endif

The #ifdef statements are needed for external compilers that compile .cpp file as C++ code. This forces the external compiler to compile the function prototypes as C code instead of C++ code.

5. Save this file as export.h and add it to the project by selecting the Add File to Project from the File menu.

6. Go to the project window and save the project. Then, select Create Dynamic Link Library from the Build menu. Select OK if you are prompted to set debugging to none in order to create the DLL.

7. The following Create Dynamic Link Library dialog box will appear.




8. Click on the Import Library Choices... button. On the next dialog box, select Generate Import Libraries for All Compilers and click on OK. Selecting this option will create import libraries for each of the four supported compilers in subdirectories under the project's root.



9. Click on the Change... button in the Exports section. In the DLL Export Options dialog, check the export.h file that you created and added to the project. By doing this, the InitUIForDLL function can be exported.



10. Finally, click OK to have LabWindows/CVI create the DLL and import libraries.



  • By default, the name of the DLL and import libraries that are created is the same base name as the project. In the above example, OnOff.dll is created along with five copies of OnOff.lib (import library). One import library is always created in the same directory as the DLL. That import library is created with the current compatibility mode, Visual C++. Another copy of that import library is placed in the msvc subdirectory. The three remaining import libraries are for the other three compilers and stored in their respective subdirectories (borland, symantec, watcom).
  • If you want to distribute this DLL and you know which compiler your DLL will be used with, then you just need to ship the DLL, the header file, and the import library for that particular compiler. If you do not know which compiler your DLL will be used with (which is the case most of the time), you can distribute all of the import libraries with the DLL and header file. The end users will have to decide which import library to use based on their compiler.


11. Close all open windows except the project window, saving any changes.

Once the DLL and library files are created, you can include the library in an external compiler project and use the DLL. Directions on how to use the library file and DLL in Microsoft Visual C++ and Borland C++ follows.

You should first create a new project in the development environment of your choice. And add the following source code as a .cpp file in your project. Refer to Creating New Projects and Inserting Source Code to a Project section on instruction for how create new projects and insert source code into the project.

#include <Windows.h>
#include "export.h"

int __stdcall WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                      LPSTR lpszCmdLine, int nCmdShow)
{
   InitUIForDLL();
   return (0);
}

At this point you should follow the directions for the compiler of your choice bellow.

Microsoft Visual C++
1. Choose the Files Into Project from the Insert menu again, and go to the directory where the OnOff.lib import library file created in LabWindows/CVI is located, and insert it into the Microsoft Visual C++ project.

2. Then select Options... under the Tools menu.

3. Click on the Directories property tab.

4. Select Include files in the Show directories for: list box.

5. Insert the path to the cvi\include directory and click OK.

6. Create your program and include the export.h file for the DLL as a #include at the top of your program.



7. At this point you should be able to compile and run the application.

  • The DLL created from LabWindows/CVI must be accessible to the Microsoft Visual C++ project for the executable to run. To do this you need to copy the DLL to the project directory, or to the Windows\System directory.
  • It is very important to note that when the executable is run, it needs to use the UIR file from the LabWindows/CVI project. Thus, you must copy the UIR files into the directory where the executable is located. Microsoft Visual C++, by default, creates Debug\ and Release\ directories to store executables for debug and release builds. You must copy the UIR file into the Debug\ and Release\ directories.
  • Make sure that your export.h file is in the same directory as the dll.cpp file. If necessary, make one copy in your project directory.


Borland C++
1. Right click on the .exe file in the Project window.

2. Select Add Node. You should go to the directory where you saved the import library file created in LabWindows/CVI, and insert the object file into the Borland C++ project.

3. Then select Project under the Options menu and you will see the following dialog box.



4. Select Directories under the Topic: list and add the path to the cvi\include directory and click OK. You need to separate the paths by using a semicolon.



5. At this point you should be able to compile and run the application.

  • The DLL created from LabWindows/CVI must be accessible to the Borland C++ project for the executable to run. To do this you need to copy the DLL to the project directory, or to the Windows\System directory.
  • It is very important to note that when the executable is run, it needs to use the UIR file from the LabWindows/CVI project. Thus, you must copy the UIR files into the directory where the executable is located. You must also copy the export.h file into the same directory as the .c or .cpp file.

Back to Top

Customer Reviews
1 Review | Submit your review

  - Jun 9, 2011

When I use the CVI9.0 by the method1, the Visual C+6.0 report three errors: LNK2001: unresolved external symbol _on_off_switch.

Bookmark & Share


Ratings

Rate this document

Answered Your Question?
Yes No

Submit