LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

LabView LStrHandle Memory Allocation

Solved!
Go to solution

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

 

0 Kudos
Message 1 of 9
(5,487 Views)

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

0 Kudos
Message 2 of 9
(5,469 Views)
Solution
Accepted by topic author sayo9394

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;
}
Message 3 of 9
(5,449 Views)

Hi Sayo,

Thanks for providing the code!
Helped a lot and saved time...

 

Regards

 

Juergen

--Signature--
Sessions NI-Week 2017 2016
Feedback or kudos are welcome
0 Kudos
Message 4 of 9
(4,839 Views)

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.

Rolf Kalbermatter
My Blog
0 Kudos
Message 5 of 9
(4,828 Views)

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

--Signature--
Sessions NI-Week 2017 2016
Feedback or kudos are welcome
0 Kudos
Message 6 of 9
(4,818 Views)

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);

 

 

Rolf Kalbermatter
My Blog
Message 7 of 9
(4,812 Views)

Hi,

 

What's your recommondation to do this task?

 

Regrads

Juergen

 

--Signature--
Sessions NI-Week 2017 2016
Feedback or kudos are welcome
0 Kudos
Message 8 of 9
(4,798 Views)

Hi Rolf,

Forgett the upper reply!!!
I have not realized your commends in the code at all.

I agree you have reserve memory for the NULL termination character!

 

Thanks for pointing out.

 

Juergen 


--Signature--
Sessions NI-Week 2017 2016
Feedback or kudos are welcome
0 Kudos
Message 9 of 9
(4,791 Views)