06-29-2011 12:26 AM
Hi,
I'm currently working on a simple VI which all it does is call a DLL function whose prototype is the following;
int initialize(LStrHandle, int , int);
After setting up the library call, building the VI, and setting up the proper inputs following the Call DLL.vi example, running the VI crashes labview without any error codes! It kills the process all together.
So since I wasn't getting any error messages back or crash dump, I decided to test the DLL call via C code. So I wrote the following simple C++ code (c code actually, compiled in a cpp file under visual studio c++ 2010) ;
#include "C:\Program Files\National Instruments\LabVIEW 2009\cintools\extcode.h" #include <stdio.h> #include <windows.h> int main() { int length; HINSTANCE ldll; LStrHandle inputStr; char strTemp[50] = "utility.jar"; length = strlen(strTemp); //inputStr=(LStrHandle)DSNewHandle(sizeof(int32) + length * sizeof(uChar)); *inputStr = ( LStrPtr )malloc(sizeof(int32) + length * sizeof(uChar)); // Empty the buffer memset(LStrBuf(*inputStr),'\0',100); // Fills the string buffer with errorString sprintf((char*)LStrBuf(*inputStr),"%s",strTemp); // Inform LabVIEW string handle about the size of errorString LStrLen(*inputStr)= length; int (*initialize)(LStrHandle, int , int); ldll = LoadLibrary("Interface.dll"); if(ldll>(void*)HINSTANCE_ERROR) { initialize = (int (*)(LStrHandle, int , int))GetProcAddress(ldll, "initialize"); if (pisces_initialize==NULL) return 0; else { printf("return code: %d", initialize(inputStr, 3, 0)); } } return 0; }
The problem is that the function "initialize" takes an LStrHandle , So i have to use "extcode.h". I'm having problems trying to allocate some memory for it. I can't use DSNewHandle since this process isn't being called by labview, and malloc doesn't seem to work, I keep getting <bad pointer> Access violation reading location 0xcdcdcdcd....
Any help here will be greatly appreciated.
I'm running;
- Win XP sp3
- Labview 2009 Version 9.0
- VC++ 2010 Express
- Also tested with cygwin
cheers,
Simon
Solved! Go to Solution.
06-29-2011 02:40 PM
Tough stuff, I'm not an expert on this. So just some hints where I would look for a sulution:
1. If your good at C, code a dll that returns you the LStrHandle and also deallocs the memory. Then call this from LV. Avoid C++ if possible, use plain C. As an alternative, just create a wrapper of the function you call that is LabVIEW-friendly.
2. There are some functions exposed by the LabVIEW.exe that allow for memory operations. Search the LabVIEW.h file and there should also be a documentation available.
3. If you search this forum, head for RolfK's posts. He's the best in this field.
4. As you already realized, prepare for crashing LabVIEW (save often, backup the project).
Good luck.
Felix
06-30-2011 07:59 PM
It's Fixed. The following explanation applies to this;
typedef struct { int32 cnt; /* number of bytes that follow */ uChar str[1]; /* cnt bytes */ } LStr, *LStrPtr, **LStrHandle;
So I haven't done C programming in a while and I knew that the error was in how I was allocating the memory to LStrHandle (which is a Pointer to a Pointer).
An easy solution was to allocate memory to LStrPtr, which if you look at the above struct, is a pointer to the struct LStr. Then when valid memory has been returned, simply point LStrHandle to the address of LStrPtr.
Here's the code;
#include "C:\Program Files\National Instruments\LabVIEW 2009\cintools\extcode.h" #include <stdio.h> #include <windows.h> int main() { int length, error_code; HINSTANCE ldll; unsigned int* a_apiVersion = (unsigned int*)malloc(sizeof(unsigned int)); LStrHandle inputStrHndl; LStrPtr inputStr; unsigned int version = 3, reserved = 0; char strTemp[] = "utility.jar"; length = strlen(strTemp); //allocating memory for size + number of char in the strTemp inputStr = ( LStrPtr )malloc(sizeof(int) + length * sizeof(unsigned char)); // Fills the string buffer with errorString sprintf( (char *)(inputStr)->str ,"%s" ,strTemp); // Inform LabVIEW string handle about the size of String (inputStr)->cnt= length; inputStrHndl= &inputStr; int (*initialize)(LStrHandle, unsigned int , unsigned int); ldll = LoadLibrary("Interface.dll"); if(ldll>(void*)HINSTANCE_ERROR) { initialize = (int (*)(LStrHandle, unsigned int , unsigned int))GetProcAddress(ldll, "initialize"); if (initialize==NULL) return 0; else { // initializing n9-pen printf("\n******* [DEBUG] line %d > calling initialize(inputStrHndl, version, reserved)*******\n", __LINE__); error_code = initialize(inputStrHndl, version, reserved); printf("error code: %d\n", error_code); } } return 0; }
02-12-2014 01:33 AM
02-12-2014 03:25 AM
Actually something is fishy here. If the DLL makes use of labview.lib to call into the LabVIEW kernel (LV runtime engine or LV development system depending on from where it is called) then it should also bail out with the "labview.lib is not called from within a LabVIEW process" message, as soon as it tries to call any LabVIEW manager function to deal with the LStrHandle that you passed in. If it implements the LStrHandle handling itself by emulating LabVIEW manager functions, then it will certainly corrupt the LabVIEW memory when you call this DLL with real LabVIEW data from a LabVIEW diagram.
Ok looking at the code further it is obvious that the LStrHandle parameter is used as an input parameter and the DLL obviously does not do anything with it but just reading the data from it. So no need to call any LabVIEW manager functions in there, but it is not something you can generalize. It works since the DLL does not attempt to resize the string nor deallocate it in any way, but that is not the general use case of such parameters. It would have been easier for the DLL developer to just declare that parameter as char *. That way the DLL is also callable from any C program AND the only thing necessary to do in LabVIEW is to make sure the parameter is configured as C String Pointer in the Call Library Node. Much more standard for most C programmers and no disadvantage for LabVIEW users of that DLL.
02-12-2014 04:06 AM
Hi Rolf,
in may task a i am not the devloper of the DLL. LabView is the "Devopler".
LabView is providing me some vi's for my c++ application as wrapper dll.
The prototype of LabView's function call is only providing LStrHandle. --> no change you have to use this.
The upper code will "cast" from char* to LStrHandle and both Visual Studio and LabView are happy now.
Regards
Juergen
02-12-2014 04:16 AM - edited 02-12-2014 04:25 AM
If you let LabVIEW create the DLL, then make sure to configure the parameter in the DLL Build configuration as C String pointer. That makes things a lot easier for everyone. The DLL thunk created by the LabVIEW DLL Builder will have a little more overhead in converting the incoming C String into a LabVIEW String, but it makes life for everyone a lot easier especially if you intend to have the DLL called by non LabVIEW code.
And a few other comments:
First, you can't really cast a char* to a LStrHandle. C has no idea how to do that properly for you, so you would end up with a mess.
Second, the example code has a very serious flaw, aside from the fact that it will only work for a DLL function that uses a LStrHandle parameter but not a LStrHandle * one and won't attempt to resize it in any way.
unsigned int version = 3, reserved = 0; char strTemp[] = "utility.jar"; length = strlen(strTemp); // !!!!!! Determines the string length without terminating NULL character //allocating memory for size + number of char in the strTemp inputStr = ( LStrPtr )malloc(sizeof(int) + length * sizeof(unsigned char)); // !!!!!! Allocates a buffer for the LabVIEW cnt element plus the string without NULL char // Fills the string buffer with errorString sprintf( (char *)(inputStr)->str ,"%s" ,strTemp); // !!!!!! Formats a C string into the buffer adding a terminating NULL char at the end, writing over the end of the allocated buffer // Inform LabVIEW string handle about the size of String (inputStr)->cnt= length; inputStrHndl= &inputStr; int (*initialize)(LStrHandle, unsigned int , unsigned in
Last but not least, before your exit from the C code make sure you deallocate the buffer properly or you end up creating a memory leak!
free(inputStr);
02-12-2014 04:31 AM
02-12-2014 05:23 AM