10

Please could someone give me a few tips for creating function pointers for MS winapi functions? I'm trying to create a pointer for DefWindowProc (DefWindowProcA/DefWindowProcW) but getting this error:

LRESULT (*dwp)(HWND, UINT, WPARAM, LPARAM) = &DefWindowProc;

error C2440: 'initializing' : cannot convert from 
'LRESULT (__stdcall *)(HWND,UINT,WPARAM,LPARAM)' 
to 'LRESULT (__cdecl *)(HWND,UINT,WPARAM,LPARAM)'

I can't figure out what I need to use because I am not used to the MS ascii/wide macros. By the way, I'm creating a function pointer to make a quick hack, and unfortunately I don't have time to explain why - but regardless, I think this question will be helpful to people who need to create winapi function pointers.

Update:

This code works, but I'm worried that it is bad practice (and does not adhere to unicode/ascii compile options). Should I define two specifications?

LRESULT (__stdcall* dwp)(HWND, UINT, WPARAM, LPARAM) = &DefWindowProc;

Update 2:

This is nicer (thanks to nobugz):

WNDPROC dwp = DefWindowProc;
Nick Bolton
  • 38,276
  • 70
  • 174
  • 242
  • 1
    http://en.wikipedia.org/wiki/X86_calling_conventions –  Dec 28 '09 at 16:13
  • 2
    I don't think there's any bad practice about making sure your calling conventions match. – mrduclaw Dec 28 '09 at 16:26
  • 1
    however it is crazy of MS to have 3 different calling conventions, they should have picked one and stuck with it! – gbjbaanb Dec 28 '09 at 16:27
  • 3
    MS isn't responsible for __cdecl and barely for __fastcall. 64-bit code has only one calling convention. Whomever adds another will be shot. – Hans Passant Dec 28 '09 at 17:01
  • Nobugz, Microsoft also has **thiscall**, which is the default for *methods*. It's not compatible with any of cdecl, stdcall, or thiscall. And Microsoft's thiscall isn't the same as Borland's. – Rob Kennedy Dec 28 '09 at 17:19

3 Answers3

17

Fix the calling convention mismatch like this:

LRESULT (__stdcall * dwp)(HWND, UINT, WPARAM, LPARAM) = DefWindowProc;

A typedef can make this more readable:

typedef LRESULT (__stdcall * WindowProcedure)(HWND, UINT, WPARAM, LPARAM);
...
WindowProcedure dwp = DefWindowProc;

But, <windows.h> already has a typedef for this, you might as well use it:

WNDPROC dwp = DefWindowProc;
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Best answer I think; I will use `WNDPROC dwp = DefWindowProc;` – Nick Bolton Dec 28 '09 at 16:37
  • 3
    Probably best to use "CALLBACK" rather than "__stdcall", if needing to write the types out by hand, since this is what the headers use... –  Dec 28 '09 at 19:30
2

You lack __stdcall in your prototype. You need to have a matching calling convention apart from a matching prototype. WINAPI functions are all __stdcall, while the default for C++ is __cdecl.

Using extern "C" { code } is a viable alternative.

Kornel Kisielewicz
  • 55,802
  • 15
  • 111
  • 149
  • 3
    I always thought that extern "C" and __stdcall were two different things. extern "C" being needed to force the C ABI (as opposed to the name mangled c++ ABI. __stdcall is to enforce the normal windows calling convention where the called function is responsible for cleaning up the stack as opposed to the __cdecl C calling convention where the calling function cleans up the stack. – doron Dec 28 '09 at 17:02
  • 1
    You're correct, Deus Ex Machina. Calling convention has nothing whatsoever to do with linkage, which is what "extern C" controls. "Extern C" affects name mangling, and so does the calling convention, but we're not interested in name mangling here since neither DefWindowProc nor dwp is being exported or imported in any of the code shown. – Rob Kennedy Dec 28 '09 at 17:22
  • 2
    What's worse is that stdcall and cdecl are sufficiently compatible that if you use extern "C" without matching conventions, the program will link, and the call will work perfectly -- but on return from the call, you've got corrupted local variables (and if the call was the last thing in the method, you wouldn't even notice, since the return will usually work properly). A big trap waiting for the unwary. (And yes, I've had to debug code afflicted with this problem.) – Miral Jul 01 '10 at 06:05
  • Also, if you let the compiler optimise away the standard stack framing code, the return can crash your app. It's debatable whether this is better or worse -- at least it's easier to find. :) – Miral Jul 01 '10 at 06:17
0

This isn't the 'crazy' MS ascii/wide macro, you've just got 2 different function declarations.

If you decorate your internal function with "extern C" around it, you'll expose your function with the same calling type as the original and it'll compile.

gbjbaanb
  • 51,617
  • 12
  • 104
  • 148