07-02-2013 08:42 AM
Hello,
how do I dereference an array of strings from a memory allocated inside DLL ?
So far I have to concate the array into single string using special character, use "GetValueByPointer.xnode" and reconstruct the array using spreadsheet string to array VI.
This is not a good idea, since the string might contain the special composing character itself, so the data might get corrupt.
I was thinking about retrieving an array of string lengths + normal concate with no special character, and rebuild the array using the lengths. Such solution (so does the one before) seems "not good" and I am looking for some more straightforward one.
07-03-2013 02:18 AM
Hi Bublina!
There's an existing community example for returning variable length string arrays from inside a DLL, you can find it here. It works using an array of pointers to get the string elements. Does this wok for your use case?
Best regards:
Andrew Valko
NI Hungary
07-03-2013 02:55 AM - edited 07-03-2013 03:14 AM
Thanks for answer, I was searching for a good solution, but found none. All these proposed methods do work, but need some sort of workaround I would like to avoid for sake of code management and readability.
Just to clarify things, this is the current solution I use for the desired function.
Function header :
int32_t FFMPEG_stream_info(int32_t *session, uint64_t *InfoPtr)
LabView :
This works fine, but I would like to allocate and dereference a LabVIEW string array.
Edit: It would be cool, if there was some example on usage of these functions here
07-03-2013 06:09 AM - edited 07-03-2013 06:12 AM
@Bublina wrote:
Thanks for answer, I was searching for a good solution, but found none. All these proposed methods do work, but need some sort of workaround I would like to avoid for sake of code management and readability.
Just to clarify things, this is the current solution I use for the desired function.
Function header :
int32_t FFMPEG_stream_info(int32_t *session, uint64_t *InfoPtr)LabView :
This works fine, but I would like to allocate and dereference a LabVIEW string array.
Edit: It would be cool, if there was some example on usage of these functions here
The prototype you show definitely does not return a buffer pointer but instead accepts a pointer to a single value of uInt64 or maybe an array of uInt64. As such the function CANNOT return a pointer that would need to be read with GetValueByPointer.xnode, but you either pass a uInt64 value by reference or a uInt64 C array pointer to the function. Which is not clear from the function prototype alone.
In either case you have to make sure that the function either really expects a single uInt64 passed by reference or that the array you pass in is preallocated with as many elements as the function expects to fill in.
As to the examples about the functions you mention. Those are C functions and meant to be called from C code not directly from LabVIEW. Also some of the "functions" in that list are in fact C macros and can only be called from C code.
07-03-2013 07:00 AM
My code worked fine. I do not really understand this:
@rolfk wrote:
The prototype you show definitely does not return a buffer pointer but instead accepts a pointer to a single value of uInt64 or maybe an array of uInt64. As such the function CANNOT return a pointer that would need to be read with GetValueByPointer.xnode, but you either pass a uInt64 value by reference or a uInt64 C array pointer to the function.
As of what I am aware of, the GetValueByPointer.xnode takes as pointer parameter the pointer value, so I get this value by getting the pointer back like this:
*InfoPtr = (uint64_t)StreamInfo;
I do not have the original code, but this should handshake the the function prototype I posted earlier. The function itself returned error number, so I was passing the pointer value as pointer 🙂
This was the node config.
The diagram:
The output I was getting:
While dubugging the DLL, MicroSoft studio showed just common LabView exceptions, but no segfaults. So I believe I had this assembled OK.
Lastly, I decided to drop the idea of returning array of strings (2D char array), but I am instead making the underlying for loop that creates the array in LabVIEW, this solves the problem.
The only question I have now: Does the moveblock function free the original memory ?
07-03-2013 07:16 AM
I have read up this thread and it sheds enough light, so thank you.
07-03-2013 08:12 AM - edited 07-03-2013 08:15 AM
@Bublina wrote:
*InfoPtr = (uint64_t)StreamInfo;
This is evil! The function returns some arbitrary datatype disguised as a uInt64 value. This API should be shot on the spot and banned into the realms of evil creations.
Why not declare the function to return the datatype of StreamInfo instead? Without knowing the exact datatype of StreamInfo any work on a LabVIEW diagram with the returned data is at best guesswork, but more likely a timebomb to explode rather sooner than later.
The only question I have now: Does the moveblock function free the original memory ?
MoveBlock() nor ValueByPointer() deallocate anything in the pointers passed to them. A function only can consider to release memory passed into it, when knowing exactly which API was used to create that memory pointer. This goes much further than knowing if it should use free(), delete, DSDisposePtr(), or HeapAllocFree() but also requires knowledge of the exact C runtime library and version that was linked into the code that created the memory block.
Also, from the looks of it I would think FFMPEG would be very unhappy if someone tried to deallocate its internal StreamInfo data behind its back, but that is difficult to say from your single source code line. This would be part of the contract this API requires from its caller and therefore should be explicitedly documented in the API documentation.
07-03-2013 09:00 AM - edited 07-03-2013 09:02 AM
I do not understand your point.
NI makes a VI, that takes as a parameter a pointer value in form of an uint64_t. So obviously, you need to take your pointer value and cast it to (uint64_t) in order to feed it into the function.
The programmer that makes the cast obviously knows, what is he casting from to what and what and where to retrieve.
And yes, it is stupid and I do not like it either, if you have the correct solution, you are very welcome to post it.
Maybe you are confused with StreamInfo, that is just a (char *) I allocated and filled myself in the best programming manners possible. Now I only attempt to retrieve the data in it from LabView.
07-03-2013 09:08 AM - edited 07-03-2013 09:09 AM
If it is a char* then pass it as char* too. Then you can forget about complicated ValueByPointer() and MoveBlock() acrobatics altogether.
Change your function to
int32_t FFMPEG_stream_info(int32_t *session, char *InfoPtr, int32_t len);
Then configure the Call Library Node to make sure the InfoPtr parameter has a minimum size of len bytes (or allocate the according buffer explicitedly on the diagram. Inside the function make sure you only copy as many bytes into the buffer as your len parameter indicates.
And if you think this is bad performance because of the potential of having to allocate a bigger buffer than the function really needs think again. ValueByPointer() does have to do a lot more work than that.
07-03-2013 09:20 AM
Good you are no longer furious.
I wanted to try GetValueByPointer, because I found it in some community document and it allowed to dereference string allocated inside DLL, so I liked the solution. As I need to keep trace of the original pointer (I didnt figure this out earlier) in order to deallocate the memory pointed at, I still need to make at least 2 consecutive DLL calls. So I learned my lesson, that it is easier to ask about the size through one DLL call, let LabView allocate the memory and fill the memory in another DLL call. No need for those memory VIs as you stated.
In this thread, I am basicly looking for the possibility, to allocate inside DLL a memory, that will labview treat, like it was allocated by itself. That means configure the library node in a manner, that it says to labview compiler: new memory allocated inside DLL, the way you are used to, feel free to deal with it the same.
This idea of doing this happened to exist in my brain since I looked at the memory manager functions and support functions.