msys2 窗口在后台打开,而不是在 HWND_TOP

问题描述 投票:0回答:1

我很高兴将 msys2 与 pacman 包管理器结合使用来创建一个库。该库有一个窗口的概念,它围绕 HWND 和 winuser.h 的函数来创建窗口和窗口类。这些窗口旨在作为顶层窗口。通常我会怀疑一个窗口在第一次打开时满足多个条件:

  1. 它们位于其他(顶层)窗口的顶部。 (我认为,这就是当您通过 Windows 任务栏或开始菜单打开 chrome、word 等时得到的结果。
  2. 它们是从键盘接收输入的。

无论我如何尝试,都没有满足上述条件之一。该窗口位于 msys2 终端后面,还有所有其他打开的窗口。我的程序图标在底部任务栏上闪烁橙色。

我的窗口的类按如下方式创建,并在我的最后一个窗口也被销毁时被销毁。

static void
create_window_class(void)
{
    g_module_handle = GetModuleHandle(NULL);

    WNDCLASSEX win_class;
    memset(&win_class, 0, sizeof(win_class);
    win_class.cbSize        = sizeof(win_class);
    win_class.style         = CS_OWNDC;
    win_class.lpfnWndProc   = startup_winproc;
    win_class.hCursor       = LoadCursor(NULL, IDC_ARROW);
    win_class.lpszClassName = g_win_class_name;

    g_win_class  = (WNDCLASSEX*) g_malloc0(sizeof(WNDCLASSEX));
    *g_win_class = win_class;

    g_win_class_atom = RegisterClassEx(g_win_class);
    if (g_win_class_atom == 0) {
        char error_buf[1024];
        psy_strerr(GetLastError(), error_buf, sizeof(error_buf));
        g_critical("Unable to create WindowClass '%s': %s",
                   g_win_class_name,
                   error_buf);
    }
}

然后窗口就这样创建了:

static void
win_window_constructed(GObject *object)
{
    PsyWinWindow *self = PSY_WIN_WINDOW(object);
    G_OBJECT_CLASS(psy_win_window_parent_class)->constructed(object);

    DWORD win_style = WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU | WS_CAPTION;
    DWORD win_style_ex = WS_EX_OVERLAPPEDWINDOW;

    gint nth_mon = psy_window_get_monitor(PSY_WINDOW(self));
    g_assert(nth_mon >= 0 && (guint) nth_mon < self->display_info->len);
    PsyDisplayInfo *desired_monitor = self->display_info->pdata[nth_mon];
    PsySize        *size            = desired_monitor->rect->size;
    PsyPos         *pos             = desired_monitor->rect->pos;

    RECT r;
    r.bottom = 480,    // pos->y + size->height;
    r.top    = pos->x, // pos->y;
    r.right  = 640,    // pos->x + size->width;
    r.left   = pos->y, // pos->x;

    // We could use AdjustWindowRectEx to set the client size to the desired
    // size however, we try just to create a window at fullscreen size
    // AdjustWindowRectEx(&r, win_style, FALSE, win_style_ex);

    self->window = CreateWindowEx(win_style_ex,
                                  g_win_class_name,
                                  "psy_window",
                                  win_style,
                                  r.left,
                                  r.top,
                                  r.right - r.left,
                                  r.bottom - r.top,
                                  NULL,
                                  NULL,
                                  g_module_handle,
                                  self);
    if (!self->window) {
        char error_buff[1024];
        psy_strerr(GetLastError(), error_buff, sizeof(error_buff));
        g_critical("Unable to create window: %s", error_buff);
        return;
    }

    BOOL success;
    ShowWindow(self->window, SW_SHOWMAXIMIZED);

    // Try to set it to the top in the Z-order, this functions
    // succeeds, however, the windows Z-order policy doesn't
    // allow the monitor to go to the top. Only once the user
    // clicks it, it will go to the top. Currently, the window
    // will flicker it's icon on the task bar.
    //
    // Also show the window.
    success = SetWindowPos(self->window,
                           HWND_TOP,
                           0,
                           0,
                           0,
                           0,
                           SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
    if (!success) {
        char error_buf[1024];
        psy_strerr(GetLastError(), error_buf, sizeof(error_buf));
        g_critical("Unable to set window pos: %s", error_buf);
    }

    success = SetForegroundWindow(self->window);
    if (!success) {
        char error[1024];
        psy_strerr(GetLastError(), error, sizeof(error));
        g_critical(
            "%s: Unable to set window to foreground: %s", __func__, error);
    }

    PsyD3dContext *context
        = psy_d3d_context_new_full(self, 1, self->enable_debug);
    psy_canvas_set_context(PSY_CANVAS(self), PSY_DRAWING_CONTEXT(context));
}

我使用 msys2 终端运行我的程序。

./some/path/myprogram.exe

我可以看到弹出的窗口,嗯,在下面。我在任务栏上看到我的程序,如果我使用

SetForegroundWindow(self->window)
,我可以看到任务栏上的图标以橙色闪烁。我收到诸如
WM_CREATE
WM_ACTIVATE
之类的消息(尽管我确实收到消息键盘保留在 msys2 中,例如按 alt + f4 将关闭 msys2 终端而不是我的窗口)。

有一些极端情况,满足上述两点。

  1. 我通过 gdb 运行命令,例如
    gdb ./some/path/myprogram.exe
  2. 我运行cmd并从那里启动程序,它仅在第一次有效。
  3. 我可以将 HWND_TOPMOST 与 SetWindowPosition 一起使用,但这只会使窗口出现在其他窗口上方,即使我使用 alt+tab 或单击鼠标切换到另一个窗口,甚至键盘输入也不会集中在我的程序上。此外,在窗口可见后,我希望用户能够切换到他们选择的窗口。我无意与窗口的 z 顺序作斗争。

现在可能与 msys2 终端的启动程序有关。 如果我通过 msys2 终端运行 chrome,它似乎也会在其他窗口下弹出。

我在 Windows 10 版本 22H2 上运行此程序

所以我的问题归结为:为什么程序通过 msys2 运行而不是弹出而不是弹出,以及为什么键盘焦点不定向到新打开的窗口?

c++ c windows msys2
1个回答
0
投票

显然,你的程序没有前台激活权限。

当用户正在使用另一个窗口时,应用程序无法强制一个窗口进入前台。相反,Windows 会闪烁窗口的任务栏按钮来通知用户。
SetForegroundWindow函数的文档非常清楚:

系统限制哪些进程可以设置前台窗口。仅当满足以下条件时,进程才能通过调用 SetForegroundWindow 设置前景窗口:

以下所有条件均成立:

  • 调用进程属于桌面应用程序,而不是UWP应用程序或专为Windows 8或8.1设计的Windows Store应用程序。
  • 前台进程尚未通过先前调用 LockSetForegroundWindow 函数来禁用对 SetForegroundWindow 的调用。
  • 前台锁定超时已过期(请参阅 SystemParametersInfo 中的 SPI_GETFOREGROUNDLOCKTIMEOUT)。
  • 没有任何菜单处于活动状态。

此外,至少满足以下条件之一:

  • 调用进程为前台进程。
  • 调用进程是由前台进程启动的。
  • 当前没有前台窗口,因此没有前台进程。
  • 调用进程收到最后一个输入事件。
  • 前台进程或调用进程正在调试。

即使进程满足这些条件,也可能被拒绝设置前台窗口的权利。

我怀疑第一次打开的窗口满足多个条件:

  1. 它们位于其他(顶层)窗口的顶部。 (我认为,这就是当您通过 Windows 任务栏或开始菜单打开 chrome、word 等时得到的结果。
  2. 它们是从键盘接收输入的。
  1. 当您通过 Windows 任务栏或开始菜单打开 chrome 时,当前没有前台窗口。因此
    SetForegroundWindow
    成功了。
  2. 键盘输入定向到前台窗口。
© www.soinside.com 2019 - 2024. All rights reserved.