NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

cdecl stdcall extern "C"

TestStand documentation recommends not to use 'extern "C"' for DLL functions as this prevents TestStand from find out parameter type information from the DLL. It also says, TestStand supports __stdcall as wel as __cdecl functions.
We have a lot of DLLs using 'extern "C"' as this is typically the only way to ensure that the functions can be called by programs from different compilers (Windows own DLLs are also 'extern "C"', as far as I can tell). Of course, TestStand cannot find out parameter type information from these functions, but can it find out the calling convention? Because a call to a DLL function with the wrong calling convention will certainly crash with a corrupted stack.

Peter Waszkewitz
0 Kudos
Message 1 of 10
(8,251 Views)

I'm not sure which part of the documentation recommends against extern "C", but I'm guessing it does that because if you don't use extern "C" in MSVC++ on a static function, TestStand might be able to decode the prototype from the MSVC++ mangled name decoration.

If you need to use extern "C" for cross compiler compatibility, that is fine. You'll just have to enter the prototype yourself in TestStand.

You can't always correctly determine the calling convention from a DLL export name, but fortunately TestStand does not need this information. TestStand always restores the stack pointer after a DLL call so that the stack is guaranteed to be cleaned up no matter which convention the code module uses.

Message 2 of 10
(8,239 Views)

Thanks James.

From where do you take the information that "TestStand always restores the stack pointer after a DLL call ..." ?

Guenter

 

 

0 Kudos
Message 3 of 10
(8,231 Views)

I'm a developer on the TestStand team and I worked on that feature. 

Maybe we should document that. On the other hand, since it is a low level detail and it works without the need to understand it, documenting it might create more confusion than it eliminates.

0 Kudos
Message 4 of 10
(8,228 Views)

You are right, James. As TestStand now handles this calling convention issue properly I don't see any need to explicitely write it down in the documentation, either.

I got curious because some years ago I have been wasting hours on configuring the DLL adapter in TestStand 1 when dealing with DLLs created by different programmers.

Do you remember which version of TestStand introduced this calling convention check?

Guenter

0 Kudos
Message 5 of 10
(8,225 Views)
I can't remember for sure, but we've probably always restored the stack pointer. We used to ask the user to specify the calling convention, but later removed that since it was a challenging question for some and we don't use the information. I'm not sure what version we removed that in. I checked 3.5 and it was already gone by that version.
0 Kudos
Message 6 of 10
(8,221 Views)
Thank you all for the help and information. One more thing, however: I looked for some more information on the calling conventions and as far as I understand it, __stdcall and __cdecl differ not only in who cleans up the stack but also in the sequence how the parameters are pushed on the stack, which is what makes varargs-calls possible with __cdecl only. I can understand that TestStand can preserve the stack pointer, but how can it get the parameter sequence right without knowing the calling convention?
 
Peter
 
0 Kudos
Message 7 of 10
(8,208 Views)

cdecl and stdcall use the same order, right to left.

The pascal calling convention is the one that passes parameters left to right. However, it pretty much fell into disuse a long time ago after the transition from 16-bit to 32-bit Windows.

0 Kudos
Message 8 of 10
(8,194 Views)

Ah, yes, thank you, I mixed that up. That clarifies the issue. Thanks again for your help!

Peter

0 Kudos
Message 9 of 10
(8,182 Views)

I have a question possibly related to the DLL stack topic.

Recently I came across a case where a DLL function was called with a wrong parameter list. This seemed to have worked fine for years, but then there was a system where it crashed persistently with an 0xc0000471 exception (which is "unknown software exception").

The correct function prototype was

int Function(int);

and the call from TestStand was configured as

int Function();

Am I right to assume that the function then took some arbitrary value from the stack (which was OK as this parameter was actually obsolete) and that it worked fine most of the time because TestStand restored the stack pointer?

Regards

Peter

0 Kudos
Message 10 of 10
(3,798 Views)