понедељак, 12. децембар 2011.

C++ Win32 API Tutorial


C++ Win32 API Tutorial

 
You may have already done quite a bit of console programming with C++. Although, you probably wondered how they get those nice graphical user interfaces (GUI) in windows programs that don't have a black screen. Well, these GUI programs are called Win32 API programs. Learn how to make buttons, windows, text edits, and other GUI objects in Windows 32 programming.
They use the windows 32-bit Application programming interface, which basically means interacting with Windows operating systems such as Windows XP or Vista. In this tutorial, you will learn how to use C++ with the Win32 APIto make wonderful Windows Applications.
Windows programs register themselves on the operating system and work with one loop for messages. In addition, the message loop goes through a process function that handles all the windows messages and delivers what the user or operating system demands.
The most common windows messages are WM_CREATEWM_DESTROY, and WM_COMMAND. WM Stands forWindows Message. CREATE handles the initial message that the program receives upon registering itself with the windows operating system''s process list. You can add most of your GUI code inside WM_CREATE, and any other code that initializes the program. WM_DESTROY would be for any variables you need to delete or GUI you need to clean up to avoid memory leaks; it is also used for saving last minute settings, like the state of the program was left last. WM_COMMAND is basically your event handler, and you handle all sorts of messages for your buttons or GUI, and messages from other programs or any other user input.
Our first example will create a window with one button that will pop up a message box when clicked.
#include <windows.h>

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

Ok, first we included our windows.h, this is the main header that links the Win32 API with your program.
We then declare a prototype WindowProcedure function defined as an LRESULT CALLBACK, which is just a windows data type for certain functions. A prototype is a function that is defined at the top but will be declared later on in the program, so you will see this same function again but with actual code later. We declare the arguments for this function as HWND, UINT, WPARAM, and LPARAM.
HWNDs are usually used for GUI elements; they represent the actual window or window elements of a program. UINT is an unsigned integer and WPARAM and LPARAM are parameter messages that windows uses to add more data into a message.
#define IDBUTTON 102

/*  Make the class name into a global variable  */
char szClassName[ ] = "MyFirstProgram";
HINSTANCE g_hInst;

It is important to declare your globals and definitions at the top of your program. IDBUTTON is our id defined as 102, which is a standard definition for a GUI control ID. We will use this definition to link our button to handle what happens in the event that the button is clicked. HINSTANCE is the program's instance; it is used to define what program a GUI belongs to. We declared it globally because we are going to use it throughout the program. szClassName is the class name that the Windows Operating system requires us to register the program with.

WINAPI WinMain Function

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil) {
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    g_hInst = hThisInstance;
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows''s default color as the background of the window */
    wincl.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;
We define our WinMain program, which is a special function that windows OS recognizes. We declare the HWND of our main program, which is the main window of the program. We then declare the MSG of our program that we will use to create our Windows message loop. In addition, we create the object of WNDCASSEX which is the structure used to register some data about our program in Windows OS.

Message Event Loop For Windows

After we define our data, we register our class and check for any errors.
    /* The class is registered, let''s create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "MyFirstProgram v1.0.0.0",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           230,                 /* The programs width */
           75,                  /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, SW_SHOW);
    UpdateWindow(hwnd);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL00))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }
    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}
We use CreateWindowEx to build our main window GUI. We define some information about what kind of window we are creating.
We then show the window, update it, and begin our message loop so that our program can actually communicate with the operating system.

Windows Procedure Callback

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
    HWND hwndButton;
    switch (message) {                 /* Handles all Windows Messages */
        case WM_COMMAND:{
              if(((HWND)lParam) && (HIWORD(wParam) == BN_CLICKED)){
                int iMID;
                iMID = LOWORD(wParam);
                switch(iMID){
                  case IDBUTTON:{
                       MessageBox(hwnd, (LPCTSTR)"You just pushed me!",  (LPCTSTR) "My Program!", MB_OK|MB_ICONEXCLAMATION);
                       break;
                       }
                  default:
                       break;
                }
              }
              break;
            }
        case WM_DESTROY:{
              PostQuitMessage (0);       /* send a WM_QUIT to Message Queue, to shut off program */
              break;
             }
The Window Procedure function is the Win32 API way of sending and receiving Windows messages declared as WM_ .
We define the actual function that we prototyped earlier in the program. We create an HWND for the button, and declare each of our window messages and process them.
In WM_COMMAND, we use a switch to look at the LPARAM and WPARAM parameters, and decide what command has been sent to us and about which control. If we receive the correct message that states our button was clicked, we show a message box.
In WM_DESTROY, we declare PostQuitMessage(0), to exit our program. This message is activated when the X button is clicked on our title bar.

Window Message Create

        case WM_CREATE:{
               hwndButton = CreateWindowEx(0,                    /* more or ''extended'' styles */
                         TEXT("BUTTON"),                         /* GUI ''class'' to create */
                         TEXT("Push Me"),                        /* GUI caption */
                         WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,   /* control styles separated by | */
                         10,                                     /* LEFT POSITION (Position from left) */
                         10,                                     /* TOP POSITION  (Position from Top) */
                         200,                                    /* WIDTH OF CONTROL */
                         30,                                     /* HEIGHT OF CONTROL */
                         hwnd,                                   /* Parent window handle */
                         (HMENU)IDBUTTON,                        /* control''s ID for WM_COMMAND */
                         g_hInst,                                /* application instance */
                         NULL);
               break;
             }
        default:                      /* messages that we will not process */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
In WM_CREATE we use CreateWindowEx to create a graphical control as a button. We define the text we use, the styles, the positions, the sizes, the parent window, our menu ID which we use in WM_COMMAND, and declare which HINSTANCE this control belongs to.
Default is called when a message comes that we do not want to handle. Of course at the end of our program we return 0, since we declared the function as an int, and windows waits for us to return a zero.
Some C++ and Win32 Data types

DataTypes

You do not need to know the following datatypes in order to use Win32 API, the lesson here is, that most Win32 datatypes are similar, if not the same as C++ datatypes. You are free to use standard C++ datatypes to express any Win32 datatypes. A lot of the datatypes in Win32 API, are synonyms and are not really that important to know, but I''ll give you a quick reference anyway:
-BOOL is a windows datatype that is an equal representation of the simple bool used in C++. Its value can either be true or false.
-WORD This is a 16-bit integer, that is similar to long. Specifically used for some windows functions. It is the equivalent of unsigned short in C++.
-FLOAT is the equivalent of float in C++.
-UINT is the equivalent of unsigned int in C++.
-WINAPI, APIENTRY, CALLBACK, APIPRIVATE, STDCALL are all exactly the same as __stdcall in C++, which is the standard calling convention.
-CDECL, WINAPIV, are both the same as __cdecl calling convention in C++.
-FASTCALL is the same as __fastcall calling convention in C++.
-PASCAL is the same as __pascal calling convention in C++.
-WPARAM equivalent to an unsigned int pointer, and is used in Windows Messages.
-LPARAM in Win32 API this is used for Windows Messages, starting with prefix WM_, but is actually a pointer to along.
-LRESULT Same as HRESULT or LONG/long, but a pointer to the long.
-INT Standard integer datatype, same as int in C++ (signed).
-BYTE is a synonym for unsigned char in C++. It is used for text characters.
-DWORD This is similar to LONG or long in standard C++.
-LONG is a substitute for INT.
-HRESULT is the exact equivalent of a long in C++.
-HANDLE This is a standard long in Win32 API, but usually used to indicate a GUI object, graphical object, or some other win32 objects.
-HINSTANCE This is also a long similar to HANDLE except used to declare the instance of a windows program. Similar to a window ID for each object in win32.
-HWND This long is used to indicate the window object itself, hence the name H-Wind(ow).
-LPSTR Pointer to a string in Win32.
-LPCSTR This object is a long pointer to a constant string.
-LPTSTR This long pointer is equivalent to LPSTR, but there are two versions of this function, one expecting an ANSI string, and the other expecting a Unicode string.
-LPCTSTR This is a combination of TCHARs in an LPTSTR. It can contain unicode or ANSI.

Learning Win32 API C++ Programming

Of course there are many more Window Messages that you could handle, and many more CreateWindowEx classes that we can use in our program, including many other GUI functions that we can show instead of a message box. For further reading and learning about more messages I ask that you favorite this tutorial andhttp://msdn.microsoft.com/library
I tried to make this tutorial as simple as possible to follow for beginners and also enough examples for many of you to understand the structure of a windows program. However, I'm sure that one will have many questions about the various functions and data types.
You may have already done quite a bit of console programming with C++. Although, you probably wondered how they get those nice graphical user interfaces (GUI) in windows programs that don't have a black screen. Well, these GUI programs are called Win32 API programs.

Нема коментара:

Постави коментар