Click to choose your tutorial
Tutorial 1: SDK
Tutorial 2: Creating a Window
Tutorial 3: Vulkan Instance
Tutorial 4: Supported Extensions
Tutorial 5: Drawing Points
Tutorial 6: Drawing Lines
Tutorial 7: Drawing Triangles
Tutorial 8: Introduction to Shaders
Tutorial 9: Loading Shaders
Tutorial 10: Using Multiple Shaders
Tutorial 11: Loading 3D Model
Tutorial 12: Displaying 3D Model
Tutorial 13: Vertex Animation
Tutorial 14: Bone Animation
OpenGL Tutorials
site is v0.1a build Sep 11, 2016
Join to be notified of new tutorials
Join

Win32 API Tutorial 2 - Creating Your First Window With Win32API

Written by staff. Contact us to submit your article for review.
Sep 13, 2016
tags Tags win, 32, api
Post #36

Now that you read the first part of windows tutorials it's time to write some code. But before I dive into the code I wanna say something about handles. You already know what they are. The following are some of the most important(to these tutorials) handles you will need to know about. For obvious reasons, you can name them anything you want, but here's what they are in my source:

HWND hwnd; // handle to the window HDC hdc; // handle to the device context

The device context handle won't be used in this tutorial but you still need to know about it. It'll be used mostly for drawing in the window in the next tutorials. What about the window handle? It will be used during creation of the window. It is now time to dump the window creation code on you. This is the starting point of your program:

#include <windows.h> #define WNDCLASSNAME "wndclass" HDC hdc; HWND hwnd; bool quit = false;

First you will need to include the windows.h header and define the window class name. You already know what those 2 handles are, so I'll skip their explanation here. The quit flag will indicate whether the program is running or not. As soon as you set the quit flag to true the program terminates. You will see how this works in the main loop which I'll write in a few.

//*===================== // The event handler //*===================== LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch(msg) { case WM_CLOSE: { PostQuitMessage(0); break; } } return DefWindowProc(hwnd, msg, wparam, lparam); }

This is the even handler function - WinProc( ). It processes all the messages that are being sent to the window. The only message we need right now is the WM_CLOSE message. It is sent when the window is being closed. There's also a function at the end which is returned. That function takes care of the rest of the messages that you don't have to worry about. Moving on to the most important function - WinMain( ). It will create and show the window. //*===================== // WinMain //*===================== int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int nshowcmd) { MSG msg; WNDCLASSEX ex; ex.cbSize = sizeof(WNDCLASSEX); ex.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC; ex.lpfnWndProc = WinProc; ex.cbClsExtra = 0; ex.cbWndExtra = 0; ex.hInstance = hinstance; ex.hIcon = LoadIcon(NULL, IDI_APPLICATION); ex.hCursor = LoadCursor(NULL, IDC_ARROW); ex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); ex.lpszMenuName = NULL; ex.lpszClassName = WNDCLASSNAME; ex.hIconSm = NULL; RegisterClassEx(&ex); // Create the window hwnd = CreateWindowEx(NULL, WNDCLASSNAME, "Window", WS_OVERLAPPEDWINDOW, 0, 0, 300, 300, NULL, NULL, hinstance, NULL); ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); // The message loop while(!quit) { if(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) { if(msg.message == WM_QUIT) quit = true; TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.lParam; }

Not a lot is going on over there actually as it might seem at first. Most of the code is just flags and properties of the window followed by the message loop. That's all it takes to create a window. I'll briefly go over the most important flags used to create the window in WinMain( ) and the message loop to make it clear for you. I'll skip a few details that are obvious and don't need explanation. You'll just have to figure them out on your own(I did), it's not that hard. If you're a prodigy you can skip the rest of the tutorial and just type the code in and you're good to go.

First you declare the message(msg) and the window class structure(ex). Then you have to fill all the data in the the ex structure. This data will specify all kinds of properties, the window style and assign the event handler function to the window to let the window know which function takes care of the sent messages(WinProc). The styles assigned to the window through ex.style can be combined by using the bitwise OR (|) operator. You can find a decent number of styles in the MVC Docs but you won't need to worry about all of them. We only need to OR three of them. By ORing the three flags: CS_HREDRAW|CS_VREDRAW|CS_OWNDC to the style parameter you tell the window to redraw the entire window if a movement or size adjustment changes the width(CS_HREDRAW) or the height(CS_VREDRAW) of the client area and that you want to allocates a unique device context for each window in the class(CS_OWNDC). The next two parameters(cbClsExtra and cbWndExtra) are always 0. They really have no importance to us. The icon and cursor parameters are obvious, you simply load them and they appear in your window. I use the default icon and cursor although you can load your own from a resource. You'll need to cast the GetStockObject(BLACK_BRUSH)'s result to (HBRUSH) and you'll have a black backgrounded window. I assign NULL to ex.lpszMenuName because it is used to attach a menu to the window and we don't need that yet. ex.lpszClassName takes our previously defined window class name string.

Register the class by calling RegisterClassEx(&ex);

The next part is actually creating the window and setting its width height and position. The function CreateWindowEx( ) does that for us. Let's take a look at the parameters. The first parameter is an extended style and we never need that, it has to deal with the appearance of the window on the screen and we only need a plain window for a start, set that to NULL. You can always look up stuff in the MVC Docs so I don't have to rewrite a lot of text that's been written in there already. Only to describe all the possible extended styles would require a new tutorial. Let's get back to the second parameter, and it is as simple as the window class name string. The next parameter is a pointer to a null terminated string that will appear in the window's title bar as the window's name. The next parameter specifies the style of the window. This is a little different than the first parameter(the extended style) and we need to let the window know what it will look like, will it have a title bar, etc. For a typical window with a title bar you will use the WS_OVERLAPPEDWINDOW flag. It is actually a combo of a bunch of other flags but they don't have to be ORed together so you would just use this flag alone to create a simple window quickly. Again, you can look up a whole horde of styles in the Docs. Good luck! I wanna go a lil off the purpose of this tutorial now and say that for full-screen applications this flag would have been set to WS_POPUP and it would have created a void window with no controls or borders. So now you know that even if it's a full-screen app it is still a window, it just has no controls and is stretched all over your monitor to cover the rest of windows and make you feel like nothing is behind. Let's move on. The rest of parameters is very obvious. The x and y position of the window on the screen (0,0) and it's width and height (300 x 300). Also don't forget to pass the instance of the app. The parameters I set to NULL are not needed for this tutorial and you can just ignore them for now. Another useful option is to look them up in the MVC Docs. Okay this was the last time I mentioned the MVC Docs on this web-site so, calm down and remember that they are always out there waiting for you to open them(unless you forgot to install them). And If you ever feel like I'm not explaining something it simply means you'll have to look it up. It will save time for both of us.

After the CreateWindowEx( ) is called you have to show whacha got. In other words you have to finally show the window on the screen. You do that by calling ShowWindow(SW_SHOW) followed by UpdateWindow(HWND hwnd) to "refresh" the window. At this point you have a successfully created window. The next part is creating the message loop. This is the loop your window goes around until the user closes the window or hits Alt-F4.

The message loop is nothing hard to comprehend. The program repeats itself while the quit flag is set to false. Whenever you set the quit flag to true the program should close the window and uninitialize itself. You have to see if there was a message and if there was you will process it. That's exactly what if(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) { ... } does. Then you test whether the message is WM_QUIT and if it is, break the loop by assigning true to the quit flag. It's done with a simple test in my program: if(msg.message == WM_QUIT) quit = true; If you omit these two lines the window will disappear after you close it, however the loop will go on and you'll end up with a "lost" application. TranslateMessage(&msg) and DispatchMessage(&msg) are self-explanatory.

At the ending point of your program you return control to windows. It's like calling return 0; from a console application.

article tab
Follow OpenGL Tutorials
You will only receive important news about OpenGL tutorial updates.
Who is joining?
  • Programmers You want to stay in touch to receive OpenGL tutorial updates.
  • Game Devs You're a game developer, and you also want to learn more about OpenGL!
  • Supporters You have invested interest in supporting OpenGL tutorial site.
Follow OpenGL Tutorials
Follow