Sign in to follow this  
rayli1107

Win32 question about setParent with listboxes, comboboxes

Recommended Posts

Does anyone know why the following code won't add the combobox correctly to the window? // hWnd is a handle to a window HWND combo1 = CreateWindow("COMBOBOX", "", CBS_DROPDOWNLIST | WS_VISIBLE | WS_POPUP, 50, 50, 200, 200, NULL, NULL, NULL, NULL); SetParent(combo1, hWnd); SetWindowLong(combo1, GWL_style, CBS_DROPDOWNLIST | WS_VISIBLE | WS_CHILD); This also doesn't work with list boxes, but it works for simpler controls like buttons and checkboxes. Thanks.

Share this post


Link to post
Share on other sites
SetParent will only change where notification messages go. It will not magically move the control into another window. Simply do:

HWND combo1 = CreateWindow("COMBOBOX", "", CBS_DROPDOWNLIST | WS_VISIBLE | WS_CHILD, 50, 50, 200, 200, hWnd, NULL, NULL, NULL);

Share this post


Link to post
Share on other sites
I was wrong about SetParent. It is supposed to move the child window as well.

What happens when you try it on a combobox/listbox? Does it simply not relocate the window or does the relocated window not work properly?

Share this post


Link to post
Share on other sites
Try changing the order of things. MSDN explicitly states:


For compatibility reasons, SetParent does not modify the WS_CHILD or WS_POPUP window styles of the window whose parent is being changed. Therefore, if hWndNewParent is NULL, you should also clear the WS_CHILD bit and set the WS_POPUP style after calling SetParent. Conversely, if hWndNewParent is not NULL and the window was previously a child of the desktop, you should clear the WS_POPUP style and set the WS_CHILD style
before calling SetParent.

Share this post


Link to post
Share on other sites
The code does not work because you call CreateWindow without initialising the parentwindow there (you set it to NULL).

From the docu of createwindow:
----------------------------------------
hWndParent
[in] Handle to the parent or owner window of the window being created. To create a child window or an owned window, supply a valid window handle. This parameter is optional for pop-up windows.
-----------------------------------------

As you do not supply a valid parent handle, your new window is not a child window.


Than look into the documentation of SetParent:
-----------------------------------------
An application can use the SetParent function to set the parent window of a pop-up, overlapped, or child window. The new parent window and the child window must belong to the same application.
-----------------------------------------

I am not sure what exactly happens, but I guess that without the parentwindow and without the hinstance as well (you set both to NULL) that created window becomes a desktop window and maybe no longer counts as beeing "owned" by your application, thus cannot become one later on.


How to resolve the problem? Well, you could i.e. use your applications framewindow as default-parent window and change to the desired parentwindow later on (tested this, works for me).

Share this post


Link to post
Share on other sites
As far as I know, you do not need parent window to call CreateWindow... such a window will appear on the desktop instead of in the parent window.

This same code will work with other simple controls such as buttons or checkboxes. The following would work:

HWND button1 = CreateWindow("BUTTON", "", BS_PUSHBUTTON | WS_VISIBLE | WS_POPUP,
50, 50, 200, 200, NULL, NULL, NULL, NULL);
SetParent(button1, hWnd);
SetWindowLong(button1, GWL_style, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD);

For some reason, it just doesn't work with combo boxes and list boxes

Share this post


Link to post
Share on other sites
True, but for controls that have child windows, it may be necessary to link to your application. I repeat my questions mentioned above: have you tried specifying your application's HINSTANCE? Is the window handle of the control actually non-NULL?

Share this post


Link to post
Share on other sites
Your code works fine for me (tested inside an MFC app):


HWND button1 = CreateWindow("COMBOBOX", "", CBS_DROPDOWNLIST | WS_VISIBLE | WS_POPUP,
50, 50, 200, 200, NULL, NULL, NULL, NULL);
::SetParent(button1, m_hWnd);
::SetWindowLong(button1, GWL_style, CBS_DROPDOWNLIST | WS_VISIBLE | WS_CHILD);


I get a combo and can also popup the list without problems. Also i can't detect any flaw in that code.

What kind of app are you using? Win32 or MFC? Are you having a correct Message Pump (one that uses NULL for the HWND inside GetMessage/PeekMessage)?

Share this post


Link to post
Share on other sites
Quote:
Original post by rayli1107
When I set both the HWND and HINSTANCE of the combo box to NULL (with WS_POPUP style) it appears on the desktop instead of in the parent window

Not exactly the point. You're simply not trying the suggestion Schue and I gave you. On my version of Windows, it doesn't matter what the HINSTANCE is set to. That doesn't mean this is true for every version.

Quote:
I'm doing a Win32 app, which should have no problem

Again, you seem to be missing the point here. As Endurion says: your message loop should NEVER specify a window handle. (Can you tell from my font selection that that is important?) Lots of stuff, including comboboxes, will not work properly with a window handle specified. It should always be NULL in your message loop.

Also, did you try changing the order of things?

All that said, I cannot reproduce the behaviour you describe. It works fine for me in all configuration. Here is my testcase:

#include <windows.h>

LRESULT CALLBACK WinProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE : PostQuitMessage (0);
}

//Let default window handler handle this message
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCommandLine, int cmdShow)
{
//Register window class
WNDCLASS wc;
ZeroMemory (&wc, sizeof (wc));
wc.style = 0;
wc.lpfnWndProc = WinProc;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszClassName = "TEST";
RegisterClass (&wc);

//Create window
HWND hWnd = CreateWindow("TEST", "Test window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
ShowWindow (hWnd, SW_NORMAL);

//Create combobox and reparent
HWND combo1 = CreateWindow("COMBOBOX", "", CBS_DROPDOWNLIST | WS_VISIBLE | WS_POPUP, 50, 50, 200, 200, NULL, NULL, hInstance, NULL);
SetParent(combo1, hWnd);
SetWindowLong(combo1, GWL_STYLE, CBS_DROPDOWNLIST | WS_VISIBLE | WS_CHILD);

//Message loop
while (true)
{
MSG msg;
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
if (msg.message == WM_QUIT) break;
}
}
return 0;
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this