我很高兴将 msys2 与 pacman 包管理器结合使用来创建一个库。该库有一个窗口的概念,它围绕 HWND 和 winuser.h 的函数来创建窗口和窗口类。这些窗口旨在作为顶层窗口。通常我会怀疑一个窗口在第一次打开时满足多个条件:
无论我如何尝试,都没有满足上述条件之一。该窗口位于 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 终端而不是我的窗口)。
有一些极端情况,满足上述两点。
gdb ./some/path/myprogram.exe
现在可能与 msys2 终端的启动程序有关。 如果我通过 msys2 终端运行 chrome,它似乎也会在其他窗口下弹出。
我在 Windows 10 版本 22H2 上运行此程序
所以我的问题归结为:为什么程序通过 msys2 运行而不是弹出而不是弹出,以及为什么键盘焦点不定向到新打开的窗口?
显然,你的程序没有前台激活权限。
当用户正在使用另一个窗口时,应用程序无法强制一个窗口进入前台。相反,Windows 会闪烁窗口的任务栏按钮来通知用户。
SetForegroundWindow函数的文档非常清楚:
系统限制哪些进程可以设置前台窗口。仅当满足以下条件时,进程才能通过调用 SetForegroundWindow 设置前景窗口:
以下所有条件均成立:
- 调用进程属于桌面应用程序,而不是UWP应用程序或专为Windows 8或8.1设计的Windows Store应用程序。
- 前台进程尚未通过先前调用 LockSetForegroundWindow 函数来禁用对 SetForegroundWindow 的调用。
- 前台锁定超时已过期(请参阅 SystemParametersInfo 中的 SPI_GETFOREGROUNDLOCKTIMEOUT)。
- 没有任何菜单处于活动状态。
此外,至少满足以下条件之一:
- 调用进程为前台进程。
- 调用进程是由前台进程启动的。
- 当前没有前台窗口,因此没有前台进程。
- 调用进程收到最后一个输入事件。
- 前台进程或调用进程正在调试。
即使进程满足这些条件,也可能被拒绝设置前台窗口的权利。
我怀疑第一次打开的窗口满足多个条件:
- 它们位于其他(顶层)窗口的顶部。 (我认为,这就是当您通过 Windows 任务栏或开始菜单打开 chrome、word 等时得到的结果。
- 它们是从键盘接收输入的。
SetForegroundWindow
成功了。