LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

StdCall (WINAPI)

Solved!
Go to solution

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.

Rolf Kalbermatter
My Blog
0 Kudos
Message 11 of 20
(1,179 Views)

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.

Bill
CLD
(Mid-Level minion.)
My support system ensures that I don't look totally incompetent.
Proud to say that I've progressed beyond knowing just enough to be dangerous. I now know enough to know that I have no clue about anything at all.
Humble author of the CLAD Nugget.
0 Kudos
Message 12 of 20
(1,145 Views)

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.

 

Download All
0 Kudos
Message 13 of 20
(1,120 Views)

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.

Rolf Kalbermatter
My Blog
0 Kudos
Message 14 of 20
(1,112 Views)

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#

 

0 Kudos
Message 15 of 20
(1,104 Views)

Dear Rolf

 

All these get functions work properly except PCAN Get ATTACHED_CHANNELS .vi

 

Martin_Kunze_1-1626250939918.png

 

 

 

 

0 Kudos
Message 16 of 20
(1,105 Views)

Hi Rolf

 

As you have seen in the C# call the method doesnt need a sizeof(buffer) information.

Martin_Kunze_0-1626253471891.png

 

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.

0 Kudos
Message 17 of 20
(1,100 Views)

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.

Rolf Kalbermatter
My Blog
0 Kudos
Message 18 of 20
(1,086 Views)

Dear Rolf,

 

you are right.

This works now:

Martin_Kunze_0-1626256295531.png

 

Thank you very much!

Best regards

Martin

0 Kudos
Message 19 of 20
(1,080 Views)
Solution
Accepted by topic author Martin_Kunze

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.

Rolf Kalbermatter
My Blog
0 Kudos
Message 20 of 20
(1,055 Views)