a dialog based win32 c program

Upload: pavan-kumar

Post on 14-Apr-2018

234 views

Category:

Documents


9 download

TRANSCRIPT

  • 7/30/2019 A Dialog Based Win32 C Program

    1/12

    A dialog based Win32 C program, step by

    step

    1. Introduction

    When writing pure Win32 programs, usually you see tutorials showing how to use raw

    windows, by filling a WNDCLASSEX structure, calling RegisterClassEx and then

    CreateWindowEx. This is explained in detail in Charles Petzold's classicProgramming Windowsbooka must-have for any Win32 programmer, let me say.

    But sometimes you dont need to create a new window entirely from scratch, a simple dialog box

    would fit your needs.

    In this article, Ill discuss how to use a dialog box as the main window for your program, step by

    step, from scratch. A dialog box resource can be quickly createdwith labels, editboxes, andbuttonsusing any resource editor. Here Ill use Visual Studio 2008, but the steps should be

    similar for other Visual Studio versions, or even other IDEs.

    Ill use pure Win32 C code to keep things as simple as possible: noMFC, noATL, noWTL, or

    whatever. Ill also use the TCHAR functions (declared in tchar.h, more informationhere) to makethe code portable with ANSI and Unicode, and only functions that are both x86 and x64

    compatible.

    1.1. Program structure

    Our program will be composed of three files:

    C source filethe source code well effectively write, and the central theme of this article; RC resource script describes the dialog box resources, easily created by Visual Studio or any

    resource editor, or even by hand, and compiled with aresource compiler; and

    H resource header simply the macro constants used in the RC file to identify the resources,usually created automatically together with the RC script.

    2. The dialog box

    Before writing the C source code, well create an empty project and add a dialog box resource toit. When doing so, a resource script is created, containing the dialog box code. Lets start a new

    project:

    http://www.amazon.com/Programming-Windows%C2%AE-Fifth-Microsoft/dp/157231995X/ref=sr_1_3?ie=UTF8&qid=1310930429&sr=8-3http://www.amazon.com/Programming-Windows%C2%AE-Fifth-Microsoft/dp/157231995X/ref=sr_1_3?ie=UTF8&qid=1310930429&sr=8-3http://www.amazon.com/Programming-Windows%C2%AE-Fifth-Microsoft/dp/157231995X/ref=sr_1_3?ie=UTF8&qid=1310930429&sr=8-3http://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Libraryhttp://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Libraryhttp://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Libraryhttp://en.wikipedia.org/wiki/Active_Template_Libraryhttp://en.wikipedia.org/wiki/Active_Template_Libraryhttp://en.wikipedia.org/wiki/Active_Template_Libraryhttp://en.wikipedia.org/wiki/Windows_Template_Libraryhttp://en.wikipedia.org/wiki/Windows_Template_Libraryhttp://en.wikipedia.org/wiki/Windows_Template_Libraryhttp://www.codeproject.com/KB/string/cppstringguide1.aspxhttp://www.codeproject.com/KB/string/cppstringguide1.aspxhttp://www.codeproject.com/KB/string/cppstringguide1.aspxhttp://msdn.microsoft.com/en-us/library/aa381042%28v=VS.85%29.aspxhttp://msdn.microsoft.com/en-us/library/aa381042%28v=VS.85%29.aspxhttp://msdn.microsoft.com/en-us/library/aa381042%28v=VS.85%29.aspxhttp://msdn.microsoft.com/en-us/library/aa381042%28v=VS.85%29.aspxhttp://www.codeproject.com/KB/string/cppstringguide1.aspxhttp://en.wikipedia.org/wiki/Windows_Template_Libraryhttp://en.wikipedia.org/wiki/Active_Template_Libraryhttp://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Libraryhttp://www.amazon.com/Programming-Windows%C2%AE-Fifth-Microsoft/dp/157231995X/ref=sr_1_3?ie=UTF8&qid=1310930429&sr=8-3
  • 7/30/2019 A Dialog Based Win32 C Program

    2/12

    Choose Visual C++ and Win32 from the tree in the left, then Win32 project, and give a

    name to it. Pay attention to the directory you are saving it. Then click OK:

  • 7/30/2019 A Dialog Based Win32 C Program

    3/12

    Now choose Windows application and Empty project. When creating an empty project,

    Visual Studio will create no files for us, and this is important because here we want to create a

    pure Win32 program, with no additional libraries. Then, click Finish:

    Now, lets add the dialog box. In the Solution Explorer windowif you cant see it, enable it inthe View menu right-click the project name and choose Add, Resource:

  • 7/30/2019 A Dialog Based Win32 C Program

    4/12

    Here you can see a couple of resource items whose script can be generated automatically by

    Visual Studio. Well use just the dialog box, so choose Dialog and click New:

    Once done, you should see your dialog in the resource editor, where you can add controlslikeeditboxes, buttons, and labelsby just using the mouse, positioning and arranging them really

    quickmuch quicker than you would do with a raw window application, where you must deal

    with the code directly. My dialog looks like this:

  • 7/30/2019 A Dialog Based Win32 C Program

    5/12

    At this point, we have a resource script and a resource header, they can be seen in the Solution

    Explorer. Now its time to write the source code to bring this dialog box alive.

    3. The source code

    Lets add an empty source file to our project. In the Solution Explorer, right-click the SourceFiles folder, then Add, New Item. Then give any name to the file, like main.c.

    In Visual Studio, by default, the source files will be compiled according to the file extension: Cfiles compiled as plain C; and CPP, CXX (and some others) compiled as C++. Here well write

    C code, but it can also be compiled as C++, so the file extension can be any of those cited.

    Particularly, I used the C extension, to make it clear its a plain C program.

    Our C source will have only two functions:

    WinMain the program entry point, which will have the main program loop; and DialogProc the dialog box procedure, which will process the dialog messages.

    Lets start writing the code with the normal Win32 entry point function (the TCHAR version of it):

    Collapse |Copy Code

    #include

    http://msdn.microsoft.com/en-us/library/ms633559%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms633559%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms645469%28VS.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms645469%28VS.85%29.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://msdn.microsoft.com/en-us/library/ms645469%28VS.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms633559%28v=vs.85%29.aspx
  • 7/30/2019 A Dialog Based Win32 C Program

    6/12

    #include

    /* usually, the resource editor creates this file to us: */#include "resource.h"

    int _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPCTSTR lpCmdLine, int nCmdShow){

    return 0;}

    4. Dialog creation and message loop

    The dialog will be created inside the WinMain function with the CreateDialogParam function

    (instead ofCreateWindowEx), and there is nowindow classregistration. Then we make it visible

    with a call to ShowWindow:

    Collapse |Copy Code

    HWND hDlg;hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc,0);ShowWindow(hDlg, nCmdShow);

    IDD_DIALOG1 is the resource identifier to our dialog box, declared in resource.h. DialogProc isour dialog box procedure, which will handle all dialog messagesIll show it later on.

    Then it follows the main program message loop. Its the heart of any Win32 programsee it as

    the bridge between the operational system and your program. It also exists in common raw

    window programs, although slightly different from this. Here, the message loop is specifically

    to deal with a dialog box as the main window:

    Collapse |Copy Code

    BOOL ret;MSG msg;while((ret = GetMessage(&msg, 0, 0, 0)) != 0) {

    if(ret == -1) /* error found */return -1;

    if(!IsDialogMessage(hDlg, &msg)) {TranslateMessage(&msg); /* translate virtual-key messages */DispatchMessage(&msg); /* send it to dialog procedure */

    }

    }

    The IsDialogMessage function immediately forwards the message to our dialog box procedureif it belongs to it. Otherwise, the message enters regular handling. More information about the

    message loop can be foundhere.

    There is a possibility to bypass this program loop (not writing it), as explained by Iczelion in the

    10th

    lessonof his wonderful Win32 Assembly article series. However, by doing so, we have less

    http://msdn.microsoft.com/en-us/library/ms633574%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms633574%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms633574%28v=vs.85%29.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.winprog.org/tutorial/message_loop.htmlhttp://www.winprog.org/tutorial/message_loop.htmlhttp://www.winprog.org/tutorial/message_loop.htmlhttp://win32assembly.online.fr/tut10.htmlhttp://win32assembly.online.fr/tut10.htmlhttp://win32assembly.online.fr/tut10.htmlhttp://win32assembly.online.fr/tut10.htmlhttp://win32assembly.online.fr/tut10.htmlhttp://www.winprog.org/tutorial/message_loop.htmlhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://msdn.microsoft.com/en-us/library/ms633574%28v=vs.85%29.aspx
  • 7/30/2019 A Dialog Based Win32 C Program

    7/12

    control: we cannot put any verification in the loop, likeaccelerator handling, for example. So,

    lets keep the loop in our code.

    4.1. Enabling visual styles

    In order to get the common controls 6visual styles, introduced with Windows XP, you must notonly call InitCommonControls (declared in CommCtrl.h), but also embed a manifest XML fileinto your code. Fortunately, there is a handy trick you can use in the Visual C++ compiler, whichI learned fromRaymond Chen's blog. Just add this to your code:

    Collapse |Copy Code

    #pragma comment(linker, \"\"/manifestdependency:type='Win32' "\"name='Microsoft.Windows.Common-Controls' "\"version='6.0.0.0' "\"processorArchitecture='*' "\"publicKeyToken='6595b64144ccf1df' "\"language='*'\"")

    This will generate and embed the XML manifest file automatically, and youll never worry aboutit again.

    To call InitCommonControls, you must statically link your program to ComCtl32.lib, and this

    can be accomplished with a #pragma comment directive as well:

    Collapse |Copy Code

    #pragma comment(lib, "ComCtl32.lib")

    4.2. Our WinMain

    So far, this is our complete WinMain function (without the dialog box procedure yet):

    Collapse |Copy Code

    #include #include #include #include "resource.h"

    #pragma comment(linker, \"\"/manifestdependency:type='Win32' "\"name='Microsoft.Windows.Common-Controls' "\"version='6.0.0.0' "\"processorArchitecture='*' "\"publicKeyToken='6595b64144ccf1df' "\"language='*'\"")

    #pragma comment(lib, "ComCtl32.lib")

    http://msdn.microsoft.com/en-us/library/ms646337http://msdn.microsoft.com/en-us/library/ms646337http://msdn.microsoft.com/en-us/library/ms646337http://msdn.microsoft.com/en-us/library/hh270423%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/hh270423%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/hh270423%28v=vs.85%29.aspxhttp://blogs.msdn.com/b/oldnewthing/archive/2007/05/31/2995284.aspxhttp://blogs.msdn.com/b/oldnewthing/archive/2007/05/31/2995284.aspxhttp://blogs.msdn.com/b/oldnewthing/archive/2007/05/31/2995284.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://blogs.msdn.com/b/oldnewthing/archive/2007/05/31/2995284.aspxhttp://msdn.microsoft.com/en-us/library/hh270423%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms646337
  • 7/30/2019 A Dialog Based Win32 C Program

    8/12

    int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, intnCmdShow){

    HWND hDlg;MSG msg;BOOL ret;

    InitCommonControls();hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0,

    DialogProc, 0);ShowWindow(hDlg, nCmdShow);

    while((ret = GetMessage(&msg, 0, 0, 0)) != 0) {if(ret == -1)

    return -1;

    if(!IsDialogMessage(hDlg, &msg)) {TranslateMessage(&msg);DispatchMessage(&msg);

    }

    }

    return 0;}

    5. Dialog box procedure

    The dialog procedure is responsible for handling all program messages, responding to all events.

    It starts like this:

    Collapse |Copy Code

    INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAMlParam){

    return FALSE;}

    Windows calls this function for every program message. If we return FALSE, it means Windowscan carry out the default processing for the message, because were not interested in it; if we

    return TRUE, we tell Windows weve actually processed the message. This is slightly different

    from the raw window message handling throughWndProc, where you return a call to the

    DefWindowProc function. Here, we must not call DefWindowProc, just return FALSE.

    So, well write only the handling of messages that are interesting to us. Among the mostcommonly used messages, we have WM_INITDIALOG, WM_COMMAND, and WM_SIZE. But to build aminimal functional program, we need only two:

    Collapse |Copy Code

    switch(uMsg){

    http://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://msdn.microsoft.com/en-us/library/ms633573%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms633573%28v=vs.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ms633573%28v=vs.85%29.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://msdn.microsoft.com/en-us/library/ms633573%28v=vs.85%29.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspx
  • 7/30/2019 A Dialog Based Win32 C Program

    9/12

    case WM_CLOSE: /* there are more things to go here, */return TRUE; /* just continue reading on... */

    case WM_DESTROY:return TRUE;

    }

    Notice we dont need to handle the WM_PAINT message with dialog boxes.

    5.1. The minimal message handling

    WM_CLOSE is called just prior to window closing. If you want to ask the user if he really wants toclose the program, here is the place to put this check. To close the window, we call

    DestroyWindowif we dont call it, the window wont be closed.

    So heres the message handling, also prompting the user. If you dont need to prompt the user,

    just omit the MessageBox check and call DestroyWindow directly. And dont forget to return

    TRUE here, whether you close the window or not:

    Collapse |Copy Code

    case WM_CLOSE:if(MessageBox(hDlg,TEXT("Close the window?"), TEXT("Close"),MB_ICONQUESTION | MB_YESNO) == IDYES)

    {DestroyWindow(hDlg);

    }return TRUE;

    Finally, we must handle the WM_DESTROY message, telling Windows we want to quit the mainprogram thread. We do this by calling the PostQuitMessage function:

    Collapse |Copy Code

    case WM_DESTROY:PostQuitMessage(0);return TRUE;

    The WM_DESTROY message is also the best place to free resources that were allocated by theprogram and are still waiting to be deallocatedits final cleanup time. But dont forget to do

    the cleanup before calling PostQuitMessage.

    5.2. Closing on ESC

    An interesting feature of the dialog boxes is that they can be easily programmed to be closedwhen the user hits the ESC key, and it can also be done when the dialog box is the main window

    as well. To do so, we must handle the WM_COMMAND message and wait for the IDCANCEL identifier,

    which comes in the low word of the WPARAMargument, and thats what we do:

    http://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspx
  • 7/30/2019 A Dialog Based Win32 C Program

    10/12

    Collapse |Copy Code

    case WM_COMMAND:switch(LOWORD(wParam)){case IDCANCEL:

    SendMessage(hDlg, WM_CLOSE, 0, 0);return TRUE;}break;

    The IDCANCEL identifier is declared in WinUser.h, which is included in Windows.h, so itsalways available.

    Notice that when handling IDCANCEL, we send a WM_CLOSE message to our dialog window, which

    causes the dialog procedure to be called again with the WM_CLOSE message that we previouslycoded, so the user will be prompted if he wants to close the window (because thats the way we

    coded it).

    6. The final program

    So here is ourfinal program. Its the C source code for a minimally functional Win32 dialog

    based program, with the message loop and visual styles properly enabled, just ready to go. Youcan keep this to use as the skeleton for any Win32 dialog based program.

    Collapse |Copy Code

    #include #include

    #include #include "resource.h"

    #pragma comment(linker, \"\"/manifestdependency:type='Win32' "\"name='Microsoft.Windows.Common-Controls' "\"version='6.0.0.0' "\"processorArchitecture='*' "\"publicKeyToken='6595b64144ccf1df' "\"language='*'\"")

    #pragma comment(lib, "ComCtl32.lib")

    INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM

    lParam){

    switch(uMsg){case WM_COMMAND:switch(LOWORD(wParam)){case IDCANCEL:

    SendMessage(hDlg, WM_CLOSE, 0, 0);

    http://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspx
  • 7/30/2019 A Dialog Based Win32 C Program

    11/12

    return TRUE;}break;

    case WM_CLOSE:if(MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"),

    MB_ICONQUESTION | MB_YESNO) == IDYES){

    DestroyWindow(hDlg);}return TRUE;

    case WM_DESTROY:PostQuitMessage(0);return TRUE;

    }

    return FALSE;}

    int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, intnCmdShow){

    HWND hDlg;MSG msg;BOOL ret;

    InitCommonControls();hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0,

    DialogProc, 0);ShowWindow(hDlg, nCmdShow);

    while((ret = GetMessage(&msg, 0, 0, 0)) != 0) {if(ret == -1)

    return -1;

    if(!IsDialogMessage(hDlg, &msg)) {TranslateMessage(&msg);DispatchMessage(&msg);

    }}

    return 0;}

    7. Further organization

    Usually, when your program grows in complexity, youll end up with a huge DialogProc stuffedwith code, and therefore very painful to maintain. A useful approach to this is the use of functioncalls to each messagethe famoussubroutines. Its specially handy because it isolates the logic

    of the code, you can see clearly each part of the program, giving you the notion of responding to

    events. For example, our program could have two dedicated functions:

    Collapse |Copy Code

    http://en.wikipedia.org/wiki/Subroutinehttp://en.wikipedia.org/wiki/Subroutinehttp://en.wikipedia.org/wiki/Subroutinehttp://en.wikipedia.org/wiki/Event_%28computing%29http://en.wikipedia.org/wiki/Event_%28computing%29http://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://en.wikipedia.org/wiki/Event_%28computing%29http://en.wikipedia.org/wiki/Subroutine
  • 7/30/2019 A Dialog Based Win32 C Program

    12/12

    void onCancel(HWND hDlg){

    SendMessage(hDlg, WM_CLOSE, 0, 0);}

    void onClose(HWND hDlg){

    if(MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"),MB_ICONQUESTION | MB_YESNO) == IDYES)

    {DestroyWindow(hDlg);

    }}

    And it would allow us to rewrite ourDialogProc like this:

    Collapse |Copy Code

    INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM

    lParam){

    switch(uMsg) /* more compact, each "case" through a single line, easier onthe eyes */

    {case WM_COMMAND:switch(LOWORD(wParam)){case IDCANCEL: onCancel(hDlg); return TRUE; /* call subroutine */}break;

    case WM_CLOSE: onClose(hDlg); return TRUE; /* call subroutine */case WM_DESTROY: PostQuitMessage(0); return TRUE;}

    return FALSE;}

    http://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspxhttp://www.codeproject.com/KB/dialog/dialog-based-win32-c.aspx