04-01-2022 04:08 AM - edited 04-01-2022 04:12 AM
Hi,
I have a LabVIEW program that communicates via TCP/IP with an electronic device. The messages exchanged are binary and serialized. To deserialize them, I call a Qt DLL that takes the encoded message as input and returns the decoded message.
In Qt, we use a QByteArray for binary messages. However, LabVIEW does not know this type of data. So I decided to exchange strings ( Qt and LabVIEW know how to convert byte arrays to strings).
The problem is that the CLFN does not return any data. Here is more information :
I have to decodedMsg : 1 in string, 1 in hex.
Here myDLL.dll :
std::string* myDLL::decodeMsg(std::string* receivedMessageString)
{
QByteArray receivedMessage(receivedMessageString->c_str(), receivedMessageString->length());
// Deserialize
std::string response(receivedMessage.constData(), receivedMessage.length());
return &response;
Just simply DLL that return what I send.
The response :
CLFN configuration :
I don't understand why I can't get a response.
Thanks for help.
Solved! Go to Solution.
04-01-2022 05:43 AM
LabVIEW doesn't know about a std::string either... Std is a C++ namespace, not a global standard.
Pass an array of chars or c_str to the function.
04-04-2022 06:39 AM
Thank you for your answer.
I already pass a CStr to my DLL.
I could pass an unsigned char array to my DLL (to an unsigned char *) but I could not receive such an array because Labview can only retrieve String and Numerics.
How could I pass my Byte Array to a QByteArray (DLL) and retrieve a String in LabVIEW?
Thanks for your help.
04-04-2022 07:07 AM
@syuiopwdfghj wrote:
and retrieve a String in LabVIEW?
I don't know about the QByteArray...
But if you want to pass a string or array from a DLL, you usually pass a big enough buffer as an input, fill it, and then read the results in the caller.
Passing data created in the dll is a problem, because there's no stable way to deallocate the data. The dll created it, but the caller wouldn't know how to deallocate it.
So, pass a large enough buffer to the dll (pointer and size) and use that in the dll...
04-05-2022 05:07 AM - edited 04-05-2022 05:16 AM
@syuiopwdfghj wrote:
I already pass a CStr to my DLL.
That is not what you showed in your code.
I could pass an unsigned char array to my DLL (to an unsigned char *) but I could not receive such an array because Labview can only retrieve String and Numerics.
LabVIEW strings are internally unsigned char arrays but wrapped inside a handle. But if your DLL says that it receives char* or unsigned char *, doesn't really matter other than an interpretational difference.
So a possible way to solve your problem is like this:
int decodeMsg((unsigned) char *receivedString, (unsigned) char *responseString, size_t *size)
{
QByteArray receivedMessage(receivedString, strlen(receivedString);
// Deserialize
std::string response(receivedMessage.constData(), receivedMessage.length());
if (*size <= response.length())
return buffToSmall;
strncpy(responseString, response.c_str(), response.length() + 1);
*size = response.length();
return noError;
Most likely you can also get rid of the creation of the response std:string variable by directly mem-copying the bytes from the QByteArray const buffer into the C string buffer and appending an explicit 0 termination character yourself to the string.
A very fancy but LabVIEW specific function (that requires to also link your DLL to labviewv.lib in your cintools directory and include at least extcode.h from the same directory) would be this:
MgErr decodeMsg(LStrHandle receivedString, LStrHandle *responseString)
{
QByteArray receivedMessage(LStrBuf(*receivedString), LStrLen(receivedString);
// Deserialize
MgErr err = NumericArrayResize(uB, 1, (UHandle*)responseString, receivedMessage.length());
if (!err)
{
MoveBlock(receivedMessage.constData(), LStrBuf(**responseString), receivedMessage.length());
LStrLen(**responseString) = receivedMessage.length();
}
return err;
}
04-14-2022 05:19 AM
I prefer your last solution. Only extcode.h does not know my compiler (MinGW in QtCreator). You seem to know QByteArray so I think maybe you know how to include extcode.h correctly in a Qt DLL project ?
Thank you for your help !
04-14-2022 06:11 AM - edited 04-14-2022 06:48 AM
No I don't know QTByteArray at all. Everything in that code is just inferred from your previous example and generic C++ object knowledge.
If your compiler does not define Microsoft Visual C compatible compiler defines you have to look into the cintools header files how to make it understand that it should more or less act like it is a Windows compiler anyways. The compiler detection part is done in platdefines.h in that directory.
Somewhere in the section that detects Windows you also have the compiler and CPU detection.
#if defined(__MWERKS__)
#define Compiler kMetroWerks
#elif defined(_MSC_VER) || defined(_NI_VC_)
#define Compiler kVisualC
#elif defined(__SC__) || defined(_NI_SC_)
#define Compiler kSymanCWin
#elif defined(__BORLANDC__) || defined(__BCPLUSPLUS__)
#define Compiler kBorlandC
// Add a detection for GCC and MinGW and for the ease of it just claim it is GCC in either case
#elif defined(__GNUC__) || defined(__MINGW32__)
#define Compiler kGCC
#else
#error "We don't know the Compiler"
#endif
#ifdef _M_PPC
#define ProcessorType kPPC
// The __i386__ or __x86_64__ should be defined by GCC, _X86_ and __MINGW64__ is from MinGW,
#elif defined(_M_IX86) || defined(__i386__) || defined(_X86_)
#define ProcessorType kX86
#elif defined(_M_X64) || defined(__x86_64__) || defined(__MINGW64__)
#define ProcessorType kX86
#elif defined(_M_ALPHA)
.....
NI doesn't ever use GCC or derived compilers for Windows, so they have nothing in the headers to support that out of the box but the detection logic is straightforward enough that you can add it yourself, if you really feel inclined to do so.
You might have to play with these as I have really no experience what MinGW all defines in addition to the GCC or instead of its defines. And there is of course no guarantee that something may not break. The headers and link libraries that NI provides are meant to be used with Visual Studio, aka MSC. GCC is in many respects different and MinGW tries to make it more compatible to MSC but only so much.
04-19-2022 04:35 AM
setPower function into Qt DLL :
int myClass::setPower(char *receivedMessageString, char *responseMessageString, size_t *size)
{
// Error codes
int noError = 0;
int buffToSmall = 10;
QByteArray receivedMessage(receivedMessageString, strlen(receivedMessageString));
std::string response(receivedMessage.constData(), receivedMessage.length());
if(*size <= response.length())
{
return buffToSmall;
}
qstrncpy(responseMessageString, response.c_str(), response.length() + 1);
*size = response.length();
return noError;
}
LabVIEW front result :
(not the same size, why ???)
LabVIEW diagram :
LabVIEW crash with this error (like a memory leak ?) : DAbort 0xF50EFD7B in MemoryManager.cpp
My questions are why the size of the message changes between input and output when it is the same message and why the copy works well but LabVIEW crashs ?
Thanks
04-19-2022 07:51 AM
If you'd show the names in the dll (right click, Name Format, Names), we could actually read the code...
If a string is 2 bytes per character, it's probably using wide chars (2 bytes per character).
04-19-2022 08:59 AM
Yes, sorry. Here the CLFN :