02-26-2014 02:59 PM
I have a DLL supplied by a hardware manufacture that I am trying to run in Labview 2012. The first function gets a handle to a device connected to the USB port.
PDEC i1d3Status_t i1d3GetDeviceHandle(unsigned int whichDevice, i1d3Handle *devHndl);
i1d3Status_t is an ENUM of error codes and i1d3Handle is defined as void* i1d3Handle.
I wrote a wrapper for that DLL
int GetDeviceHandle(int device, i1d3Handle &handle) {
i1d3Status_t m_err;
int error;
m_err = i1d3GetDeviceHandle(device, &handle);
error = m_err;
return error;
}
I can get this to work by passing the handle as adapt to type and handle by value. The next function opens the device
int OpenProbe(i1d3Handle handle) {
i1d3Status_t m_err;
int error;
unsigned char ucOEM[] = {0xD4,0x9F,0xD4,0xA4,0x59,0x7E,0x35,0xCF,0};
m_err = i1d3OverrideDeviceDefaults(0,0,ucOEM );
if(m_err == i1d3Success) {
m_err = i1d3DeviceOpen(handle);
if (m_err != i1d3Success) {
unsigned char ucNull [] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0};
i1d3OverrideDeviceDefaults(0,0,ucNull);
m_err = i1d3DeviceOpen (handle);
}
}
error = m_err;
return error;
}
This works by passing the value of the returned handle from the previous VI as an I64. There are several other functions that read parameter of the device so that I know it is open and the handle is valid but here is my problem. The next function I have to pass it a pointer here is the code.
int GetDiffuserPosition(i1d3Handle handle, unsigned char* pos) {
i1d3Status_t m_err;
int error;
m_err = i1d3ReadDiffuserPosition((i1d3Handle)handle, &pos);
return error;
}
This code works in VC++ but not in Labview I get an 1097 error from the VI. So passing the handle as a I64 will work as long as I don't pass another pointer along with it because this code will work.
unsigned char GetDiffuserPosition(i1d3Handle handle) {
i1d3Status_t m_err;
unsigned char pos;
m_err = i1d3ReadDiffuserPosition((i1d3Handle)handle, &pos);
return pos;
}
I even tried to dumb down the function
int GetDiffuserPosition(i1d3Handle handle, int* x) {
*x = 5;
return 0;
}
and still get the 1097 error. Any suggestions would be welcome
Solved! Go to Solution.
02-26-2014 06:00 PM
No need to make this so complicated. You don't need the wrappers around the DLL functions. Configure the device parameter as a pointer-sized integer passed by pointer. If you look at the help you'll see that this is effectively what you're doing already, since when you configure a Call Library Function Node parameter as Adapt to Type with a scalar input, the scalar is passed by reference and the Data Format parameter is ignored. In all the following functions, pass that same value as a pointer-sized integer passed by value, as you're already doing.
The problem most likely with the pos parameter is that you are not allocating it beforehand. Can you show your LabVIEW code, and the configuration of the call library function node? If "pos" is a string, then you need to preallocate it before passing it to the function. Generally the easiest way to do this is to initialize an array of U8, then use byte array to string (or, just pass the pos parameter as a byte array). Make sure you allocate enough space to meet the requirements of the DLL. In the "dumbed down" version, did you pass the integer parameter "x" by pointer?
02-27-2014 08:17 AM
I had to write the wrapper because since the original DLL returned the error as an enum the Labview call would always return a 0 so I have to convert the i1d3Status_t variable to a int and return that from my wrapper DLL. It seemed the problem was that Labview could not process the i1d3Handle varible which was difined as a void* when it was passed with another pionter. So I could get the handle by using the adapt to type option and in the following calls pass the handle by value as a U64. Labveiw was okay with me passing a U64 with the same value as the i1d3Handle as long as I didn't pass another pointer with it, then I would get the 1097 error. I think I have the problem solved by changing the wrapper DLL to accept a long long instead of the handle and then casting it to a i1d3Handle within the DLL wrapper.
int GetDeviceHandle(int device, long long &handle) {
i1d3Status_t m_err; //create error enum
int error;
i1d3Handle i1d3dev; //create device handle varible
m_err = i1d3GetDeviceHandle(device, &i1d3dev); //get the device handle from the other DLL funciton
*handle = (long long) i1d3dev; //cast the device handle to a U64 pointer
error = m_err; //return the error
return error;
}
for Labview call
return_value is int
parm1 u32 pass value
parm2 u64 pass pointer to value
int GetDiffuserPosition(long long handle, unsigned char* position) {
i1d3Status_t m_err; //for error handling
int error;
i1d3Handle i1d3dev; //create device handle varible
i1d3dev = (i1d3Handle) handle; //cast the device handle with the long long handle
unsigned char pos; //pos to be passed to the i1d3ReadDiffuserPosition function as a pointer
m_err = i1d3ReadDiffuserPosition(i1d3dev, &pos); //this function is in a different DLL
*position = pos; //assign the value of the pos to position
error = m_err; //cast the error as a int
return error;
}
for Labview call
return_value is int
parm1 u64 pass value
parm2 u8 pass pointer to value
This seems to work so I will probably go with it.
02-27-2014 11:33 AM
Are you sure you aren't doing something simple wrong, for example configuring the Call Library Function Node with the wrong calling convention? I wonder if your DLL is simply translating calling conventions for you.
When you didn't use the wrapper, and did not receive a correct return value from the enumeration, how did you configure the return value? What size integer? Did you experiment with multiple options?
There is definitely no problem with passing multiple pointer parameters to a function - as far as LabVIEW is concerned, they're all just numbers. I can't figure out what you're doing wrong from your comments, but if you attach your LabVIEW code and the header file with the function prototypes, I'll take a look
02-27-2014 02:02 PM
I have attached header file for the DLL. I also have attached a CPP file for a console program.
As far as the labview code I am simply trying to create a library in labview for the fuctions in the DLL so they were just the the Library call with error checking. Basically a Error In control to a case structure to check for an error in, the library call with the error going to a sub VI that updates the errror out with the code and text for the failure.
The error returned from the function is 0 for success or either a postive number less than 100 or a negative greater than -1000 therefore it has to be a signed integer.
At this point since I have gotten the functions to work with my wrappers I probably am not going to spend a lot of time on getting the supplied DLL to work by itself, but thanks for your help.
02-27-2014 03:22 PM
This snippet should be the correct Call Library Function Node for the Initialize and Read Diffuser functions. Give it a try? (If you're not familiar with snippets: this image is code. Drag it to your desktop to save a copy, then drag it into a block diagram. You'll need to fix the path to the DLL of course.)
02-28-2014 05:38 AM
From a brief look at the header file, I think this might not work as intended as there is also a i1d3DeviceOpen() function that probably needs to be called before one can use other functions on that handle?
02-28-2014 06:49 AM
It works but I am now confused as to why mine didn't work it is pretty much the way I had it except I configured the path in the call but that shouldn't make a difference. I don't have the VI I started with since I have made changes. The only thing I may have had different is that in the getDeviceHandle I think I had the handle param set to adapt to type then wired to a I64 constant, but I tried this and it still works. Oh well got lots of practice writing DLL's though. How did you create that snippet? Do you drag the code into a picture editor and save as a png file?
02-28-2014 07:02 AM
@lkprather wrote:
[...] How did you create that snippet? Do you drag the code into a picture editor and save as a png file?
Just select the code you want to have in the snippet and select Edit >> Create VI Snippet from Selection.
Norbert