Thread: Modeless MessageBox() Internals

  1. #1
    Registered User
    Join Date
    Jul 2015
    Posts
    64

    Modeless MessageBox() Internals

    Hey all, this should be a fairly quick one!

    I'm currently rolling my own MessageBox function (and maybe whacking it in a library for future use,) to allow for advanced text formatting and inheritance of various parent window properties. Modality has got me kind of stumped though.

    So, in order to implement a modal "dialogue", we can call EnableWindow(hParent, FALSE) and force the user to interact with the messagebox window first. Then, as the messagebox routine completes, we can reactivate the parent window with EnableWindow(hParent, TRUE). Conversely, if we need to implement task modality, we could make the same calls whilst enumerating through the current thread's window handles. That part should be easy enough.

    However, it is modeless MessageBox() functionality that is confusing me. Obviously, a modeless dialogue cannot block the main thread because otherwise execution would not flow between the message loop and the windows procedure (and this would surely mean that the user cannot interact with other windows on the same thread whilst the messagebox is open.) So I considered that the MessageBox function might create a new thread for itself and run it's own message loop and procedure separate from other windows to allow execution to continue in the main thread and avoid this blocking problem.

    However, if this is the case, I'm at a loss as to how Win32 applications can seem to manage the return value of MessageBox() whilst seeming to jump over any return-handling code and continuing the flow of execution within/into the message loop.

    I'm sorry, that's not a very good description at all. I think a code example would describe my confusion better; please consider:

    Code:
    #include <windows.h>
    #include <tchar.h>
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch (msg)
        {
            case WM_LBUTTONDOWN:
                MessageBox(hwnd, _T("WM_LBUTTONDOWN event handled."), _T("WndProc"), MB_OK);
                break;
    
            case WM_CLOSE:
                DestroyWindow(hwnd);
                break;
    
            case WM_DESTROY:
                PostQuitMessage(0);
                break;
    
            default:
                return DefWindowProc(hwnd, msg, wParam, lParam);
        }
    
        return 0;
    }
    
    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow)
    {
        const TCHAR g_szClassName[] = _T("WindowClass");
    
        WNDCLASSEX wc;
        HWND hWnd;
        MSG Msg;
    
        wc.cbSize = sizeof(WNDCLASSEX);
        wc.style = 0;
        wc.lpfnWndProc = WndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH) (COLOR_WINDOW);
        wc.lpszMenuName = NULL;
        wc.lpszClassName = g_szClassName;
        wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    
        if (!RegisterClassEx(&wc))
        {
            MessageBox(NULL, _T("Window Registration Failed!"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
    
        hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,
                              g_szClassName,
                              _T("Window"),
                              WS_OVERLAPPEDWINDOW,
                              CW_USEDEFAULT, CW_USEDEFAULT, 500, 500,
                              NULL, NULL, hInstance, NULL);
    
        if (hWnd == NULL)
        {
            MessageBox(NULL, _T("Window Creation Failed!"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
    
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
    
        // Confusing modeless messagebox behaviour :(
        int mbresult = 0;
        mbresult = MessageBox(NULL, _T("First messagebox."), _T("WinMain"), MB_OK);
    
        if (mbresult == IDOK)
            MessageBox(NULL, _T("Second messagebox.\nExecution has continued."), _T("WinMain"), MB_OK);
    
        // The Message Loop
        while (GetMessage(&Msg, NULL, 0, 0) > 0)
        {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }
    
        return (int) Msg.wParam;
    }
    When the above program is run, the main window is created and the first messagebox is displayed. However, if we ignore this messagebox and click in the client area of the main window, we can trigger the WM_LBUTTONDOWN messagebox. This supports the idea that the messagebox might be running in it's own thread; execution seems to jump over the if statement following the first messagebox (as we would expect since MessageBox hasn't returned yet and thus mbresult does not yet equal IDOK.)

    So we know that execution has reached the message loop and is bouncing around between the loop and the windows procedure. The main window is fully interactive at this point, as we'd expect once code has reached the message loop. However, even if execution has reached the message loop and then we click 'Ok' on the first messagebox, the second messagebox is triggered; that is, point of execution within the source code seems to jump "upwards" out of the message loop and into the if statement.

    Hopefully that explains my confusion a little better. And there was me thinking this would be a short post If anyone could please possibly explain what is going on here and, by extension, how such logic can be achieved in a hand-crafted messagebox function, that would be hugely appreciated!

    Many thanks for your time,
    Abyssion
    Last edited by Abyssion; 07-06-2016 at 11:41 AM. Reason: Clarity within source code

  2. #2
    Registered User
    Join Date
    Jul 2015
    Posts
    64
    In fact, this can be more easily demonstrated by:

    Code:
    // WinMain...
    
    int mbresult = 0;
    mbresult = MessageBox(NULL, _T("First messagebox."), _T("WinMain"), MB_OK);
    
    Sleep(10000);
    
    // The Message Loop
    while (GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    
    return (int) Msg.wParam;
    The program doesn't sleep until 'Ok' is pressed in the messagebox, as expected. However, the window still seems able to process the WM_LBUTTONDOWN message before the program even reaches the message loop. If I had to guess, I'd say that the operating system is somehow detecting that the window is unresponsive and intervening somehow...

    I dunno, I'm completely stumped. This is sort of messing with my whole understanding of the message loop/windows procedure interaction.

    So yeah, any help would be hugely appreciated!

  3. #3
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Quote Originally Posted by Abyssion View Post
    ...
    The program doesn't sleep until 'Ok' is pressed in the messagebox, as expected. However, the window still seems able to process the WM_LBUTTONDOWN message before the program even reaches the message loop. If I had to guess, I'd say that the operating system is somehow detecting that the window is unresponsive and intervening somehow...
    ...
    I don't think it's a matter of simply not responding. A 10 second "sleep", or a call to MessageBox() with a NULL owner window handle, will both block and prevent entry into the message loop if placed before the loop.

    The Sleep() causes an obvious "not responding" condition, displaying the hourglass symbol and ignoring most keyboard and mouse messages. The MessageBox() however does not cause any obvious "not responding" condition. In fact, if I ignore the message box, I can continue to operate the program, even though the message loop is not executing. I have proven this by removing the message loop completely. The program still functions as long as the message box has not been closed. As soon as I close the message box, my WinMain() continues on to the return statement and terminates.

    So it would appear that the program must be receiving sent messages instead of posted messages while the call to MessageBox() has not yet returned.

    Note that the MB_APPLMODAL modality flag is the default;
    From here: MessageBox function (Windows)
    MB_APPLMODAL - The user must respond to the message box before continuing work in the window identified by the hWnd parameter. However, the user can move to the windows of other threads and work in those windows.

    So with a NULL argument for the owner window, any window, including the window in the calling thread itself would presumably still be usable while the modal message box was still open.

    Normally, a message box has an owner window. Perhaps, under certain conditions, the Windows OS sends messages instead of posting them to insure that a blocked thread receives them.

    -
    Last edited by megafiddle; 07-07-2016 at 03:02 AM.

  4. #4
    Registered User
    Join Date
    Dec 2010
    Location
    Shamokin PA (middle of nowhere)
    Posts
    146
    My guess as to what you are seeing Abyssion is that once you call MessageBox(), the internal implementation contains code very similiar to that I've posted in my last post of this morning in your "Control Handles..." post in my Form1_Button_Click procedure where I show the internal code for creating a Dialog Box, and where you'll find within an IsDialogMessage() code block the typical TranslateMessage() / DispatchMessage() block too. So in other words, your main app is working even without your message pump in your WinMain() because the message pump within the internal Dialog Box code is servicing your app. Check out that other post of mine.

  5. #5
    Registered User
    Join Date
    Dec 2010
    Location
    Shamokin PA (middle of nowhere)
    Posts
    146
    However, it is modeless MessageBox() functionality that is confusing me. Obviously, a modeless dialogue cannot block the main thread because otherwise execution would not flow between the message loop and the windows procedure (and this would surely mean that the user cannot interact with other windows on the same thread whilst the messagebox is open.) So I considered that the MessageBox function might create a new thread for itself and run it's own message loop and procedure separate from other windows to allow execution to continue in the main thread and avoid this blocking problem.

    However, if this is the case, I'm at a loss as to how Win32 applications can seem to manage the return value of MessageBox() whilst seeming to jump over any return-handling code and continuing the flow of execution within/into the message loop.
    Your prescience amazes me Abyssion. You actually reasoned it out almost perfectly. This morning I just read your question here quickly and realized that other post of mine would fill in the details for you. Message boxes are a sort of special dialog created by a component of Windows sometimes called the 'Windows Dialog Engine'. What's involved is that Windows internally registers various classes for Dialog Boxes, and when you call a function such as MessageBox() or CreateDialog() a window of the registered class is created behind the scenes with a typical CreateWindowEx() function call. You don't have it in your source code as its internal to Windows itself. Afterwards Windows falls into an internal message pump of its own which you don't see either, but its there. That is proven by the behavior of your test app. The message pump that is running and allowing your WM_LBUTTONDOWN processing of your main window without your own message pump running in WinMain() is the one internal to Windows. What is going on there is that Windows is calling IsDialogMessage() to see if a message is related to the MessageBox()/Dialog Box. If it isn't Windows simply calls the usual TranslateMessage/Dispatch message sequence. That's why your WM_LBUTTONDOWN messages are being picked up. If you study my Main.cpp file in the other thread like I said you'll see how a dialog box is created without use of the hidden code of the Windows Dialog Engine. Here is that specific code...
    Code:
    long btnForm1_Click(WndEventArgs& Wea)                     //This is an 'Event Handler' for a click of the top button on the
    {                                                          //main Form.  It uses CreateWindowEx() to instantiate a new Window
     DWORD dwStyle,dwExStyle;                                  //of class "Form1"  Note that the last parameter of the call is
     HWND hDlg;                                                //Wea.hWnd.  That is the HWND of the main program Window.  The
     MSG Msg;                                                  //last parameter is the Creation Parameters parameter.  It can be
                                                               //retrieved (as can all the others) through the CREATIONSTRUCT a
     dwStyle   = WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE;     //pointer to which is received in the lParam of the WM_CREATE
     dwExStyle = WS_EX_DLGMODALFRAME | WS_EX_CONTROLPARENT;    //message for the newly instantiating Window.
     hDlg=CreateWindowEx(dwExStyle,_T("Form1"),_T("Form1"),dwStyle,50,25,310,185,Wea.hWnd,(HMENU)0,GetModuleHandle(0),Wea.hWnd);
     ShowWindow(hDlg,SW_SHOWNORMAL);
     UpdateWindow(hDlg);
     while(GetMessage(&Msg,NULL,0,0))    // The IsDialogMessage function determines whether a message is intended for the specified
     {                                   // dialog box and, if it is, processes the message.  If the message has been processed, the
        if(!IsDialogMessage(hDlg,&Msg))  // return value is nonzero.  If the message has not been processed, the return value is zero.
        {                                // Because the IsDialogMessage function performs all necessary translating and dispatching of
           TranslateMessage(&Msg);       // messages, a message processed by IsDialogMessage must not be passed to the TranslateMessage
           DispatchMessage(&Msg);        // or DispatchMessage function.If the return value is zero, its not a message for hDlg.  So
        }                                // process it.
     }
     
     return 0;
    }
    In btnForm1_Click() you have the event/message handler for a click of the top button on the startup form. That button click causes a CreateWindowEx() call for an object of class "Form1". After that call execution falls into the message pump (the 2nd one in the app) where first a call is made to IsDialogMessage(). What that function is specifically for is handling tabbing between controls within the dialog, amoung other things. In this case there really aren't any. As a minor digression, you had mentioned use of the EnableWindow(hWnd, FALSE) as a way of making a dialog modal. That's not really the full story. The missing part there is the dialog's message pump which handles tab order of child window controls within the dialog. But returning to the story, if the message isn't for the dialog, e.g., your WM_LBUTTONDOWN's on your main form, then the dialog's message pump forwards the message to the correct Window Procedure (TranslateMessage()/DispatchMessage()).

  6. #6
    Registered User
    Join Date
    Jul 2015
    Posts
    64
    Ahh, thank you both so much! I can feel myself starting to become one with the Force.

    I have proven this by removing the message loop completely. The program still functions as long as the message box has not been closed. As soon as I close the message box, my WinMain() continues on to the return statement and terminates.
    Excellent idea Mega, thank you! Yes, that clearly demonstrates that a secondary message-handling system is in play. I am actually not 100% sure on the exact differences between sending and posting a message (I believe one method passes MSG structures directly to the windows procedure, bypassing the message loop, whilst the other doesn't?) but I shall do my own research into this. Cheers for the pointer!

    For anyone else who doesn't quite understand the intricacies of the message loop/windows procedure interaction (or indeed, overlooked it, like myself) this page on MSDN, at a glance, looks like it would be an excellent resource: About Messages and Message Queues (Windows)

    You mentioned the default MB_APPLMODAL modality, Mega; that was actually something that I initially wanted to change. I quite liked the idea of non-modality being the default with the option to pass in a new uType value to control modality, but looking back on it now, I think it's safe to say that Microsoft did do things right. Architecturally, I guess it does make more sense to simply pass NULL as hWnd if you don't want an owned dialogue. Bahh, I digress.

    Freddie, thank you once again for your input! I've checked out the code examples you referenced (from the other thread also, which I shall respond to as soon as I can ) and, yes, I can see now how an internal dialogue message loop can service windows other than itself to maintain thread-wide functionality! I think my main hurdle was the tight association I had misguidedly drawn between a window and a message loop; having never developed an application with a multiple document interface in the past, I was under the illusion that message loops serviced one window and one window only. Thank you for demonstrating how this isn't the case!

    Your prescience amazes me Abyssion.
    That, sir, is quite the compliment; cheers! I like to make sure I do at least some research before posing a question to the good people of the boards. In this case, I realise I should have done more.

    I do have a question about your example code, if you don't mind? I find myself wondering if the IsDialogMessage() call is strictly necessary; presumably it is necessary and I've just overlooked something, but I'm unsure about what, specifically, the function does internally. Given that the first member variable of a MSG structure is a handle to the target window, would the system not just pass the message to the correct procedure implicitly? If we consider a "standard" message loop:

    Code:
    while (GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    I'm trying to determine what would happen if this loop was incorporated inside a dialogue function (i.e. without the IsDialogMessage() call). If a message intended for the dialogue was received by GetMessage(), unless I'm mistaken, the system (or would our thread be doing the work here?) would look up the procedure address associated with the handle stored in MSG.hWnd and appropriately forward the message to that procedure. Conversely, if a message intended for a "main window", for instance, was received, these messages would also be forwarded to the appropriate procedure via looking up the main window's associated procedure via MSG.hWnd.

    So if a "standard" message loop can pass messages to multiple windows correctly, is the IsDialogWindow() call strictly necessary? Does this function perhaps perform some additional processing invisibly that would not be achieved by a "standard" message loop?

    Thanks again for your time!
    Fingers crossed that I haven't missed something embarrassingly simple

    EDIT: Also, apologies for taking so long to get back to you both. Things are pretty hectic over here!

  7. #7
    Registered User
    Join Date
    Dec 2010
    Location
    Shamokin PA (middle of nowhere)
    Posts
    146
    I think my main hurdle was the tight association I had misguidedly drawn between a window and a message loop; having never developed an application with a multiple document interface in the past, I was under the illusion that message loops serviced one window and one window only. Thank you for demonstrating how this isn't the case!
    That's why I basically posted that other application, i.e., to make absolutely clear the relationship between a specific INSTANCE of a window and a Window Procedure, which services all INSTANCES of a Class, rather than just one window instance. I don't believe I've ever seen any tutorial type materials that emphasize that point. Its usually implied but no examples seem to ever be given. So its important I think to really internalize that concept within your understanding of the one to many relationship between a window and its Window Procedure. And keep in mind too the role played by the ever important WNDCLASSEX::cbWndExtra bytes in all that; any data attached there pertains to the specific instance. It becomes 'instance' data of a specific object. Thinking that over you might begin to understand the purpose and use of the WNDCLASSEX::cbClsExtra bytes, which pertain to the whole class. They are like C++ static members of a C++ Class.

    None of the code I posted makes absolutely clear the real purpose of the IsDialogMessage() function. If you are writing your own Dialog Boxes without using resource scripts and the Windows Dialog Engine, you'll find that you can't tab between child window controls of the Dialog Box if you don't use the IsDialogMessage() Api. At least I'm pretty sure of that. I have an example somewhere over in Jose Roca's forum under the command line compiling examples, I believe ProgEx 41, or 42 or somewhere in there where I have a self-created Dialog Box with an OK and Cancel button on it where you could test that. But I believe that's the gist of it.

  8. #8
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    I also like to "roll my own", and am currently working on a simple dropdown list control. I find the standard combobox with a dropdown list to be unnecessarily large for my use.

    The link you provided just above - About Messages and Message Queues (Windows), has a good amount of information about posting and sending messages. In addition, the documentation for specific messages should also note whether that particular message is posted or sent. Sometimes important to know.

    The CreateWindow() function, which I completely overlooked, would have been a good example for your original question. Very often, CreateWindow() is called from inside WinMain(), before entering the message loop. Before returning, CreateWindow() sends one or more messages to the window procedure. Before the message loop even begins, some messages have already been processed by the window procedure. So there are functions also which send messages directly (as opposed to posting them to the message queue).

    There are a great deal of functions availailable that can be used for customizing purposes, though they are often not easy to find. Or they are mentioned but easily overlooked because their purpose isn't readily apparent. Just a general problem with references; they are just that - references.

    -
    Last edited by megafiddle; 07-10-2016 at 04:20 PM.

  9. #9
    Registered User
    Join Date
    Dec 2010
    Location
    Shamokin PA (middle of nowhere)
    Posts
    146
    From MSDN on IsDialogMessage()...

    Although the IsDialogMessage function is intended for modeless dialog boxes, you can use it with any window that contains controls, enabling the windows to provide the same keyboard selection as is used in a dialog box.

    When IsDialogMessage processes a message, it checks for keyboard messages and converts them into selections for the corresponding dialog box. For example, the TAB key, when pressed, selects the next control or group of controls, and the DOWN ARROW key, when pressed, selects the next control in a group.
    You can pretty easily see that in the example I alluded to above which is a non-resource script created Dialog at...

    ProgEx43 : Command Line Compiling With The GNU Compilers

    ...entitled "Command Line Compiling With The GNU Compilers". Its actually ProgEx43. In WndProc_OnAbout() you can comment out the IsDialogMessage() function and the two brackets enclosing the typical TranslateMessage()/DispatchMessage() sequence, and see that keyboard navigation withing the Dialog Box among the button controls stops.

  10. #10
    Registered User
    Join Date
    Dec 2010
    Location
    Shamokin PA (middle of nowhere)
    Posts
    146
    I find the standard combobox with a dropdown list to be unnecessarily large for my use.
    Why do you say that megafiddle? All the code, whatever it took Microsoft to create it - dropdown combobox, is within Windows itself - not in your app. Or do you mean you aren't satisfied with the sizes on your app's client area? I would think those are configurable?

  11. #11
    Registered User
    Join Date
    Jul 2015
    Posts
    64
    So its important I think to really internalize that concept within your understanding of the one to many relationship between a window and its Window Procedure.
    Duly noted; I shall try to bare this in mind! The message loop is very easy to overlook given that, as you say, most online tutorials seem to brush over it. Cheers for clarifying; things are much easier to follow when one has some understanding of message loop internals.

    The CreateWindow() function, which I completely overlooked, would have been a good example for your original question. Very often, CreateWindow() is called from inside WinMain(), before entering the message loop. Before returning, CreateWindow() sends one or more messages to the window procedure. Before the message loop even begins, some messages have already been processed by the window procedure. So there are functions also which send messages directly (as opposed to posting them to the message queue).
    Damn, I can't believe I didn't think of that myself! Clear-cut example Mega, and one that'll be found in the vast majority of Windows GUI programs; excellent work and thank you very much! I wasn't actually aware that CreateWindow(Ex)() might send additional messages, other than WM_CREATE, to the newly created window... I guess if WS_VISIBLE is set, WM_PAINT and WM_ERASEBKGND might be sent?

    Going back to IsDialogMessage() briefly, I see what you mean, Freddie, about losing keyboard navigation functionality within the dialog without the call. I read a couple of descriptions of how this problem arises (Why do we need IsDialogMessage at all? | The Old New Thing, c - Question about IsDialogMessage() in WIN32 - Stack Overflow it seems that the loss of functionality is because the keyboard messages are being sent to the control within the dialog that currently has focus and the control's procedure cannot handle keyboard navigation input.

    Building on that, might IsDialogMessage() look something like this:

    Code:
    BOOL IsDialogMessage(HWND hDialog, MSG* msg)
    {
        if (GetParent(msg->hwnd) == hDialog)
        {
            if (msg->message == WM_KEYDOWN)
            {
                if (msg->wParam == VK_TAB || msg->wParam == VK_LEFT || msg->wParam == VK_UP ||
                    msg->wParam == VK_DOWN || msg->wParam == VK_RIGHT)
                {
                    msg->hwnd = hDialog;           // Redirect keyboard navigation messages
                    TranslateMessage(msg);         // to the dialog itself, instead of a
                    DispatchMessage(msg);          // control contained within
    
                    return TRUE;
                }
            }
        }
        
        return FALSE;
    }
    This is supposed to be a rough snippet that takes certain WM_KEYDOWN MSGs designated for a control within a dialog and sends it to the dialog itself so that navigation can be handled in the dialog's windows procedure. Am I thinking sort of along the right lines here?

  12. #12
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Quote Originally Posted by Abyssion View Post
    ... I guess if WS_VISIBLE is set, WM_PAINT and WM_ERASEBKGND might be sent?
    ...
    I believe they are. I've never seen anything in the documentation other than this:

    "If the WS_VISIBLE style is specified, CreateWindow sends the window all the messages required to activate and show the window."

    And CreateWindowEx() sends additional messages related to the window frame.

    Glad to help (and hope it helps!)

    -
    Last edited by megafiddle; 07-11-2016 at 08:38 PM.

  13. #13
    Registered User
    Join Date
    Dec 2010
    Location
    Shamokin PA (middle of nowhere)
    Posts
    146
    This is supposed to be a rough snippet that takes certain WM_KEYDOWN MSGs designated for a control within a dialog and sends it to the dialog itself so that navigation can be handled in the dialog's windows procedure. Am I thinking sort of along the right lines here?
    Quite possibly Abyssion. To be perfectly honest, I was never that interested in it to give it much thought. I guess you could say I take it on faith that it works. There is always an alternative to using various Windows functions or functionality such as that to accomplish keyboard navigation among child window controls, but it always involves writing a bunch of nasty code oneself - like dozens and dozens of lines of it, involving subclassing and whatnot. Its just easier to play by the rules is all.

  14. #14
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Quote Originally Posted by freddie View Post
    Why do you say that megafiddle? All the code, whatever it took Microsoft to create it - dropdown combobox, is within Windows itself - not in your app. Or do you mean you aren't satisfied with the sizes on your app's client area? I would think those are configurable?
    It is the size of the control in the dialog that is too large. And I have tried configuring them as small as possible.

    For some reason, the item text in the edit control portion of a combobox has some additional space above the text. This requires that that the combobox be larger than would be necessary for the text alone, to accomodate this extra space. I am guessing this is due to the size of the dropdown icon which is also located in the edit control.

    And also, since I am not using the edit portion of the control for editing, I don't need the icon. Normally, the item text in the edit portion is selected to edit the item, and the icon is selected to open the list portion of the control. In that case the icon is necessary to differentiate between the two functions. In my case, I can use the item itself to open the list.

    My current project, has a large number of controls with very small item lengths. I found that if I use a simple listbox and size it just large enough to hold the currently selected item, I can make the height smaller than a combobox, and the absence of the icon makes the width smaller also. This then functions as the "current selection" portion of the control. And the size is considerably smaller.

    The list portion of the control is handled by a single separate list box (common to all controls) which is created and filled with appropriate items when a control is selected. The list is also located directly below the selected control and so behaves very much like a combobox.

    -

  15. #15
    Registered User
    Join Date
    Jul 2015
    Posts
    64
    Quote Originally Posted by megafiddle View Post
    I believe they are. I've never seen anything in the documentation other than this:

    "If the WS_VISIBLE style is specified, CreateWindow sends the window all the messages required to activate and show the window."

    And CreateWindowEx() sends additional messages related to the window frame.
    Glad to help (and hope it helps!)

    -
    Ahh, wonderful! I was unaware of the additional window frame messages; I shall look into these.
    This certainly does help, thank you Mega

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Windows Internals book
    By pc2-brazil in forum Windows Programming
    Replies: 1
    Last Post: 05-14-2013, 03:11 AM
  2. Internals of OPENMP?
    By chiku123 in forum C++ Programming
    Replies: 1
    Last Post: 10-23-2007, 10:19 AM
  3. modal and modeless
    By Bleech in forum Windows Programming
    Replies: 2
    Last Post: 12-02-2006, 06:07 PM
  4. The internet's internals revealed
    By valis in forum A Brief History of Cprogramming.com
    Replies: 22
    Last Post: 07-29-2006, 08:13 AM
  5. problem with A simple modeless messagebox
    By hanhao in forum C++ Programming
    Replies: 8
    Last Post: 07-05-2005, 11:18 PM

Tags for this Thread