LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Use Qt DLL into Labview

Solved!
Go to solution

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 :

 

1.JPG

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 :

2.JPG

CLFN configuration :

3.JPG4.JPG

I don't understand why I can't get a response.

 

Thanks for help.

0 Kudos
Message 1 of 11
(2,785 Views)

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.

0 Kudos
Message 2 of 11
(2,759 Views)

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.

0 Kudos
Message 3 of 11
(2,717 Views)

@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...

0 Kudos
Message 4 of 11
(2,715 Views)
Solution
Accepted by topic author syuiopwdfghj

@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;
}

 

 

 

 

Rolf Kalbermatter
My Blog
Message 5 of 11
(2,687 Views)

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 !

0 Kudos
Message 6 of 11
(2,609 Views)

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.

Rolf Kalbermatter
My Blog
0 Kudos
Message 7 of 11
(2,605 Views)

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 :

5.JPG

(not the same size, why ???)

 

LabVIEW diagram :

6.jpg

 

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

0 Kudos
Message 8 of 11
(2,550 Views)

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

0 Kudos
Message 9 of 11
(2,534 Views)

Yes, sorry. Here the CLFN :

7.JPG

Message 10 of 11
(2,522 Views)