如何将一个窗口保留在另一个应用程序窗口的前面

How to keep a window in front of another applications window

本文关键字:窗口 保留 另一个 应用程序 前面 一个      更新时间:2023-10-16

我需要在所选应用程序的窗口顶部显示闪烁的边框(在我的示例中,应用程序是cmd.exe(。为此,我使用了分层窗口。一切正常,除了一件事:如果目标窗口与另一个窗口重叠(如果另一个窗口在前台(,我无法将目标窗口(在我的例子中 - cmd.exe(放在前面。当我最大化/最小化目标窗口时,它有效,但在目标窗口重叠的情况下不起作用。我无法通过单击任务栏中的应用程序图标进行恢复。

const COLORREF MY_COLOR_KEY = RGB(255, 128, 0);
HWND cmdHanlde = NULL;
constexpr unsigned int timerIdWindowUpdate = 1;
constexpr unsigned int timerIdFrameColor = 2;
bool tick = false;
bool minimized = false;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR    lpCmdLine,
_In_ int       nCmdShow)
{
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpszClassName = L"MyTransparentFrame";
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpfnWndProc = [](HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) -> LRESULT
{
switch (msg)
{
case WM_PAINT:
{
PAINTSTRUCT ps{};
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc{}; GetClientRect(hwnd, &rc);
HPEN hPen = CreatePen(PS_SOLID, 5, tick ? RGB(255, 128, 1) : RGB(255, 201, 14));
HBRUSH hBrush = CreateSolidBrush(MY_COLOR_KEY);
HGDIOBJ hOldPen = SelectObject(hdc, hPen);
HGDIOBJ hOldBrush = SelectObject(hdc, hBrush);
Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
if (hOldPen)
SelectObject(hdc, hOldPen);
if (hOldBrush)
SelectObject(hdc, hOldBrush);
if (hPen)
DeleteObject(hPen);
if (hBrush)
DeleteObject(hBrush);
EndPaint(hwnd, &ps);
}
break;
case WM_TIMER:
{
if (wp == timerIdWindowUpdate)
{
WINDOWPLACEMENT windowPlacement = { sizeof(WINDOWPLACEMENT), };
if (::GetWindowPlacement(cmdHanlde, &windowPlacement))
{
if (windowPlacement.showCmd == SW_SHOWMINIMIZED
|| !IsWindowVisible(cmdHanlde))
{
minimized = true;
}
else
{
RECT rect = {};
DwmGetWindowAttribute(cmdHanlde, DWMWA_EXTENDED_FRAME_BOUNDS, &rect, sizeof(rect));
MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfoW(MonitorFromWindow(cmdHanlde, MONITOR_DEFAULTTONEAREST), &monInfo);
if (cmdHanlde != NULL && ::IsZoomed(cmdHanlde))
{
rect.left = monInfo.rcWork.left;
rect.top = monInfo.rcWork.top;
rect.bottom = monInfo.rcWork.bottom > rect.bottom ? rect.bottom : monInfo.rcWork.bottom;
rect.right = monInfo.rcWork.right > rect.right ? rect.right : monInfo.rcWork.right;
}
if (minimized)
{
::SetWindowPos(hwnd, cmdHanlde, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
minimized = false;
}
else
{
::SetWindowPos(cmdHanlde, hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
::SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_SHOWWINDOW);
}
}
}
}
else if (wp == timerIdFrameColor)
{
tick = !tick;
::RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hwnd, msg, wp, lp);
}
return 0;
};
RegisterClassEx(&wc);
HWND hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE |     WS_EX_LAYERED |     WS_EX_TRANSPARENT, wc.lpszClassName, L"", WS_POPUP | WS_VISIBLE | WS_DISABLED,
0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr);
::SetTimer(hwnd, timerIdWindowUpdate, 50, NULL);
::SetTimer(hwnd, timerIdFrameColor, 500, NULL);
SetLayeredWindowAttributes(hwnd, MY_COLOR_KEY, 255, LWA_COLORKEY);
ShowWindow(hwnd, SW_SHOW);
cmdHanlde = FindWindow(L"ConsoleWindowClass", L"C:\WINDOWS\system32\cmd.exe");
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}

所以这里的问题是如何在目标窗口被另一个窗口重叠后恢复目标窗口?

if (minimized) {
ShowWindow(hwnd, SW_HIDE);
minimized = false;
} else {
SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, 
rect.bottom - rect.top, SWP_NOZORDER);
SetWindowPos(hwnd, GetNextWindow(cmdHandle, GW_HWNDPREV), 0, 0, 0, 0, 
SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
}