The Windows API (aplication programming interface) is a very powerful framework when it is used correctly, however it it often considered by beginners as confusing and difficult to learn. This tutorial will go over the basics of setting up a window and displaying it to the user in the hopes that the Windows API will seem less intimidating to people who want to learn but have little or no knowledge of it.
What you will need for this tutorial
The code I write for this tutorial is designed for compilation in Visual C++ 2010, of which the Express edition is free to download and register, I'd recommend using that.
How to create a Windows API project in Visual C++ 2010
1) Go to file/new/project
2) When the "new project" dialog box shows, select a "Win32 project", choose a name and location for the project and then click the "Ok" button.
3) Click "next" in the next form.
4) Now, under "Additional options:", check the box that says, "Empty project", as we will be doing this from scratch.
5) Click finish.
6) Under the "Solution explorer" tab, right click "source files" directory and in the menu click add/new item. If you can't find the solution explorer, go to "view/solution explorer".
7) Select a "C++ file (.cpp)" and name it "WinMain.cpp", click add.
8) Now, finally we are going to tell Visual C++ to use the "Multi-byte character set". Go to project/<your project name> properties/configuration properties/general/character set/Use Multi-Byte Character Set. We use this character set so that we don't need to use macros when dealing with string literals.
9) Now we're read to code, yay!
A basic Windows API program
As you probably know, C++ console applications use an entry symbol called "main", which takes optional arguments and should return an integer. In contrast to this, Windows API programs use an entry symbol called "WinMain". Like "main", it is the first function to execute in a program, and also returns an integer, but "WinMain" has some arguments which are required for any Windows API program to compile.
The following code is about the most basic Windows API program you will ever see, it simply displays a message box to the user. All the code in this tutorial will be heavily commented to make it more clear.
#include <Windows.h> /* The standard "windows.h" inclusion */
int WINAPI WinMain( HINSTANCE hInstance, /* A handle to the current instance of the application. */
HINSTANCE hPrevInstance, /* A handle to the previous instance of the application. */
LPSTR lpCmdLine, /* The command line for the application, excluding the program name. */
int nCmdShow) /* Controls how the window is to be shown. */
{
/* Call to the MessageBox function */
MessageBox(NULL, "Hello, Windows API!", "Hello", MB_OK | MB_ICONINFORMATION);
/* WinMain returns 0 if we exit before we enter message loop, more on that to come */
return 0;
}
You can compile this by going to the build menu and clicking on "build" (or press F7), then you can run it by clicking the green arrow in Visual C++.
Most of the arguments that "WinMain" takes will likely never be used by you, probably the most important argument is called "hInstance", but you will see its use when we set up a window. Note that "WinMain" uses the "__stdcall" calling convention in Visual C++, which is what WINAPI is #defined as.
Creating a window
Creating, displaying and running a window requires alot more code, but a basic window isn't too hard to set up. I'll get straight to the code, here is the code that will display a window.
#include <Windows.h>
/* Create nice looking controls */
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
/* Name of our class and the title */
const char *clsName = "WinAPI";
char *title = "Windows API";
/* Global flag for our message loop */
bool running = true;
/* Handle to the window */
HWND hWnd = NULL;
/* A windows callback procedure. */
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
/* Message created when the user tries to close the window */
case WM_CLOSE:
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
running = false;
return 0;
default:
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
}
/* Entry point of our application */
int WINAPI WinMain( HINSTANCE hInstance, /* A handle to the current instance of the application. */
HINSTANCE hPrevInstance, /* A handle to the previous instance of the application. */
LPSTR lpCmdLine, /* The command line for the application, excluding the program name. */
int nCmdShow) /* Controls how the window is to be shown. */
{
WNDCLASSEX WndEx;
MSG msg;
WndEx.cbSize = sizeof(WNDCLASSEX); /* The size, in bytes, of this structure. */
WndEx.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; /* The class style(s) */
WndEx.lpfnWndProc = (WNDPROC)WndProc; /* A pointer to the window procedure. */
WndEx.cbClsExtra = 0; /* The number of extra bytes to allocate following the window-class structure. */
WndEx.cbWndExtra = 0; /* The number of extra bytes to allocate following the window instance. */
WndEx.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* A handle to the class icon. */
WndEx.hCursor = LoadCursor(NULL, IDC_ARROW); /* A handle to the class cursor. */
WndEx.hbrBackground = NULL; /* A handle to the class background brush. */
WndEx.lpszMenuName = NULL; /* We're not using a menu here */
WndEx.lpszClassName = clsName; /* A pointer to a string that contains the class name */
WndEx.hInstance = hInstance; /* A handle to the instance that contains the window procedure for the class. */
WndEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION); /* A handle to a small icon that is associated with the window class */
/* Register the windows class */
if (!RegisterClassEx(&WndEx))
{
MessageBox(NULL, "Failed to register class", "ERROR", MB_OK | MB_IConerror);
return 0;
}
/* Create the window */
if (!(hWnd = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, /* The extended window style */
clsName, /* A pointer to a string that contains the class name */
title, /* A pointer to a string that contains the title of the window */
WS_OVERLAPPEDWINDOW | /* The style of the window being created */
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, /* initial x,y position of the window */
460, 340, /* initial x,y size of the window */
NULL, /* A handle to the parent or owner window */
NULL, /* A handle to a menu */
hInstance, /* A handle to the instance of the window */
NULL))) /* lParam */
{
MessageBox(NULL, "Failed to create the window", "ERROR", MB_OK | MB_IConerror);
return 0;
}
/* The window is initially hidden, we need to show it */
ShowWindow(hWnd, SW_SHOW);
/* The main message loop of our program */
while(running)
{
/* Are there any messages in the message queue? */
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
/* translate and dispatch the message */
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
Let's look at the steps taken to create that window.
Step 1: Create a set up a "WNDCLASSEX" structure.
WndEx.cbSize = sizeof(WNDCLASSEX); WndEx.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; WndEx.lpfnWndProc = (WNDPROC)WndProc; WndEx.cbClsExtra = 0; WndEx.cbWndExtra = 0; WndEx.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndEx.hCursor = LoadCursor(NULL, IDC_ARROW); WndEx.hbrBackground = NULL; WndEx.lpszMenuName = NULL; WndEx.lpszClassName = clsName; WndEx.hInstance = hInstance; WndEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
This structure contains information about the windows class. It is used with the RegisterClassEx and describes various aspects of the window. It is heavily commented so i won't go too far into that.
Step 2: Register the class
/* Register the windows class */
if (!RegisterClassEx(&WndEx))
{
MessageBox(NULL, "Failed to register class", "ERROR", MB_OK | MB_IConerror);
return 0;
}
Pretty self explanitory, just registers the previously set up WNDCLASSEX structure with the class.
Step 3: Create the window
/* Create the window */
if (!(hWnd = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
clsName,
title,
WS_OVERLAPPEDWINDOW |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
460, 340,
NULL,
NULL,
hInstance,
NULL)))
{
MessageBox(NULL, "Failed to create the window", "ERROR", MB_OK | MB_IConerror);
return 0;
}
This creates the window and sets up some details about it, such as its position, size, style and it's parent (if any).
Step 4: Show the window
/* The window is initially hidden, we need to show it */ ShowWindow(hWnd, SW_SHOW);
Displays the window
Step 5: The message loop
/* The main message loop of our program */
while(running)
{
/* Are there any messages in the message queue? */
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
/* translate and dispatch the message */
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
This loop keeps running as long as the global "running" flag is set.
Now would be a good time to talk about the message loop. Whenever anything happens to your window, a message is sent. This might be a resize, a create message, a close message etc etc. This message needs to be caught and translated in order to be of any use, this is the job of our message loop, along with our callback procedure. The message loop catches the message and our callback procedure defines how we should act. Here is our callback procedure again.
/* A windows callback procedure. */
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
/* Message created when the user tries to close the window */
case WM_CLOSE:
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
running = false;
return 0;
default:
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
}
Notice that the message is passed to the function and it is decoded by by the switch statement. the "WM_<insert message name here>" defines are just values that reperesent a message.
Back to our message loop
The "PeekMessage" function checks whether there are any messages that need to be processed, if there are, then the message is translated and dispatched. In this process, the callback procedure is called so that any messages sent can be caught arbitrarily as described above.
That's about it for a very basic window, i hope this was informative.
Thanks







MultiQuote







|