01-20-2013 07:32 PM
So, I am using an Opal Keyy XEM3005 board.
Depending on the documentation I read, this board has a native ANSI C interface with a C++ wrapper.
In their forums, they say to rename the ".cpp" file to "c", and then go forward with calling the default constructor & keep track of the pointer. Their functions are all in an externally loadable DLL.
Well and good.
Their API documentatin is available here: http://www.opalkelly.com/library/FrontPanelAPI/
I have written a REALLY simple app to ease my way in - it does nothing more than allow the user to throw a switch, and when this happens, it goes off to connect to the board:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <cvirte.h>
#include <userint.h>
#include "Try1.h"
#include "XEM.h"
#define _WIN32_WINNT 0x0501
//#define _WIN32
#include <windows.h>
static int panelHandle;
static okFrontPanel_HANDLE XEM_Device;
int __stdcall WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
if (InitCVIRTE (hInstance, 0, 0) == 0)
return -1; /* out of memory */
if ((panelHandle = LoadPanel (0, "Try1.uir", PANEL)) < 0)
return -1;
DisplayPanel (panelHandle);
RunUserInterface ();
DiscardPanel (panelHandle);
return 0;
}
int CVICALLBACK Connect (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
int Value = 0;
switch (event)
{
case EVENT_COMMIT:
GetCtrlVal(PANEL, PANEL_CONNECT_SWITCH, &Value);
SetCtrlVal(PANEL, PANEL_CONNECT_LED, Value);
if( Value )
XEM_Connect(XEM_Device);
else
XEM_Disconnect(XEM_Device);
break;
}
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;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This, of course, works fine by itself (with empty _Connect() and _Disconnect() functions)
I then started working with the XEM_Connect function.
The first step is to run their LoadDLL function as such:
int XEM_Connect ( okFrontPanel_HANDLE XEM_Device )
{
int NoDevices = 0; // Number of devices attached to the PC
// Load the DLL (?)
// Load the FrontPanel DLL
if (FALSE == okFrontPanelDLL_LoadLib(NULL))
{
printf("Could not load FrontPanel DLL\n");
exit(-1);
}
return XEM_SUCCESS;
}
And this would compile and run just fine.
Now, when I added the functions to start trying to get info about the device, I started getting "missing prototype" errors.
int XEM_Connect ( okFrontPanel_HANDLE XEM_Device )
{
int NoDevices = 0; // Number of devices attached to the PC
// Load the DLL (?)
// Load the FrontPanel DLL
if (FALSE == okFrontPanelDLL_LoadLib(NULL))
{
printf("Could not load FrontPanel DLL\n");
exit(-1);
}
// Find out how many devices are attached
XEM_Device = okFrontPanel_Construct( );
// XEM_Device = okCFrontPanel( void );
// NoDevices = GetDeviceCount( );
printf("%d OK devices attached\n", NoDevices);
// Call the contructor?
// okCFrontPanel ();
return XEM_SUCCESS;
}
Now, I searched the forums and found the bits about adding #define _WIN32_WINNT 0x0501 prior to inclusion of windows.h. Did that. No joy.
Then I searched some more and found the bit about changing the build options to uncheck the "prototype required" flag.
Done.
This seemed to work at first (the above code could be built with no errors, and appeared to run).
So I thought maybe I had it, and added the next line, so:
int XEM_Connect ( okFrontPanel_HANDLE XEM_Device )
{
int NoDevices = 0; // Number of devices attached to the PC
// Load the DLL (?)
// Load the FrontPanel DLL
if (FALSE == okFrontPanelDLL_LoadLib(NULL))
{
printf("Could not load FrontPanel DLL\n");
exit(-1);
}
// Find out how many devices are attached
XEM_Device = okFrontPanel_Construct( );
OpenBySerial( XEM_Device, "UaLgzvVpBJ" );
// XEM_Device = okCFrontPanel( void );
// NoDevices = GetDeviceCount( );
printf("%d OK devices attached\n", NoDevices);
// Call the contructor?
// okCFrontPanel ();
return XEM_SUCCESS;
}
Now it doesn't complain about no prototypes (duh), but instead I get linker errors:
Undefined symbol '_OpenBySerial@0' referenced in "XEM.c".
So, dredging through the .h and .c files, I found a couple of things:
in the okFrontPanel.c file I found the following:
okDLLEXPORT ok_ErrorCode DLL_ENTRY
okFrontPanel_OpenBySerial(okFrontPanel_HANDLE hnd, const char *serial)
{
if (_okFrontPanel_OpenBySerial)
; return((*_okFrontPanel_OpenBySerial)(hnd, serial));
return(ok_UnsupportedFeature);
}
In the okFrontPanel.h file I found:
and also:
okDLLEXPORT ok_ErrorCode DLL_ENTRY okFrontPanel_OpenBySerial(okFrontPanel_HANDLE hnd, const char *serial);
So, I see them in the .h & .c files, but the linker is bombing out.
I smell a problem with actual code to link being in the DLL... How do I resolve this, any ideas? Or am I doing something so stupidly (and obviously) wrong that I'm being blinded to it?
01-21-2013 12:06 PM
Hi tomii,
My suspicion is that these issues are due to using a C++ dll in a C environment. There are inherent challenges with performing such an operation as you have to make sure all your parameters and settings are correct.
I also could not find the documentation that the Opal Kelly dll is ANSI C but it sounds like you can use this in C with some reconfiguration. I would recommend using their forums to get more information on what steps need to take place to get things working in ANSI C.
From the information you provided, I did find some resources on the missing prototype error and undefined symbol issue with the linker.
For the missing prototype I found a thread of someone actually using LabWindows and seeing this compiler error you may want to look at
http://bytes.com/topic/c/answers/695019-missing-prototype
I found a few cases where using a function definition of int func(void) removes such issue when int func() does not.
Another link I found that may be worth a look can be found at http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html
It gives some good pointers to mixing C and C++ code. Some of it may be applicible in your case.
And, a resource for your undefined symbol linking issue.
http://www.cprogramming.com/tutorial/compiler_linker_errors.html
Hopefully these resources will give some context for getting things compiling and working with your dll.
Good luck!
01-21-2013 08:14 PM
Hi! Tomii,
1) It might not be that simple just to rename the ".cpp" file to ".c" and hope it'll work flawlessly. Usually, it won't.
2) Use Dependency Walker (http://www.dependencywalker.com/) to check the functions in the DLL file. Make sure the function names are exported properly and are not mangled (such as a function name like: FPi_i?YAHPZ@). If so, you will need more detailed info from the vendor to know how to call the functions in the DLL correctly. See more at http://forums.ni.com/t5/LabWindows-CVI/Problem-with-DLL-import-library-function-names/m-p/143255#M11...
3) You probably need to re-write the header file (.h) to make it work with C program. The original header file written for the ".cpp" program may not work seamlessly just by including them in to your code.
01-31-2013 12:44 PM
All solved. Turns out that when using straight C, you need to append "okFrontPanelDLL_" to the beginning of all the functions.