From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

returning a C string from a win32 dll

I have found that changing the Calling Convention will sometimes fix a situation where the program crashes after returning from the DLL call.  The two choices are C and Standard (WINAPI).  Even though you are calling a WINAPI, try both conventions.
- tbob

Inventor of the WORM Global
0 Kudos
Message 11 of 15
(879 Views)
I use the C calling convention. The program crashes imediatly if I use the WINAPI call method.

But, the problem persists if when I try to get the string that had to be returned in the cluster, but with all other variables types, it works. Is there a different thing that I have to do when I try to get strings?

Thank you in advance.


0 Kudos
Message 12 of 15
(877 Views)

I'm not sure if this will work, but give it a try.  For a string in a main cluster, when inputting the cluster to a DLL, extract the string from the main cluster, change the string to a byte array, change the array into a subcluster, rebuild the main cluster with the subcluster and the rest of the original cluster.  Only drawback is that you must know how many characters there are in the string.  The Array to Cluster function would have to be sized to be the number of characters in the string.  The default setting is 9.

Message Edited by tbob on 07-17-2006 01:53 PM

- tbob

Inventor of the WORM Global
0 Kudos
Message 13 of 15
(874 Views)


@tbob wrote:

I'm not sure if this will work, but give it a try.  For a string in a main cluster, when inputting the cluster to a DLL, extract the string from the main cluster, change the string to a byte array, change the array into a subcluster, rebuild the main cluster with the subcluster and the rest of the original cluster.  Only drawback is that you must know how many characters there are in the string.  The Array to Cluster function would have to be sized to be the number of characters in the string.  The default setting is 9.

Message Edited by tbob on 07-17-2006 01:53 PM


First you say you are calling a Win32 API function then you are using C calling convention. These two things are almost  exclusive. Except for a few very special functions Microsoft is always using STDCALL for all its APIs. Most likely when you say you interface to Win32 API you do not mean this in the true sense as being a Windows API itself but just some arbitrary DLL that is compatible with Win32.

As to if above solution will work it depends. There are fundamentally two ways in C to put a string in a cluster. The first looks like:

struct {
    double val;
    char string[10];
} name

and is basically what you can create with above solution. You need to make sure to configure the array to cluster function to contain the right amount of elements (in our example that would be 10).

The second is of the form:

struct {
    double val;
    char *string;
} name

and can only be created in LabVIEW with some through fundamental understanding of C datatypes and some extra magic with extra function calls. To explain how to do this goes to far here and in fact is only really useful for someone understanding C datatypes quite well anyhow. So for the average user the second form is not directly interfaceable from LabVIEW and needs a wrapper DLL.

It's up to you to see which form your API uses or tell us what API you exactly call. And this thread was actually captured for a not completely correct question. The original was about returning a string as return value of a function. Your question is about passing a cluster containing a string as function parameter. Creating your own thread would have possibly helped to make it more clear and also possibly prompted you to provide more specific information in the first post already. And of course there are several threads on this forum that deal with just this topic already!!

Rolf Kalbermatter

Message Edited by rolfk on 07-18-2006 11:05 AM

Rolf Kalbermatter
My Blog
0 Kudos
Message 14 of 15
(863 Views)


@Klaus Vestergaard Kragelund wrote:

Some C code he refers to:

> CStr __stdcall SendRequest(long intComPort, CStr strID, CStr strType,
> CStr strParam, CStr strData, CStr strReturn)
> {
> LPVOID lpMsgBuf;
> char strErrMsg[1024];
> char strComPortName[25];
> char strRequestMessage[50];
> char strCheckSum[2];
>
> strcpy(strReturn, "");
>
> sprintf(strErrMsg, "Here is the function input: ComPort=%d, ID=%d,
> Type=%s, Parameter=%d.\n", intComPort, strID, strType, strParam);
> Log(strErrMsg);
>
> //Validate Input
> if (!ValidateInput(strID, strType, strParam, strData, strErrMsg))
> {
> FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
> FORMAT_MESSAGE_FROM_SYSTEM |
> FORMAT_MESSAGE_IGNORE_INSERTS,
> NULL,
> GetLastError(),
> MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
> (LPTSTR) &lpMsgBuf,
> 0,NULL);
> sprintf(strReturn,"%s:\n%s\n", strMessage, lpMsgBuf);
> LocalFree( lpMsgBuf );
> Log(strReturn);
> return strReturn;
> }
>

Off-hand - in the line just above "return strReturn". You are returning the
pointer of strReturn. But shouldn't the prototype be:

> CStr __stdcall SendRequest(long intComPort, CStr strID, CStr strType,
> CStr strParam, CStr strData, CStr *strReturn)

and without the return of strReturn. You have allready supplied the pointer
in the last argument - so why are you also using "Return" ?. I don't know
the CStr type - but I'm guessing it is a string.


It's quite late but I still want to comment on this. Basically it does not matter that you pass the string pointer as parameter already if you want to return it as function parameter or if the string is located on the stack or in a constant data segement for instance.

What is not really compatible with LabVIEW (and most other programming environments, even C without a big NOTE to that fact in the function documentation) would be if the function allocates the string pointer on the heap itself and then returns it as function return value.

On return of a function that returns a string, LabVIEW creates a new string  long enough to hold the data and copies its contents over. There is no other way since function return values that are strings are normally located on the stack or in a constant data segment and LabVIEW can not use this memory at all for further processing. But by doing so LabVIEW will inevitably leak memory if the string was actually allocated from the heap by the function.

In this case as the OP had, just make sure you allocate a long enough buffer in the LabVIEW diagram (Initialize Array with U8 and optional Byte Array String will do fine here) and pass it as last parameter. You could configure the return value as C string in the Call Library configuration dialog but you don't really need to since the same information is also available in the right terminal of the last parameter of the Call Library Node, that holds the actual buffer too. Not configuring the return value as string will actually save one buffer allocation and copy LabVIEW would otherwise have to do for the function returned string, but that is all.

Rolf Kalbermatter
Rolf Kalbermatter
My Blog
0 Kudos
Message 15 of 15
(859 Views)