11

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;
5
  • 1
    en.wikipedia.org/wiki/X86_calling_conventions Commented Dec 28, 2009 at 16:13
  • 2
    I don't think there's any bad practice about making sure your calling conventions match. Commented Dec 28, 2009 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! Commented Dec 28, 2009 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. Commented Dec 28, 2009 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. Commented Dec 28, 2009 at 17:19

3 Answers 3

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;
Sign up to request clarification or add additional context in comments.

2 Comments

Best answer I think; I will use WNDPROC dwp = DefWindowProc;
Probably best to use "CALLBACK" rather than "__stdcall", if needing to write the types out by hand, since this is what the headers use...
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.

4 Comments

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.
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.
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.)
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. :)
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.

1 Comment

Compile, yes. Work, not exactly. See my comment on Kornel's answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.