Sign in to follow this  
ekrax

never have understood this in a windows program ...

Recommended Posts

i finally have a grasp on exactly everything you need to code for a basic windows program, however i don't understand the syntax on 2 functions ... the WndProc function ... LRESULT CALLBACK WndProc ( // ... ); and WinMain ... int WINAPI WinMain ... what im confused about is how there looks like there is 2 return types ... this makes no sense to me, LRESULT CALLBACK ... how can you declare a function with 2 types? this has always confused me, what is going on? thanks for any help.

Share this post


Link to post
Share on other sites
The LRESULT is the return type. CALLBACK defines how to call the function. There are different ways to call functions, like __fastcall, you just use CALLBACK to make sure that the function is called correctly.

Share this post


Link to post
Share on other sites
to add something here. this is called a "calling convention". because some languages pass the parameters of a function through the stack in a different order, this forces the compiler to pass the arguments in a given order. this is needed sometimes for functions used by different languages.

Share this post


Link to post
Share on other sites
LRESULT is a macro for the return type, unsigned long I believe. CALLBACK and WINAPI is macros for the calling-convetion, i.e. the way you want the compiler to push function arguments on the stack and handle return values when producing the assembler code.

//edit: meh, gotta stop keeping pages in a background tab for half an hour before answering them =P

Share this post


Link to post
Share on other sites
Quote:
Original post by ekrax
... how can you declare a function with 2 types? ...


2 "types"? That's nothing. How about 4 "types"?
    static const MyClass __cdecl foo(); 
As you can see they aren't all types. LRESULT, CALLBACK, and WINAPI are macros and aren't necessarily types either.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
well i know those aren't types, i just didn't know there was another "setting" you could apply to defining variables or functions, to me i thought something like this ...

mutable volatile int MyFunc ();
or something like ...
static const float MyFunc ();

was the most qualifers or specifers you could apply i didn't know that you could add a "calling convention" to it ... i have been reading "c++ from the ground up" by herbet schildt, but i guess this subject isn't covered in this book. so this brings me to belive that using a calling convention is very rare?

so anyways are there are built in calling conventions? or must you define them yourself using "C" style macros or asm or something else?

Share this post


Link to post
Share on other sites
Basically, there are default calling conventions, and it's quite rare that you need to specify one. They specify the order in which things go on the stack, how the register values are saved (by caller or callee), and other stuff like that, which you're trying to avoid worrying about in the first place by not writing in assembler.

Common ones in C++ include _cdecl (normal, "free function"), _thiscall (used for member functions, and specifies to put the 'this' pointer on the stack in addition to the other arguments), _fastcall (Microsoft-specific I think) and _dllimport/_dllexport (for DLLs, also MS-specific). I think I got that right. Anyway, this stuff is *normally* taken care of for you (e.g. you don't need to write the _thiscall for your member functions). But when you are writing a DLL, or setting up WinMain, you need to worry about it.

Share this post


Link to post
Share on other sites
A little correction, the fastcall convention is not microsoft specific, but the thiscall one is. Check them up in the msdn if you want to know more about them. And as already stated, you rarely need to specific which calling convention to use, it's mainly used when sharing code between compilers/languages.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I'm interested in finding out abit more about how LRESULT CALLBACK.. works. I've read that it enables a function to call a funcction. My guess on this is that because you are running your program on a windows computer (operating system), then this is the way for your program to communicate with windows, a windows program really is "just another window", it has to rely on Windows itself, i.e. getting input from the keyboard comes via Windows, when you have a WM_MESSAGE in the CALLBCK function you are kind of asking Windows to tell if such or such event occured. If it did then your case statement catches it and you can do what ever you wanted.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
I'm interested in finding out abit more about how LRESULT CALLBACK.. works. I've read that it enables a function to call a funcction.


No, it doesn't do any enabling. Besides which that's all you do in code, is write functions that call functions! No need to 'enable' anything. More specifically, when you compile a program the compiler needs to know the calling convention of all functions you call. This is so it can properly create the instructions that sets up the function call. Window procedures are a typedefed function pointer (WNDPROC). When the API dlls are compiled by the MS people, the compiler set up the function call to the window procedure (somewhere deep in event pump land) using the declared calling convention. When you create a window procedure, it should have the same signature (return type and calling convention). If it doesn't, bad things could happen. The macros help with that.

Using LRESULT ensures the function is declared with the proper return type, and CALLBACK ensures function has the proper calling convention. Most Win32 API functions are __stdcall, but the functions in a C program are typically __cdecl by default. Using CALLBACK allows your application to declare the function using the calling convention that the API expects a callback to have. It doesn't do anything special beyond that. So this:

LRESULT CALLBACK MyProc

translates to something like this

unsigned long __stdcall MyProc

Or whatever LRESULT and CALLBACK are defined as. The idea being that if the expected values ever change (such as LRESULT becomes a float) you don't need to go through and change any code - just recompile.

Share this post


Link to post
Share on other sites
Hi all,

The main thing of having a __cdecl and a __stdcall calling convention (WINAPI and CALLBACK are stdcall) is mainly a programming language issue. Pascal flavours (delphi and the like) are using a different calling convention. Arguments are pushed on the stack by the caller, and the callee clean the stack (easy to implement: you do not have varargs in pascal). C/C++ programs do not work this way : it is up to the caller to clean the stack (yeah... vararg stuff). Both are pushing args in the reverse order (right to left).

In order to have window procedure to work in a pascal environment (as well as all other callbacks), then you need to choose one of these calling convention. Due to historical reasons, and because you do not use callbacks with varargs, pascal won.

On this particular issue, the MSDN says :

Quote:
WINDOWS.H now supports the WINAPI macro, which translates to the appropriate calling convention for the target. Use WINAPI where you previously used PASCAL or __far __pascal.


... Noone to remember :


int PASCAL WinMain(/*hInstance, hPrevInstance, ...*/)
{
}


Good old days of Windows (I still have this 1.01 version somewhere...)

(PS : stdcall is also used for Fortran modules)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this