11-02-2023 04:26 AM
Hi guys,
I wrapped the PostLVUserEvent function in C++/C and I called it in Labview.
Executing it in the development environment did not trigger the user registration event, but it did trigger the user registration event in the runtime environment.
Let me show you some pictures:
Note: if you can't find the library, please refer to the solution at this link (refer the corresponding library to /usr/lib).
I will include the source code in the attachment.
This problem has been bothering me for a few days!😤
11-04-2023 10:01 AM - edited 11-04-2023 10:06 AM
Several things that seem not to match here and/or are bad:
int test_callback_pointer(unsigned int *ref)
{
const char *pd = "123456789";
int len = strlen(pd);
char *data = (char *)malloc(len);
memcpy(data,pd,len);
int ret = PostLVUserEvent(*ref, data);
return ret;
}
1) Your user event is a 64-bit integer but you pass a pointer to a string as data. Luckily your buffer is more than 8 bytes long so it will be able to read 64-bit from that buffer without accessing invalid memory.
2) You allocate a new buffer with each call but never free it -> memory leak
3) When passing the user event refnum to the C function LabVIEW passes it by reference. It is more easily to see that if you use explicit datatypes. Right Clicking on the CLN and selecting "Create C code" will actually generate this prototype (on Windows at least):
#include "extcode.h"
int32_t funcName(LVUserEventRef *refnum);
int32_t funcName(LVUserEventRef *refnum)
{
uint64_t value = 12345678;
return PostLVUserEvent(*refnum, &value);
}
Filling in the body as here will be all that is needed to pass the number back;
4) In the C code you pass the return value of PostLVUserEvent() to the caller as return value. This is a MgErr (int32_t), but in the example you show it is the numeric value of the user event refnum! How can that be? Either your C code you attached is not what you are really executing or the panel values you show are not from a proper execution. If it really is as you say, something somewhere seriously is messing up your stack. Are you sure you compile the code for the right calling convention? (I don't believe there is any option to select calling convention in the Call Library Node under Linux as LabVIEW 64-bit for Linux only supports the standard first 6 parameter in registers and then the rest of the parameters on the stack).
The weird thing is that even if the function somehow would not be called correctly, the first parameter (the reference to the refnum) would be passed in EDI (but not the refnum itself) but the return value is retrieved from EAX (which should be the return value of the PostLVUserEvent() call).
11-06-2023 12:50 AM
Thanks for your reply.
1. I looked up the prototype of the PostLVUserEvent function, which defines the user event as uint_32, so my wrapper defines the uint_32 parameter.
2. You are right, but it should not be the original cause of the problem
3. See picture
4.This is where I feel the same pain, but from the C code it looks like the test_callback_pointer function simply calls PostLVUserEvent and passes the input user event and the defined character constant to PostLVUserEvent; Compiled shared libraries also follow the C protocol.
In addition, I generated the application with Labview vi, and Labview was able to respond to user events normally.
If you have time and a Linux machine, you can try it.
11-06-2023 02:29 AM - edited 11-06-2023 02:34 AM
Strictly it defines the first parameter as LVUserEventRef. Yes that eventually is an alias for MagicCookie and that is again an alias for an uint32_t but in these cases I prefer to keep the most distinctive datatype definition, eventhough it won't matter for the compiler. But for any casual reader of the source code it can make a whole lot of difference.
I don't have LabVIEW for Linux at this point but know that I used these functions in earlier LabVIEW version on Linux without problems.
My main point is, that with your convoluted function that does pretty weird things with string constant pointers on the stack, that get copied into a never deallocated second memory buffer to be passed as in uint64_t to LabVIEW you really make it extra hard to debug anything here.
Instead you should try to make it as simple as possible, invoke gdb on the shared library before you execute your LabVIEW program, set the breakpoint to the first statement of the function and then watch what happens with your stack and registers from within gdb. Something is very weird. It could be the linking to the LabVIEW runtime library but it could also be something in your compiler tool chain not correctly setup.
Yes you do LabVIEW programming, but you also do C programming here. So you need to familiarize yourself with the debugging tools for that too. Trying to debug shared libraries written in C/C++ from just running a LabVIEW program is similar to trying to fly an airplane by communicating through a telephone with a dummy operator on the plane. It is pretty much flying blind!
11-06-2023 03:22 AM
Thanks for your reply, I will try it😁