Thread: Is this the correct way to handle button messages?

  1. #1
    Registered User
    Join Date
    Jan 2013
    Posts
    13

    Is this the correct way to handle button messages?

    I'm very new to Windows programming. The basic problem is I don't know what I'm doing. :-)

    This code works correctly, but the message handling looks kludgy (especially the casting required to make it work). I want to make sure that I'm doing this the correct way, and didn't produce code that works sometimes but not always.


    One window, with two buttons on it. Click button 1, a message window pops saying 'button 1 was clicked' ... click button 2, message window pops saying 'button 2 was clicked' ... simple enough.

    Code snippets:

    Two global variables in callbacks.c:
    Code:
    HWND g_hwndButton1, g_hwndButton2;

    Creating the buttons:
    Code:
        case WM_CREATE:
        {
    
          hInstance = ((LPCREATESTRUCT) lParam)->hInstance;
    
    
    
          g_hwndButton1 = CreateWindow(
            L"BUTTON",  // Predefined class; Unicode assumed
            L"OK",      // Button text
            WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles
            10,         // x position
            10,         // y position
            100,        // Button width
            30,         // Button height
            hWnd,       // Parent window
            NULL,       // No menu.
            (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
            NULL);      // Pointer not needed.
    
    
          g_hwndButton2 = CreateWindow(
            L"BUTTON",  // Predefined class; Unicode assumed
            L"OK",      // Button text
            WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles
            10,         // x position
            80,         // y position
            100,        // Button width
            30,         // Button height
            hWnd,       // Parent window
            NULL,       // No menu.
            (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
            NULL);      // Pointer not needed.


    And handling the clicks:
    Code:
        case WM_COMMAND:
        {
          switch (LOWORD(wParam))
          {
    
            case BN_CLICKED:
            {
              // which button?
              if( lParam == (int)g_hwndButton1 ) {
                  MessageBox(hWnd, (LPCWSTR)L"Button 1 was clicked / WM_COMMAND", (LPCWSTR)L"Yay", MB_OK | MB_ICONINFORMATION);
                  return 0;
              } else if( lParam == (int)g_hwndButton2 ) {
                  MessageBox(hWnd, (LPCWSTR)L"Button 2 was clicked / WM_COMMAND", (LPCWSTR)L"Yay", MB_OK | MB_ICONINFORMATION);
                  return 0;
              }
              break;
            }

    Again, this works, but feels like I should be doing it differently.

    In particular, when I put the (int) casting here
    Code:
    if( lParam == (int)g_hwndButton1 )
    I felt like I was committing a crime, that the "right" way to do it would be less kludgy.

    Some feedback would be appreciated. Thank you.

  2. #2
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    Oh boy! Haven't posted here for ages! And I come by and find an easy question! Oh Boy! I love easy questions!

    Anyway, that's not quite right 168gr. I prefer 165 grain boattails for my 30-06 loads. But anyway, here's a whole program with two buttons. Check out the WM_CREATE and WM_COMMAND handlers - fnWndProc_OnCreate() and fnWndProc_OnCommand ...

    // 1st the little header
    Code:
    //Form3.h
    #ifndef Form_h
    #define Form_h
    
    #define  IDC_BUTTON1          1500
    #define  IDC_BUTTON2          1505
    
    #define dim(x) (sizeof(x) / sizeof(x[0]))
    
    struct WndEventArgs
    {
     HWND                         hWnd;
     WPARAM                       wParam;
     LPARAM                       lParam;
     HINSTANCE                    hIns;
    };
    
    long fnWndProc_OnCreate       (WndEventArgs& Wea);
    long fnWndProc_OnCommand      (WndEventArgs& Wea);
    long fnWndProc_OnDestroy      (WndEventArgs& Wea);
    
    struct EVENTHANDLER
    {
     unsigned int                 iMsg;
     long                         (*fnPtr)(WndEventArgs&);
    };
    
    const EVENTHANDLER EventHandler[]=
    {
     {WM_CREATE,                  fnWndProc_OnCreate},
     {WM_COMMAND,                 fnWndProc_OnCommand},
     {WM_DESTROY,                 fnWndProc_OnDestroy}
    };
    #endif
    // Then main cpp source
    Code:
    //Form3.cpp
    #include <windows.h>
    #include <tchar.h>
    #include "Form3.h"
    
    
    long fnWndProc_OnCreate(WndEventArgs& Wea)
    {
     HWND hCtl;
    
     Wea.hIns=((LPCREATESTRUCT)Wea.lParam)->hInstance;
     hCtl=CreateWindow(_T("button"),_T("Button #1"),WS_CHILD | WS_VISIBLE,75,60,150,30,Wea.hWnd,(HMENU)IDC_BUTTON1,Wea.hIns,0);
     hCtl=CreateWindow(_T("button"),_T("Button #2"),WS_CHILD | WS_VISIBLE,75,110,150,30,Wea.hWnd,(HMENU)IDC_BUTTON2,Wea.hIns,0);
    
     return 0;
    }
    
    
    long fnWndProc_OnCommand(WndEventArgs& Wea)
    {
     switch(LOWORD(Wea.wParam))
     {
        case IDC_BUTTON1:
             MessageBox(Wea.hWnd,_T("You Thought About It Then Chose And Clicked Button #1!"),_T("Received WM_COMMAND Message!"),MB_OK);
             break;
        case IDC_BUTTON2:
             MessageBox(Wea.hWnd,_T("You Thought About It Then Chose And ClickedButton #2!"),_T("Received WM_COMMAND Message!"),MB_OK);
             break;
     }
    
     return 0;
    }
    
    
    long fnWndProc_OnDestroy(WndEventArgs& Wea)
    {
     PostQuitMessage(0);
     return 0;
    }
    
    
    
    LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
    {
     WndEventArgs Wea;
    
     for(unsigned int i=0; i<dim(EventHandler); i++)
     {
         if(EventHandler[i].iMsg==msg)
         {
            Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
            return (*EventHandler[i].fnPtr)(Wea);
         }
     }
    
     return (DefWindowProc(hwnd, msg, wParam, lParam));
    }
    
    
    int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
    {
     TCHAR szClassName[]=_T("Form3");
     WNDCLASSEX wc;
     MSG messages;
     HWND hWnd;
    
     wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
     wc.cbSize=sizeof (WNDCLASSEX);               wc.style=CS_DBLCLKS;
     wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
     wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
     wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=0;
     wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
     RegisterClassEx(&wc);
     hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,75,75,320,305,HWND_DESKTOP,0,hIns,0);
     ShowWindow(hWnd,iShow);
     while(GetMessage(&messages,NULL,0,0))
     {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
     }
    
     return messages.wParam;
    }
    Note you needn't use any global variables in Windows GUI programs. Your HWNDs of the button controls created in W_CREATE don't need to be saved. At any time at any place in your program you can retrieve the Control ID of a control (the (HMENU) typed parameter of the CreateWindow() call) using GetDlgItem(). And in any case, in WM_COMMAD processing the LOWORD of wParam will contain the control id of the control sending a WM_COMAND message to its parent.

    The reason my code looks like nothing you've ever seen is because it uses my message cracker scheme. I wasn't smart enough to figure that out by myself. I appropriated it from Douglas Boling. And he appropriated it from Ray Duncan. Instead of using a switch construct to route program flow, it uses a for loop.
    Last edited by freddie; 01-26-2013 at 06:50 PM.

  3. #3
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148

    You Already Got A usable hInstance

    Further, why did you use this in your CreateWindow() calls for the hInstance ...

    (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE) ?

    You already got the hInstance by casting the lParam received in your WM_CREATE handler to a LPCREATESTRUCT, and from that the correct hInstance.

  4. #4
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    See, where you went wrong is this - you didn't fill out the CreateWindow() calls to create your buttons correctly....

    Code:
    g_hwndButton1 = CreateWindow(
        L"BUTTON",  // Predefined class; Unicode assumed
        L"OK",      // Button text
        WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles
        10,         // x position
        10,         // y position
        100,        // Button width
        30,         // Button height
        hWnd,       // Parent window
        NULL,       // No menu.
        (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
        NULL);      // Pointer not needed.
    For your 9th parameter you have this ...
    NULL, // No menu.

    That parameter has a dual role. If the CreateWindow() call is to create a main program window - possibly with a menu, then an HMENU can go there. But for child window controls, i.e., buttons, edit controls, combo boxes, etc., an integral numeric id goes in there. You choose these yourself. For example, look at my ...

    #define IDC_BUTTON1 1500
    #define IDC_BUTON2 1505

    in my code in the Form3.h file. Those ids (cast to HMENU) go in the 9th parameter of the CreateWindow() call. Then when you click one of those buttons, the id will be found in thw LOWORD(wParam). Verstehen Sie?

  5. #5
    Registered User
    Join Date
    Jan 2013
    Posts
    13
    Quote Originally Posted by freddie View Post
    Oh boy! Haven't posted here for ages! And I come by and find an easy question! Oh Boy! I love easy questions!

    Anyway, that's not quite right 168gr. I prefer 165 grain boattails for my 30-06 loads.
    The 168 Amax does great in my .308 but actually I'm finding that the 175 SMKs are maybe a bit better past 7-800 yards ...


    Thanks for responding. That looks so much cleaner ...


    Quote Originally Posted by freddie View Post
    Further, why did you use this in your CreateWindow() calls for the hInstance ...

    (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE) ?

    You already got the hInstance by casting the lParam received in your WM_CREATE handler to a LPCREATESTRUCT, and from that the correct hInstance.
    I did it that way because that's the way some tutorial told me to do it. :-)



    Quote Originally Posted by freddie View Post
    See, where you went wrong is this - you didn't fill out the CreateWindow() calls to create your buttons correctly....

    Code:
    g_hwndButton1 = CreateWindow(
        L"BUTTON",  // Predefined class; Unicode assumed
        L"OK",      // Button text
        WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles
        10,         // x position
        10,         // y position
        100,        // Button width
        30,         // Button height
        hWnd,       // Parent window
        NULL,       // No menu.
        (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
        NULL);      // Pointer not needed.
    For your 9th parameter you have this ...
    NULL, // No menu.

    That parameter has a dual role. If the CreateWindow() call is to create a main program window - possibly with a menu, then an HMENU can go there. But for child window controls, i.e., buttons, edit controls, combo boxes, etc., an integral numeric id goes in there. You choose these yourself. For example, look at my ...

    #define IDC_BUTTON1 1500
    #define IDC_BUTON2 1505

    in my code in the Form3.h file. Those ids (cast to HMENU) go in the 9th parameter of the CreateWindow() call. Then when you click one of those buttons, the id will be found in thw LOWORD(wParam). Verstehen Sie?
    That code is straight off the Microsoft tutorial ...

    How to Create a Button (Windows)

    Figures that they'd try to sabotage me.


    Thanks for your help!

  6. #6
    Registered User
    Join Date
    Jan 2013
    Posts
    13
    I don't suppose you have that in straight C, do you?

    I can probably tweak it and get past those passing-argument-by-reference bits by just passing pointers (and defining the structures in the C-style typedef struct{} name; fashion), but I don't even know what this syntax is
    Code:
    struct EVENTHANDLER {
      unsigned int                 iMsg;
      long                         (*fnPtr)(WndEventArgs&);
    }; 
    
    const EVENTHANDLER EventHandler[]=
    {
     {WM_CREATE,                  fnWndProc_OnCreate},
     {WM_COMMAND,                 fnWndProc_OnCommand},
     {WM_DESTROY,                 fnWndProc_OnDestroy}
    };
    and my C compiler doesn't either ...

    Complicating matters is that I'm working in a unixish environment on Windows (cygwin).
    Last edited by 168gr; 01-27-2013 at 10:00 AM.

  7. #7
    Registered User
    Join Date
    Jan 2013
    Posts
    13
    FWIW, I have it functioning with some of your corrections, but not your organization / scheme:

    Making the buttons:
    Code:
        case WM_CREATE:
        {
          hCtl = CreateWindow(
            L"BUTTON",  // Predefined class; Unicode assumed
            L"OK",      // Button text
            WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles
            10,         // x position
            10,         // y position
            100,        // Button width
            30,         // Button height
            hWnd,       // Parent window
            (HMENU)IDC_BUTTON1,
            (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
            NULL);      // Pointer not needed.
    
    
          hCtl = CreateWindow(
            L"BUTTON",  // Predefined class; Unicode assumed
            L"OK",      // Button text
            WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles
            10,         // x position
            80,         // y position
            100,        // Button width
            30,         // Button height
            hWnd,       // Parent window
            (HMENU)IDC_BUTTON2,
            (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
            NULL);      // Pointer not needed.
    
          return 0;
        }
    And handling the clicks ...
    Code:
        case WM_COMMAND:
        {
          switch (LOWORD(wParam))
          {
            case IDC_BUTTON1:
            {
              MessageBox(hWnd, (LPCWSTR)L"Button 1 was clicked / WM_COMMAND", (LPCWSTR)L"Yay", MB_OK | MB_ICONINFORMATION);
              return 0;
            }
            case IDC_BUTTON2:
            {
              MessageBox(hWnd, (LPCWSTR)L"Button 2 was clicked / WM_COMMAND", (LPCWSTR)L"Yay", MB_OK | MB_ICONINFORMATION);
              return 0;
            }

  8. #8
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    Sure 168gr. Give me a few minutes to work it up. I'll repost it in C two ways. I didn't pick up on the fact your were compiling as C. I'm pretty much a C coder myself, but I always compile as C++. Funny about my message crackers! Just the other day I changed the code to use references instead of pointers. It cleaned it up and made the code more readable. All that's going on there is that this ...

    Code:
    struct EVENTHANDLER 
    {
      unsigned int                 iMsg;
      long                         (*fnPtr)(WndEventArgs&);
    };
    is creating a struct or UDT (user defined type) that contains two integral quantities, not really much different from this

    Code:
    struct EVENTHANDLER
    {
     unsigned int   iMsg;
     unsigned int   fnFunctionAddress;
    };
    So what that does is associate together in one 'object' an unsigned integer, which, in my scheme above will be one of the integral constants from, I believe "WinUser.h", e.g., WM_COMMAND, WM_CREATE, WM_DESTROY, with the address of a function within a program that will 'handle' that particular message. So this then ...
    Code:
    const EVENTHANDLER EventHandler[]=
    {
     {WM_CREATE,                  fnWndProc_OnCreate},
     {WM_COMMAND,                 fnWndProc_OnCommand},
     {WM_DESTROY,                 fnWndProc_OnDestroy}
    };
    ...creates a const array of EVENTHANDLER objects, with each object in the array being a message constant, e.g., WM_CREATE, WM_COMMAND, etc., and the address of the function that handles that const message.

    It can be easily set up with pointers instead of references. In fact, that is how it was originally in Douglas Boling's book "Programming Windows CE", where I found it years ago. Gimme a minute and I'll post it.

  9. #9
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    I'm too dumb to fix it. I can't get it working in C. However, I did manage to change it back to using pointers instead of references. But only in C++. For this compile I used Mingw. I like the Code::Blocks IDE so that's what I use. Here is a program using pointers instead of references, but like I said in C++ ...

    Code:
    //Form1B.h
    #ifndef Form1B_h
    #define Form1B_h
    
    #define dim(x)                (sizeof(x) / sizeof(x[0]))
    
    typedef struct                WindowsEventArguments
    {
     HWND                         hWnd;
     WPARAM                       wParam;
     LPARAM                       lParam;
     HINSTANCE                    hIns;
    }WndEventArgs,                *lpWndEventArgs;
    
    long fnWndProc_OnCreate       (lpWndEventArgs Wea);
    long fnWndProc_OnDestroy      (lpWndEventArgs Wea);
    
    struct EVENTHANDLER
    {
     unsigned int                 iMsg;
     long                         (*fnPtr)(lpWndEventArgs);
    };
    
    const EVENTHANDLER            EventHandler[]=
    {
     {WM_CREATE,                  fnWndProc_OnCreate},
     {WM_DESTROY,                 fnWndProc_OnDestroy}
    };
    #endif
    Code:
    //Main.cpp
    #include <windows.h>
    #include <tchar.h>
    #include "Form1B.h"
    
    
    long fnWndProc_OnCreate(lpWndEventArgs Wea)
    {
     Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;
     return 0;
    }
    
    
    long fnWndProc_OnDestroy(lpWndEventArgs Wea)
    {
     PostQuitMessage(0);
     return 0;
    }
    
    
    LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
    {
     WndEventArgs Wea;
    
     for(unsigned int i=0; i<dim(EventHandler); i++)
     {
         if(EventHandler[i].iMsg==msg)
         {
            Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
            return (*EventHandler[i].fnPtr)(&Wea);
         }
     }
    
     return (DefWindowProc(hwnd, msg, wParam, lParam));
    }
    
    
    int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
    {
     TCHAR szClassName[]=_T("Form1B");
     WNDCLASSEX wc;
     MSG messages;
     HWND hWnd;
    
     wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
     wc.cbSize=sizeof (WNDCLASSEX);               wc.style=0;
     wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
     wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
     wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=0;
     wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
     RegisterClassEx(&wc);
     hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,75,75,320,305,HWND_DESKTOP,0,hIns,0);
     ShowWindow(hWnd,iShow);
     while(GetMessage(&messages,NULL,0,0))
     {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
     }
    
     return messages.wParam;
    }
    The fact that I can't do it in C is sad and depressing, for I am by no means a beginner. I'll have to find my copy of Doug Boling's book and see what his workup on it originally looked like. I adopted his way in a somewhat modified form like 10 years ago, and I forget the particulars.

  10. #10
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    Note in fnWndProc() I had to use this ...

    return (*EventHandler[i].fnPtr)(&Wea);

    instead of this ...

    return (*EventHandler[i].fnPtr)(Wea);

    ...because the parameter to the function pointer wants an address, which &Wea resolves to.

  11. #11
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    By Gum, I can still code in C!!! I just couldn't let that beat me! This compiles in C using Main.c and Form1.h ...

    Code:
    /* Form1.h  */
    #ifndef Form1_h
    #define Form1_h
    
    #define dim(x)                (sizeof(x) / sizeof(x[0]))
    
    typedef struct                WindowsEventArguments
    {
     HWND                         hWnd;
     WPARAM                       wParam;
     LPARAM                       lParam;
     HINSTANCE                    hIns;
    }WndEventArgs,                *lpWndEventArgs;
    
    long fnWndProc_OnCreate       (lpWndEventArgs Wea);
    long fnWndProc_OnDestroy      (lpWndEventArgs Wea);
    
    struct EVENTHANDLER
    {
     unsigned int                 iMsg;
     long                         (*fnPtr)(lpWndEventArgs);
    };
    
    const struct EVENTHANDLER EventHandler[]=
    {
     {WM_CREATE,                  fnWndProc_OnCreate},
     {WM_DESTROY,                 fnWndProc_OnDestroy}
    };
    #endif
    Main.c
    Code:
    /* Main.c */
    #include <windows.h>
    #include <tchar.h>
    #include "Form1.h"
    
    
    long fnWndProc_OnCreate(lpWndEventArgs Wea)
    {
     Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;
     return 0;
    }
    
    
    long fnWndProc_OnDestroy(lpWndEventArgs Wea)
    {
     PostQuitMessage(0);
     return 0;
    }
    
    
    
    LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
    {
     WndEventArgs Wea;
     unsigned int i=0;
    
     for(i=0; i<dim(EventHandler); i++)
     {
         if(EventHandler[i].iMsg==msg)
         {
            Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
            return (*EventHandler[i].fnPtr)(&Wea);
         }
     }
    
     return (DefWindowProc(hwnd, msg, wParam, lParam));
    }
    
    
    int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
    {
     TCHAR szClassName[]=_T("Form1");
     WNDCLASSEX wc;
     MSG messages;
     HWND hWnd;
    
     wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
     wc.cbSize=sizeof (WNDCLASSEX);               wc.style=0;
     wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
     wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
     wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=0;
     wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
     RegisterClassEx(&wc);
     hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,75,75,320,305,HWND_DESKTOP,0,hIns,0);
     ShowWindow(hWnd,iShow);
     while(GetMessage(&messages,NULL,0,0))
     {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
     }
    
     return messages.wParam;
    }
    Just to get rid of typedefs, I prefer to compile as C++ though. When you haven't been compiling with C for awhile, you tend to forget some of the reasons you stoped doing it! I used an older Mingw for that. Came in only 6.5 K. Good.
    Last edited by freddie; 01-27-2013 at 01:28 PM.

  12. #12
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    And the whole point of this 165gr is to modularize one's code. When I first started out Windows programming in C I ended up with programs thousands and thousands of lines long with only two procedures in them, i.e., your typical WinMain() with maybe 25 lines, and a WndProc() streaming on for thousands and thousands of lines with a ridiculous switch in it! I see that all the time with beginners. When I first saw what Doug Boling did with that complicated function pointer setup of his, it dawned on me that with that setup one would end up with event handling procedures exactly like in Visual Basic, and I realized that is one powerful idea (I coded in VB a real lot long time ago before .NET). So it looks complicated, but really comes into its own with major programs. One of the reasons a lot of C++ coders took to class frameworks instead of doing pure SDK Api Win32 is that the class frameworks automatically do this exact thing for you behind the scenes with complicated templates, macros, and such. They then say that Win32 SDK doesn't scale. The reason it didn't scale for them is because they didn't do what I've been showing, i.e., using Doug Boling's tricky function pointer setup. By the way, I do about this exact same thing in PowerBASIC, which I took up after Microsoft went to managed code in C# and VB.net. With PowerBASIC I get small, fast native code just like C/C++, with the advantage of a real built in string type, unlike C++'s template based strings as in the C++ Standard Library.

  13. #13
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Your code needed the HMENU param filled in, as does any window with the WS_CHILD style (see MSDN below).
    Once you have this you ccan use the following snippet of code.
    Note the redundant breaks.
    Forgetting a 'break;' can cause some interesting issues, so always include them, even if they are made redundant by a 'return'.


    Code:
    case WM_COMMAND:
    { 
    	switch(LOWORD(wParam))//the ctrl ID number
    	{
    		case IDC_BUTTON_ONE:
    			if(HIWORD(wParam) == BN_CLICKED)//button 1 was clicked
    			{
    				//button 1 code
    				return 0;
    			}
    		break;
    		case IDC_BUTTON_TWO:
    			if(HIWORD(wParam) == BN_CLICKED)//button 2 was clicked
    			{
    				//button 2 code
    				return 0;
    			}
    		break;
    		//etc
    	}
    }
    break;

    You cast HWNDs to HWNDs, not INT. HANDLEs and HWNDs are VOID*, so INT may hold the correct value in most versions of MS OSs.

    Code:
    if( lParam == (HWND)g_hwndButton1 )


    Quote Originally Posted by MSDN
    hMenu [in, optional]
    <snip>
    For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window.

    CreateWindow function (Windows)
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  14. #14
    Registered User
    Join Date
    Jan 2013
    Posts
    13
    Many thanks to both of you.

    Quick question for novacain:

    Quote Originally Posted by novacain View Post
    Code:
    case WM_COMMAND:
    { 
        switch(LOWORD(wParam))//the ctrl ID number
        {
            case IDC_BUTTON_ONE:
                if(HIWORD(wParam) == BN_CLICKED)//button 1 was clicked
                {
                    //button 1 code
                    return 0;
                }
            break;
    Why the separate check to see if HIWORD(wParam) is BN_CLICKED?

    Isn't LOWORD(wParam) being IDC_BUTTON_ONE enough? What can you do to a button besides click it?

    Is this just leaving room for the program (not the user) to send messages to the button to do something else? If so, what?

  15. #15
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by 168gr View Post
    Why the separate check to see if HIWORD(wParam) is BN_CLICKED?

    Isn't LOWORD(wParam) being IDC_BUTTON_ONE enough? What can you do to a button besides click it?

    Is this just leaving room for the program (not the user) to send messages to the button to do something else? If so, what?
    As I was providing an example I made it as clear, simple and generic as possible.

    It is good practice to filter on the type of message to the control, just in case the control receives other message types you did not expect (and so that break your code).

    Other messages generated by the user or sent by the OS to the button include BN_DBCLK, BN_KILLFOCUS, BN_SETFOCUS etc.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. [PDcurses] Handle pressed button
    By netpumber in forum Windows Programming
    Replies: 1
    Last Post: 05-08-2012, 01:49 PM
  2. handle messages even when the window isn't active
    By new_in_c++ in forum Windows Programming
    Replies: 28
    Last Post: 06-03-2011, 01:32 PM
  3. Finding correct window handle
    By chris1985 in forum C Programming
    Replies: 1
    Last Post: 02-10-2008, 10:43 AM
  4. How to Handle the messages of Clild windows ??
    By L.O.K. in forum Windows Programming
    Replies: 2
    Last Post: 03-24-2003, 04:32 AM
  5. How to get the correct handle to the desktop?
    By deadlocklegend in forum Windows Programming
    Replies: 1
    Last Post: 02-14-2002, 10:39 AM