Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

添加和其他程序交互的机制 #895

Merged
merged 7 commits into from
Apr 22, 2024
Merged

添加和其他程序交互的机制 #895

merged 7 commits into from
Apr 22, 2024

Conversation

Blinue
Copy link
Owner

@Blinue Blinue commented Apr 18, 2024

Close #447

我创建了 MagpieWatcher 来演示这些机制。

如何在缩放状态改变时得到通知

监听 MagpieScalingChanged 消息。

UINT WM_MAGPIE_SCALINGCHANGED = RegisterWindowMessage(L"MagpieScalingChanged");

参数

wParam 为事件 ID,对于不同的事件 lParam 有不同的含义。目前支持两个事件:

  • 0: 缩放已结束。不使用 lParam
  • 1: 缩放已开始。lParam 为缩放窗口句柄。

注意事项

如果你的进程完整性级别 (Integration level) 比 Magpie 更高,由于用户界面特权隔离 (UIPI),你将无法收到 Magpie 广播的消息。这种情况下请调用 ChangeWindowMessageFilter 允许接收 MagpieScalingChanged 消息。

ChangeWindowMessageFilter(WM_MAGPIE_SCALINGCHANGED, MSGFLT_ADD);

如何获取缩放窗口句柄

你可以监听 MagpieScalingChanged 消息来获取缩放窗口句柄,也可以查找类名为Window_Magpie_967EB565-6F73-4E94-AE53-00CC42592A22的窗口以在缩放中途获取该句柄。Magpie 将确保此类名不会改变,且不会同时存在多个缩放窗口。

HWND hwndScaling = FindWindow(L"Window_Magpie_967EB565-6F73-4E94-AE53-00CC42592A22", nullptr);

如何将你的窗口置于缩放窗口上方

你的窗口必须是置顶的。你还应该监听 MagpieScalingChanged 消息,当收到该消息时缩放窗口已经显示,然后你可以使用 BringWindowToTop 函数将自己的窗口置于缩放窗口上方。缩放窗口在存在期间不会尝试调整自己在 Z 轴的位置。

HWND hWnd = CreateWindowEx(WS_EX_TOPMOST, ...);
...
if (message == WM_MAGPIE_SCALINGCHANGED) {
    switch (wParam) {
        case 0:
            // 缩放已结束
            break;
        case 1:
            // 缩放已开始
            // 将本窗口置于缩放窗口上面
            BringWindowToTop(hWnd);
            break;
        default:
            break;
    }
}

如何获取缩放信息

缩放窗口的窗口属性中存储着缩放信息。目前支持以下属性:

  • Magpie.SrcHWND: 源窗口句柄
  • Magpie.SrcLeftMagpie.SrcTopMagpie.SrcRightMagpie.SrcBottom: 被缩放区域的边界
  • Magpie.DestLeftMagpie.DestTopMagpie.DestRightMagpie.DestBottom: 缩放后区域矩形边界
HWND hwndSrc = (HWND)GetProp(hwndScaling, L"Magpie.SrcHWND");

RECT srcRect;
srcRect.left = (LONG)(INT_PTR)GetProp(hwndScaling, L"Magpie.SrcLeft");
srcRect.top = (LONG)(INT_PTR)GetProp(hwndScaling, L"Magpie.SrcTop");
srcRect.right = (LONG)(INT_PTR)GetProp(hwndScaling, L"Magpie.SrcRight");
srcRect.bottom = (LONG)(INT_PTR)GetProp(hwndScaling, L"Magpie.SrcBottom");

RECT destRect;
destRect.left = (LONG)(INT_PTR)GetProp(hwndScaling, L"Magpie.DestLeft");
destRect.top = (LONG)(INT_PTR)GetProp(hwndScaling, L"Magpie.DestTop");
destRect.right = (LONG)(INT_PTR)GetProp(hwndScaling, L"Magpie.DestRight");
destRect.bottom = (LONG)(INT_PTR)GetProp(hwndScaling, L"Magpie.DestBottom");

如何使 Magpie 在你的窗口位于前台时保持缩放

前台窗口改变时 Magpie 会停止缩放,只对某些系统窗口例外。你可以通过设置属性 Magpie.ToolWindow 将自己的窗口添加入例外,这对由该窗口拥有 (owned) 的窗口也有效。

SetProp(hWnd, L"Magpie.ToolWindow", (HANDLE)TRUE);

@Blinue Blinue added the enhancement New feature or request label Apr 18, 2024
@Blinue
Copy link
Owner Author

Blinue commented Apr 21, 2024

把 MessageBox 的 hWnd 参数设为主窗口即可,弹窗会被主窗口“拥有”。如果希望弹窗期间主窗口可以交互,可以用 TaskDialogIndirect 代替。

TASKDIALOGCONFIG tdc{
    .cbSize = sizeof(TASKDIALOGCONFIG),
    .dwFlags = TDF_SIZE_TO_CONTENT,
    .pszWindowTitle = L"test",
    .pszContent = L"test",
    .cButtons = 0,
    .pButtons = nullptr,
    .pfCallback = [](HWND hWnd, UINT msg, WPARAM /*wParam*/, LPARAM /*lParam*/, LONG_PTR /*lpRefData*/) -> HRESULT {
        if (msg == TDN_CREATED) {
            SetProp(hWnd, L"Magpie.ToolWindow", (HANDLE)TRUE);
        }

        return S_OK;
    }
};
TaskDialogIndirect(&tdc, nullptr, nullptr, nullptr);

@Blinue
Copy link
Owner Author

Blinue commented Apr 21, 2024

消息窗口和文件选择窗口一般都是模态的,不需要特殊处理。原本这个机制只用于简单的场景,你的场景比较复杂的话就必须自己处理复杂的情况了。

从窗口属性读取进程 ID 不大可行。

  1. 粒度太大,可能还需要实现排除的机制
  2. Magpie 必须保存状态,这不是好设计。想象一下你的程序退出之后,Magpie 保存的进程 ID 就会无效
  3. 如果弹窗在主窗口之前得到焦点也会退出缩放,因为弹窗上没有属性,就无法获得进程 ID

@Blinue
Copy link
Owner Author

Blinue commented Apr 22, 2024

以管理员身份运行 Magpie 问题还存在吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

建议增加功能:窗口失焦后保持全屏
1 participant