Linking against a Win32-DLL
Marc Müller
dont at spam.me
Tue Jul 10 07:39:14 PDT 2007
Sorry - there is still a problem...
At first:
I downloaded Code::Blocks and installed the D-Compiler and the
Ddbg-Debugger.
After downloading - it took me less than 5 minutes to get everything
working. That's the way it should be ;-)
Now back to the problem:
When using extern(Pascal) the stack seems to be clean.
And the function I used in former news works flawless (because I passed
three times a zero-value)
Now I tried to call the external functions with real parameters.
Then again some very strange bugs occurred, but thanks to your debugger
I found the reason quickly:
The program pushes the parameters in reversed order on the stack.
I wrote some lines of inline-assembler to reverse the order manually:
=============================================================
int result = WTInfoA(WTI_DEVICES, i, buffer);
asm
{
nop;
push dword ptr buffer;
push i;
push WTI_DEVICES;
call WTInfoA;
mov result, EAX;
}
-------------------------------------------------------------
Compiles to:
-------------------------------------------------------------
push 0x64
push dword [ebp-0xc]
push dword [ebp-0x10]
call 0x414748 WTINFOA
mov [ebp-0x8], eax
nop
push dword [ebp-0x10]
push dword [ebp-0xc]
push 0x64
call 0x414748 WTINFOA
mov [ebp-0x8], eax
=============================================================
When I use the asm-code the function is called correctly.
Do you know a calling convention or compiler/linker switch to tell D to
let the callee clean up the stack like in extern(Pascal), but push the
parameters in reverse order on the stack?
Kind regards,
-Marc-
Jascha Wetzel schrieb:
> the problem is indeed the calling convention.
>
> the version of wintab32.dll i found uses FAR PASCAL. the callee's clean
> up the stack. if you use extern(C), the caller cleans up the stack.
> therefore the return address at the end of the main function is
> incorrect and it crashes.
> this is only the case, though, as long as you don't use any local
> variables. in this case, D uses the ENTER and LEAVE x86 instructions to
> create and destroy stack frames. the correct stack pointers (the pointer
> to the former stack frame) are saved (in EBP) and therefore the
> incorrect value in ESP (that results from the obsolete cleanup) gets
> overwritten by the saved value, the correct return address is in place
> -> no crash.
>
> after looking at the C headers for wintab32.dll, you see that they use
> the WINAPI = __stdcall = extern(Windows) calling convention only if the
> win32 headers have been included (WINAPI is defined). else they use FAR
> PASCAL. since the function names in wintab32.dll do not adhere to the
> __stdcall convention (leading _ and trailing @X with X being the number
> of parameter bytes), they must be using FAR PASCAL.
>
> DMD's extern(Pascal) calling convention expects all uppercase function
> names. therefore you'll have to specify the /IGNORECASE option to
> optlink. not that FAR PASCAL has to leading underscore in the function
> names (as opposed to __cdecl or extern(C)).
>
> putting it all together:
> - use implib without the /s switch (no leading underscores)
> implib wintab32.lib \WINDOWS\system32\Wintab32.dll
>
> - declare all imports as extern(Pascal)
> extern(Pascal) UINT WTInfoA(UINT, UINT, LPVOID);
>
> - pass /IGNORECASE to optlink to compensate for case sensitivity in
> wintab32.dll
> dmd wintab32.lib wintabtest.d -L/IGNORECASE
>
>
> i used Ddbg to hunt this down in a very short amount of time, btw ;)
>
> Marc Müller wrote:
>>> Is it possible you're doing extern(C) when you need to be doing
>>> extern(Window), or vice versa?
>>>
>>> I don't have much experience with that so I'm just throwing it out.
>>> Maybe it just won't link if you get that wrong.
>>
>> With extern(Windows) the program does not link :-(
>>
>> I simplified the program and wrote it to
>> digitalmars.D.learn ("Problems when using DLL-Functions")
>> as Bjoern suggested.
>>
>> Again - thanks a lot for your help!
>> -Marc-
More information about the Digitalmars-d
mailing list