I'm using Unity to build games. It has a main window and dockable windows. I have several screens. I undock some windows to other screens, however I'm also using other apps, and when I come back to the main Unity window, I don't want the child windows to go in front of my other app windows.
Using Spy++, I saw that the child windows have WS_POPUP and WS_EX_TOOLWINDOW styles, so I did this:
EnumWindows(FindUnityWindows, NULL);
And:
BOOL CALLBACK FindUnityWindows(HWND hwnd, LPARAM lParam)
{
char class_name[80];
GetClassName(hwnd, class_name, sizeof(class_name));
int processid = GetWindowThreadProcessId(hwnd, NULL);
if (!strcmp(class_name, "UnityContainerWndClass"))
{
long style = GetWindowLong(hwnd, GWL_STYLE);
style |= WS_OVERLAPPED;
style &= ~(WS_POPUP);
long exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
exstyle |= WS_EX_APPWINDOW;
exstyle &= ~(WS_EX_TOOLWINDOW);
ShowWindow(hwnd, SW_HIDE);
SetWindowLong(hwnd, GWL_STYLE, style);
SetWindowLong(hwnd, GWL_EXSTYLE, exstyle);
ShowWindow(hwnd, SW_SHOW);
}
return TRUE;
}
Which effectively changes the styles (I checked in Spy++), but the windows behaviour doesn't change. I don't have a tab in the taskbar, and the windows still appears when I activate the main window.
What more can I do?
Related
Given two windows, a parent and child, if I call SetParent() on the child passing NULL as the last parameter, the child window doesn't respond to clicks anymore.
I noticed that the child window responds when I use PostMessage() to send WM_LBUTTONDOWN/UP to it.
What am I missing?
HWND hWnd = FindWindow(NULL, L"");
HWND child = GetWindow(hWnd, GW_CHILD);
SetParent(child, NULL);
Per the SetParent documentation:
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.
When you change the parent of a window, you should synchronize the UISTATE of both windows. For more information, see WM_CHANGEUISTATE and WM_UPDATEUISTATE.
Try this:
HWND hWnd = FindWindow(NULL, L"");
HWND child = GetWindow(hWnd, GW_CHILD);
SetParent(child, NULL);
LONG_PTR style = GetWindowLongPtr(child, GWL_STYLE);
SetWindowLongPtr(child, GWL_STYLE, (style & ~WS_CHILD) | WS_POPUP);
I'm trying to create an window by CreateWindowEx, but seams even I give both dwExStyle dwStyle value 0, the window still have WS_CAPTION style.
Code snippet as following:
_hWnd = CreateWindowExW(iExStyle, pszClassName, pszTitle, iStyle | WS_CLIPCHILDREN, dX, dY, dWidth, dHeight,
hWndParent, 0, hInstance, NULL);
ASSERT(GetWindowLong(_hWnd, GWL_STYLE) & WS_CAPTION == 0); //<---- This will failed.
dwStyle = 0x00000000L means WS_OVERLAPPED or WS_TILED, this window has a title bar and a border.
Window Styles
As emax says, WS_OVERLAPPED (0) is the default and results in:
The window is an overlapped window. An overlapped window has a title bar and a border. Same as the WS_TILED style.
If you are creating a child window you must specify WS_CHILD and if you are creating a "popup" window you must use WS_POPUP or WS_POPUPWINDOW.
A tooltip for example would use WS_POPUP and WS_EX_TOOLWINDOW + WS_EX_TOPMOST...
i have a problem making my window a "click-through" window.
I have tried some methods i found online for windowsAPI but with no luck, the mouse won't pass through the created window.
My OS is Windows 10.
Any solutions?
Thanks.
Ok, finally found the problem with the windows API functions. the handle passed to them was wrong, the opencv cvGetWindowHandle() returns the wrong handle, using the handle return from FindWindow() i was able to make my window click-through.
//-Init an opencv window
cv::namedWindow("foo");
HWND hwnd = FindWindow(NULL,"foo"); //-Work!
HWND hwnd = (HWND)cvGetWindowHandle("foo");//-Doesn't Work.
//-Set window to be click-through.
LONG lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
lExStyle |= WS_EX_TRANSPARENT | WS_EX_LAYERED;
SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle);
//-Set the window to always be on top.
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
Is there a way to set true full focus on a push button (button window class) in WinAPI?
SetFocus() somewhat sets focus (the button gets an inner dotted border), but the button is actually partially focused and still cannot be pressed with the Enter key, only the Spacebar key works. At the same time, if I move focus to a sibling button with the Tab key, then this sibling button (as well as the first button if I then return focus to it using Shift+Tab) gets a true focus (visually, not just inner dotted focus border is added to the really focused button, but its main outer border becomes blue [Windows 7]), and now it reacts to Enter as intended.
How to make a button such fully focused programmatically?
Screenshot of the three button states:
Some background for clarity: there is a window (created with the regular combination of WNDCLASSEX / RegisterClassEx / CreateWindowEx() with WS_OVERLAPPEDWINDOW as its style) with a multiline edit box (edit window class with ES_MULTILINE style) and several push buttons. To implement keyboard navigation using the Tab key, I process the WM_KEYDOWN event in the edit box's procedure (subclassed via SetWindowLong()), otherwise I could navigate between buttons and from buttons to the edit box, but not from the edit box to a button. All the controls have WS_TABSTOP style. The issue with the button focus takes place when I set focus using SetFocus() when the Tab key is pressed on the edit box having focus and caret.
Minimal relevant C++ code:
HWND mainWindow;
WNDPROC defaultEditCallback = NULL;
int WINAPI WinMain(HINSTANCE instance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEXW wc;
wchar_t windowClass[] = L"testcase";
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = 0;
wc.lpfnWndProc = mainWindowCallback;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = instance;
wc.hIcon = NULL;
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = (LPCWSTR)windowClass;
wc.hIconSm = NULL;
RegisterClassExW(&wc);
mainWindow = CreateWindowW(
(LPCWSTR)windowClass, (LPCWSTR)windowClass, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, instance, NULL
);
HWND edit = CreateWindowExW(
WS_EX_CLIENTEDGE, (LPCWSTR)L"edit", NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | WS_TABSTOP,
0, 0, 0, 0, mainWindow, (HMENU) 10,
(HINSTANCE) GetWindowLongPtrW(mainWindow, GWLP_HINSTANCE),
NULL
);
defaultEditCallback = (WNDPROC)SetWindowLongPtrW(edit, GWLP_WNDPROC, (LONG)editCallback);
HWND firstButton = createButton(mainWindow, 20, L"First", buttonWidth, buttonHeight);
HWND secondButton = createButton(mainWindow, 30, L"Second", buttonWidth, buttonHeight);
HWND thirdButton = createButton(mainWindow, 40, L"Third", buttonWidth, buttonHeight);
// [Skipped] Sizing and positioning controls.
ShowWindow(mainWindow, nCmdShow);
UpdateWindow(mainWindow);
MSG msg;
while (GetMessageW(&msg, NULL, 0, 0) > 0) {
if (!IsDialogMessage(mainWindow, &msg)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK mainWindowCallback(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
if (WM_DESTROY == msg) {
PostQuitMessage(0);
}
return DefWindowProcW(window, msg, wParam, lParam);
}
LRESULT CALLBACK editCallback(HWND control, UINT msg, WPARAM wParam, LPARAM lParam) {
if (WM_KEYDOWN == msg && VK_TAB == wParam) {
HWND next = GetNextDlgTabItem(mainWindow, control, (int)(GetKeyState(VK_SHIFT) & 0x8000));
SetFocus(next);
return 0;
}
return CallWindowProc(defaultEditCallback, control, msg, wParam, lParam);
}
HWND createButton(HWND parentWindow, int id, wchar_t* caption, int width, int height) {
return CreateWindowW(
(LPCWSTR)L"button", (LPCWSTR)caption, WS_VISIBLE | WS_CHILD | WS_TABSTOP,
0, 0, width, height, parentWindow, (HMENU)id, NULL, NULL
);
}
Thanks.
The question does not make it clear whether the WS_OVERLAPPEDWINDOW main window is either a dialog, or subclassed to work like a dialog (i.e. based on DefDlgProc). Some hints about TAB navigation and DM_SETDEFID in the OP and following comments appear to indicate that it's a dialog(-styled) window.
For dialogs, the correct way to move the input focus between child controls is by sending the WM_NEXTDLGCTL message, rather than calling SetFocus directly. As noted in the docs:
This message performs additional dialog box management operations beyond those performed by the SetFocus function WM_NEXTDLGCTL updates the default pushbutton border, sets the default control identifier, and automatically selects the text of an edit control (if the target window is an edit control).
More details at How to set focus in a dialog box, including this part:
As the remarks to the DM_SETDEFID function note, messing directly with the default ID carelessly can lead to odd cases like a dialog box with two default buttons. Fortunately, you rarely need to change the default ID for a dialog.
A bigger problem is using SetFocus to shove focus around a dialog. If you do this, you are going directly to the window manager, bypassing the dialog manager. This means that you can create “impossible” situations like having focus on a pushbutton without that button being the default!
To avoid this problem, don’t use SetFocus to change focus on a dialog. Instead, use the WM_NEXTDLGCTL message.
[EDIT] After the OP edit, the main window turns out to be a regular window, not a dialog. The newly posted code, however, does not remember the focused child (nor does it remove/restore the default pushbutton style) after the main window is deactivated and reactivated, relegates keyboard navigation such as VK_TAB to child controls etc. Those introduce inconsistencies with the default dialog-like behaviors.
In order to make the main window behave like a dialog (and do it right), the WNDPROC would need to mimic the relevant parts of DefDlgProc, at least those that pertain to navigation. From Dialog Box Programming Considerations, among the messages such a WNDPROC would need special handling for are DM_GETDEFID, DM_SETDEFID, WM_ACTIVATE, WM_NEXTDLGCTL, WM_SHOWWINDOW, WM_SYSCOMMAND. Once that's done, my original answer still applies.
i'm new to C++ as well as for windows programming..
i have created a window using msdn CreateWindow() function
which works correctly..now i would like to create a child window...the parent window should control the child window...
Any helps sample code regarding this .
Thanks in advance
Roughly speaking, in the handler for the parent, where you wish to create the child, you call CreateWindow, passing in the window for the parent as the hwndParent - probably, you also want to set certain styles on the child such as WS_CHILD. Your interaction with the child window then depends on the type of the window you created. Some windows (such as buttons) are designed to work as child windows, so they send a lot of notification messages, so you would set up your parent to listen for those notification messages.
I'd highly recommend having a read through Charles Petzold's "Programming Windows" if you can obtain a copy.
Otherwise, to answer your question, pass the parent window's handle as the parent when you create the child window (using either CreateWindow or CreateWindowEx):
HWND CreateWindowEx
(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent, /// pass the parent window handle here
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
..As 1800 Info has also stated, perhaps also set the WS_CHILD style (more oon Window Styles here). This is just the rudimentary plumbing, really..
Can you be a bit more specific when you say "control the child window..."?
It Is 2018 by now.. doing some retro work on this I found SetParent() to come out handy, to assure a child window remains inside the client region of the parent.. Before SetParent() the child need not be registered as a child. In CreateWindowEx the parent handle can be NULL at first. Style WS_CHILD is not needed, but WS_CLIPSIBLINGS comes out handy, it avoids flickering.
This is my code for creating a child window:
HWND hwnd = CreateWindowExA(0, "WindowOfDLL", ctitle, WS_SIZEBOX | WS_CLIPSIBLINGS, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, hMenu, inj_hModule, NULL);
SetParent(hwnd, hwndparent);
ShowWindow(hwnd, SW_SHOWNORMAL);
I've seen no problems (yet) with threading in Win10. Each of below child windows is created in a DLL which manages the assembly. When a child window is created, the DLL adds a new member to the assembly and launches a thread, which will serve the child window and performs above code in its initialisation.
"could you post more of your code "
#BradB you're right.. our answers are all not very specific, this is old stuff it is difficult to put a complete frame in one post. Read the book RobS suggested I would say... and... take a look at Visual studio and more modern methods to design "child windows", like Winforms, WPF and Universal !
Here is some more of my legacy code, just the preparations, to let it be a CHILD window. The events etc you will have to fill in yourself..
BOOL RegisterDLLWindowClass(LPCWSTR s)
{
WNDCLASSEX wc;
wc.hInstance = NULL; // inj_hModule;
wc.lpszClassName = s;
wc.lpfnWndProc = DLLWindowProc;
wc.style = CS_DBLCLKS;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszMenuName = NULL;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
if (!RegisterClassEx(&wc))
return 0;
}
HMENU CreateDLLWindowMenu()
{
WriteLine("Create menu");
HMENU hMenu;
hMenu = CreateMenu();
HMENU hMenuPopup;
if (hMenu == NULL)
return FALSE;
hMenuPopup = CreatePopupMenu();
AppendMenu(hMenuPopup, MF_STRING, MYMENU_FILTERSOFF, TEXT("Off"));
AppendMenu(hMenuPopup, MF_STRING, MYMENU_CANNY, TEXT("Canny"));
AppendMenu(hMenuPopup, MF_STRING, MYMENU_SOBEL, TEXT("Sobel"));
AppendMenu(hMenuPopup, MF_STRING, MYMENU_THRESHOLD, TEXT("Threshold"));
AppendMenu(hMenuPopup, MF_STRING, MYMENU_DILATE, TEXT("Dilate"));
AppendMenu(hMenuPopup, MF_STRING, MYMENU_HARRIS, TEXT("Harris"));
CheckMenuItem(hMenuPopup, 0, MF_BYPOSITION | MF_CHECKED);
AppendMenuW(hMenu, MF_POPUP, (UINT_PTR)hMenuPopup, TEXT("Filter"));
HMENU hMenuPopup2 = CreatePopupMenu();
AppendMenu(hMenuPopup2, MF_STRING, MYMENU_SAMPLE1, TEXT("Change parameter"));
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hMenuPopup2, TEXT("Test"));
return hMenu;
}
void WINAPI CreateAWindow(PassedToDLL *lpParam, DWORD dwStyle)
{
if (nInstances == 0) RegisterDLLWindowClass((LPCWSTR)L"WindowOfDLL");
HMENU hMenu = CreateDLLWindowMenu();
nInstances++;
CommonInfo[nInstances - 1] = lpParam;
int i = 20 + 4 * (rand() % 10);
lpParam->p = NewPanningStruct();
lpParam->hWndChild = CreateWindowEx(0, L"WindowOfDLL", lpParam->title,
dwStyle,
i, i, 800, 550, lpParam->hWndParent, hMenu, NULL, NULL);
if (wcslen(lpParam->filename) > 0)
{
LoadBitmapFromBMPFileW(lpParam->hWndChild, lpParam->filename, &(lpParam->hBmp),
&(lpParam->hPalette));
}
}