07-13-2021 06:30 AM - edited 07-13-2021 06:35 AM
Debugging pictures is not possible and interpreting unavailable API information neither! From the information you gave so far in this thread, your initial approach should have worked. Since it hasn't, the information you provided is incomplete or inaccurate.
Without the original API documentation from the manufacturer AND the VIs you created to compare and verify them to match the API, there is nothing else I can do.
07-13-2021 11:16 AM
If Rolf says more info is needed that must definitely mean that more is needed. He is the dll heavyweight of the LabVIEW forums. You're in good hands.
07-14-2021 01:53 AM
Dear Rolf
I see that this is a problem.
Unfortunately I can just provide the 64 bit DLL and the VI.
If you want to debug you need the driver end a harware.
So it might not be very sane but I attache the files.
The first call works perfectly and the result is 2 because I have two devices.
07-14-2021 02:42 AM - edited 07-14-2021 02:57 AM
Sic!
You are correct that the DLL really doesn't help much for now. I do not have any hardware and hence can not test it here. And trying to call the DLL anyhow won't produce any result that would allow to test this specific API in any way.
When I said documentation about the DLL, I meant at the minimum the header file for the DLL. This must be provided by the DLL manufacturer in order for the DLL to be even callable in a C program. Bonus points if there is (a section of) some written documentation for this API. The C header is notoriously inadequate to describe the semantics of how a function needs to be called, as it only describes the bare interface types of the function.
But ok, from the DLL name I could at least finally deduce what manufacturer these interfaces are from and that allowed me to download the according documentation from their site!
And if I check the prototype for the function in question I see this:
TPCANStatus __stdcall CAN_GetValue(
TPCANHandle Channel,
TPCANParameter Parameter,
void* Buffer,
DWORD BufferLength);
Wait? Isn't there a fourth parameter? Indeed! And to add insult to injury, you actually use that for the first parameter query (wrongly)!
You pass 1 in there as buffer length but this parameter is really a DWORD and hence you should pass a uint32 by reference as third parameter (which you do) and another uint32 by value with the value 4 as fourth.
But the API likely doesn't really care about this BufferLength there for scalar values anyhow although that is not exactly nice. Or maybe it does and correctly only writes in the first byte of the buffer and since you are on a Little Endian machine (Intel x86 CPU) this happens to be the correct byte to transfer numbers smaller than 256. It would not work on Big Endian machines though.
But for the PCAN_ATTACHED_CHANNELS it definitely will care about this parameter in order to make sure to not overrun the user provided buffer. And that means you need to pass a fourth parameter to this function with the value of the buffer size in bytes that you pass in as third parameter.
And since your API is stdcall there is another even more grave problem with omitting this parameter in the call to this function. stdcall means that the callee (the function itself) cleans the stack from the parameters that it knows to have been passed to it from its signature. But you didn't pass that many parameters on the stack -> crash bumm and you have corrupted your stack. The LabVIEW Call Library Node when not configured to use the minimum debugging level, will try to protect the call anyways by detecting such mismatches but it can only detect that the stack doesn't match after the function call and adjust it after the fact. It can not correct for whatever the function might have done wrong to cause this and therefore reports a catch all error that basically tells you that it is better to restart your program, since there might have happened grave corruptions that could (and actually quite often do) endanger the integrity of your process.
07-14-2021 03:18 AM
Dear Rolf,
the DLL call is a method and not a fuction call.
So there ale 43 parameters for 43 different output results, numeric 32 bit, numeric 64 bit, string, and other.
C# example
// 1. PCAN_ATTACHED_CHANNELS_COUNT
TPCANStatus stsResult = PCANBasic.GetValue(PCANBasic.PCAN_NONEBUS, TPCANParameter.PCAN_ATTACHED_CHANNELS_COUNT, out uint iChannelsCount, sizeof(uint));
This works fine
// 2. declare a buffer size big enough to store all channel information in.
TPCANChannelInformation[] ciChannelInformation = new TPCANChannelInformation[iChannelsCount];
// 3. Call GetValue with Parameter PCAN_ATTACHED_CHANNELS and declared buffer to store the date in the buffer
stsResult = PCANBasic.GetValue(PCANBasic.PCAN_NONEBUS, TPCANParameter.PCAN_ATTACHED_CHANNELS, ciChannelInformation);
This is the call in C#
07-14-2021 03:23 AM
Dear Rolf
All these get functions work properly except PCAN Get ATTACHED_CHANNELS .vi
07-14-2021 04:05 AM
Hi Rolf
As you have seen in the C# call the method doesnt need a sizeof(buffer) information.
I simply addad one as a shot to nothing and get a result.
I'll analyze it and will come back to this thread.
Thank you so far.
07-14-2021 04:46 AM - edited 07-14-2021 04:52 AM
Your wrong on several accounts here.
First, the DLL interface is NOT C#, it is plain old C and follows the according rules. So there are no methods, objects, and all that modern stuff, you only have exported functions and sometimes variables, nothing else!
That the C# interface Peak provides in their examples doesn't require this extra parameter is a feature of that C# Interop Marshalling wrapper they wrote there, not of the underlying DLL interface they call in there. C# is a managed environment, when you pass a variable into a function or method it can automatically find out various things about this function such as the number of elements an array consists of, because that parameter is in fact an object with all kind of extra attributes depending on its type, and many more you can query if you use the .Net reflection functionality.
The C interface provided through the DLL has none of these gadgets. It's bare bone programming. A pointer is a pointer and nothing else, there is no reflection or whatever other standard mechanism that allows you to query the type, the size or anything of that pointer at runtime. The type is agreed to at compile time and the DLL function will treat the parameter according to how it was compiled, not to what data types you pass into it at runtime, no matter what.
Just as you never should create in LabVIEW dumb wrappers that pass all the parameters of DLL verbatim to the front panel (since LabVIEW is in fact also a managed environment although it does not use the same management semantics as .Net) so should a .Net Interop Wrapper developer NOT pass the underlying DLL interface verbatim to the caller. It should use the managed features of .Net to make that API easier and do the bit banging and low level dealings to adapt to the unmanaged DLL interface, without bothering the user of this API with such nitty gritty details.
07-14-2021 04:52 AM
Dear Rolf,
you are right.
This works now:
Thank you very much!
Best regards
Martin
07-14-2021 06:25 AM
I still would change that constant 1 at your first CLN to 4 as you are technically passing a pointer to an uint32 to the function and that is a 4 byte buffer, not a 1 byte buffer.