You are on page 1of 5

// A small piece of mine.

I use this in an OpenGL project LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // Get The Window Context GL_Window* window = (GL_Window*)(GetWindowLong (hWnd, GWL_USERDATA)); switch (uMsg) // Evaluate Window Message { case WM_ACTIVATE: { switch(wParam) { case WA_INACTIVE: SetWindowPos(window->hWnd, WND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // it ignores the x, y and cx, cy because of SWP_NOMOVE and SWP_NOSIZE return 0; } break; } return 0;

First of all, this programming tutorial is not for the faint of heart. Producing a window in C++ is one of the ugliest practices of coding around. You may even find yourself wondering if this is really Object-Oriented Programming. Enough with the talking, time to get down to the nitty gritty. Creation of the project requires you to produce a new empty win32 application. This will include the correct libraries for compilation. So when you create a project, make sure you are creating a Win32 Application. As with all Win32 applications, we need to include the correct header file for the window. Calls to win32 and any ambiguous (public) class methods will be offset with a (::) to let the user know that this is a public method that has

been precreated in the windows.h file. So the first line, as you may have guessed already is: #include <windows.h> The next few lines may seem to go pretty quickly but bare with me. First, what I will do is define a global method that will be used to control any system calls that windows throws at our window. Then I will define a class (trying to keep in OOP perspective) that will create our window, in this case, just one window. No definition of the window procedure will result in an abstract class, which could get us into a mess. So we will not work around this, instead, we will aquire 1 thing: The call to dispose the frame. LPARAM and WPARAM are two parameters that define furthur adjustments (specifics) to our window. Take a look:
LRESULT CALLBACK WindowProcedure(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam); class MyWindow { public: MyWindow(WNDPROC winProc, char const * className, HINSTANCE hInst); void Register() { ::RegisterClass(&_class); } private: WNDCLASS _class; }; MyWindow::MyWindow(WNDPROC winProc, char const * className, HINSTANCE hInst) { _class.style = 0; // Windows Style (future article) _class.lpfnWndProc = winProc; // The Window Procedure _class.cbClsExtra = 0; // Extra memory for this class _class.cbWndExtra = 0; // Extra memory for this window _class.hInstance = hInst; // The definition of the instance of the application _class.hIcon = 0; // The icon in the upper left corner _class.hCursor = ::LoadCursor(0, IDC_ARROW); // The cursor for this window _class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // The background color for this window _class.lpszMenuName = 0; // The name of the class for the menu for this window _class.lpszClassName = className; // The name of this class }

Now that the window is registered, we can now create the window!. This is done calling the CreateWindow() method. This method can get very ugly as it requires us to pass a lot of arguments essential to creating the window for view. Some of these arguments will be set to a NULL value (0) as we will not be using them right now. We may find some use for them later down the road, but for the KISS (Keep It Simple Stupid) principle, NULL values will be used.
class WindowCreator { public: WindowCreator() : _hwnd(0) {} // Inline contructor WindowCreator(char const * caption, char const * className, HINSTANCE hInstance); void SetVisible(int cmdShow) { // Makes the window visible after it is created ::ShowWindow(_hwnd, cmdShow); ::UpdateWindow(_hwnd); } protected: HWND _hwnd; }; WindowCreator::WindowCreator(char const * caption, char const * className, HINSTANCE hInstance) { _hwnd = ::CreateWindow( className, // Name of the registered window class caption, // Window Caption to appear at the top of the frame WS_OVERLAPPEDWINDOW, // The style of window to produce (overlapped is standard window for desktop) CW_USEDEFAULT, // x position of the window CW_USEDEFAULT, // y position of the window CW_USEDEFAULT, // width of the window CW_USEDEFAULT, // height of the window 0, // The handle to the parent frame (we will use this later to simulate an owned window) 0, // The handle to the menu for this window (we will learn to create menus in a later article) hInstance, // the application instance 0); // window creation data }

Now comes the part of the code that defines the main window procedure. Without this method declaration, the program could not run as a win32 application. This mimics the int main{} method of a DOS program. This is where we will instantiate our classes and assign a windows procedure to the window enabling our window to exist and take input focus. Aquiring the message's wParam (public) will allow use the return statement for our whole program (whether a troolean statement.) Microsoft in all their bright ideas came up

with the troolean. Much like the boolean staement, it does return true and false, but it also contains one more parameter which is error. WM_QUIT is equal to 0, a nonzero is another constant besides WM_QUIT, and -1 is an error. When we come into cotact with windows messages that we do not wish to mess with, the DispatchMessage() method is called telling windows that we do not wish to mess with this message. However, we will return a -1 (error) and exit the WinMain method closing the program on a -1 return. This will close the program if an error occurs.
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, char * cmdParam, int cmdShow) { char className[] = "Program"; MSG msg; int status; MyWindow myWindow(WindowProcedure, className, hInst); myWindow.Register(); WindowCreator window("Programming Is Fun!", className, hInst); window.SetVisible(cmdShow); while((status = ::GetMessage(&msg, 0, 0, 0)) != 0) { if(status == -1) { return -1; } ::DispatchMessage(&msg); } } return msg.wParam;

Simple enough? Yeah right. I know you are scratching your head. It took me ages to learn this part as you are barraged with a lot of information to hold. Don;t worry it will get easier as you progress. But to tell you the truth, this is the EASIEST form of creating this window. DeviceContexts and RenderingContexts and PixelFormatDescriptors will be intorduced later and you will be left in the dark without further reading, but I mean not to scare you away, but rather to encourage you. Alrighty, now for that last portion of the program: detecting window procedures! This section (IMO) is the easiest on and where most of the magic happens (user input wise). We will be searching for the WM_DESTROY constant as this syscall tells the windows to dispose of itself. All you may recall, we defined this method globally in the beginning of the program. This is to get csome of the mess out of one method and into seperate ones for legibility purposes. To dispose of the window, all we have to do is return a 0 value, which tells the windows application to exit without any errors.
LRESULT CALLBACK WindowProcedure(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam) { switch(message) {

} }

case WM_DESTROY: ::PostQuitMessage(0); return 0;

return ::DefWindowProc(hwnd, message, wParam, lParam);

Compile and run! Does it work? Next we will focus on more experienced aspects of creating a window as well as creating a canvas for drawing.

You might also like