Hi,

I have a little program that uses LoadLibrary and GetProcAddress to dynamically retrieve a pointer to a function of the Gdi32.dll (the GetPixel function).
Now I have noticed, that after I have made some changes to my program, I suddenly receive a pointer to a GetPixel function that uses another calling convention! First the calling convention used by GetPixel was _cdecl, and now it has become _stdcall.
Does anybody know what makes GetProcAddress choose which version of a function it returns?

Misja

PS I don't know if it matters but the code that calls LoadLibrary and GetProcAddress is written in C, the rest of the code that calls GetPixel is written in assembly.
Posted on 2006-03-31 01:52:29 by misja
There's only one GetPixel function in gdi32.dll, and it uses stdcall convention no matter what the caller is - a VB, C, asm, Pascal, Fortran or whatever else language. It is the caller's responsibility to adjust to the calling convention of the function called.

The GetProcAddress does not select "versions" (in the meaning of calling conventions) of functions, it simply returns a pointer to a function.
I suggest you check you compiler settings, #pragmas, #defines, function prototypes, externs - some of them must make your compiler assume the function (GetPixel) uses cdecl instead of stdcall and produce a kind of invalid code (cleaning stack after the function returns while the function did it already).
Posted on 2006-03-31 02:15:01 by Morris
The code that calls GetPixel is 100% written by myself, in assembler. So there is no compiler setting that choses the calling convention.
I had to find out the hard way that the calling convention of GetPixel had suddenly changed ...

I did some more research by printing the address of the function pointer returned by GetProcAddress, and entering this in a disassembler. It really was different code the second time! But the disassembler did label the address with GetPixel every time. So it really looks like there are 2 GetPixel entries in Gdi32.dll, one using _cdecl and one for _stdcall. That's all fine with me but I would like to know how GetProcAddress chooses between them ...
Posted on 2006-03-31 02:46:09 by misja

The code that calls GetPixel is 100% written by myself, in assembler. So there is no compiler setting that choses the calling convention.
I had to find out the hard way that the calling convention of GetPixel had suddenly changed ...

You named it - your code started to call GetPixel with different calling convention.


I did some more research by printing the address of the function pointer returned by GetProcAddress, and entering this in a disassembler. It really was different code the second time! But the disassembler did label the address with GetPixel every time. So it really looks like there are 2 GetPixel entries in Gdi32.dll, one using _cdecl and one for _stdcall. That's all fine with me but I would like to know how GetProcAddress chooses between them ...

Check the export table of gdi32.dll then. On my system (Windows 2000 Professional PL SP4) there's only one "GetPixel" entry, and it's address (combined with preferred base) is 77F4CBC9.

Once again - this is your code that calls a function assuming a calling convention and IT IS affected by assembler settings, the ".model" directive or PROTO declaration.

The "receiving convention" (as the function receives a call) does not change because you changed something in your code. It is your code that ASSUMES it changed.
Posted on 2006-03-31 03:06:04 by Morris

So it really looks like there are 2 GetPixel entries in Gdi32.dll, one using _cdecl and one for _stdcall. That's all fine with me but I would like to know how GetProcAddress chooses between them ...


That's a bit nonsensical - if there were different calling conventions, applications would behave irratically... like crashing. Post the smallest snippet of code that you can reproduce this with.
Posted on 2006-03-31 06:42:42 by f0dder
Since the name of the function must be unique, there can only be one GetPixel and it is STDCALL as is the vast majority of the API. A change on such a fundamental level would break almost every paint package ever running on Windows and Microsoft would not allow that to happen. The amount of research that goes into compatibility at MS is huge and they would never allow something like this to slip through.

I have used the GDI rather extensively and have never encountered this problem I also write exclusively in 100% assembler. Could you post some code that demonstrates the problem ?
Posted on 2006-04-06 18:39:33 by donkey
There is only 1 GetPixel. No doubt about it. Your problem may be related to debug vs. release build. MS VC++ uses _cdecl conv for debug builds, by default. Even if you state that you want stdcall. This has something to do with the error checking code, I suppose. This would match what you've said: first it was cdecl, and then stdcall. You (or someone else) probably switched from debug to release build. Please call the LoadLibrary and GetProcAddress functions from assembler.

That's just a guess, of course. But there is NO other GetPixel inside the gdi32.dll and the one that is, uses stdcall.
Posted on 2006-04-06 20:58:04 by ti_mo_n

MS VC++ uses _cdecl conv for debug builds, by default.

It always uses cdecl by default, 'cause it's a C compiler.


Even if you state that you want stdcall.

I can't believe such a thing. Check your project configuration. If it doesn't work and you aren't using a very old or a beta compiler send a bugreport to MS.
Posted on 2006-04-07 17:55:22 by Kvant
The compiler allows you to change the default (at least the ver 6 compiler did.)

VC has special keywords to force a calling convention, overriding any defaults. So the primary Win32 API functions are forced to be stdcall via the prototypes in the standard header files.

It isn't GetProcAddress or the GetPixel function that is changing the calling convention. It's the function pointer. Or else, you are not using the standard headers, and relying on defaults.
Posted on 2006-04-07 21:01:16 by tenkey

The compiler allows you to change the default (at least the ver 6 compiler did.)

It is not default any more if you specify the calling convention :) A plain C/C++ source file compiled without any special command line switches uses cdecl by default. That's truly default, IMHO. It doesn't depend on release/debug status or anything else.
Posted on 2006-04-08 13:41:20 by Kvant