创建不可见和无模式属性 sheet 导致焦点改变?
Creating invisible and modeless property sheet causes focus change?
我正在调查与 windows 失去焦点和更改激活相关的问题。我发现如果我创建一个不可见的 属性 sheet,active/foreground window 会改变,焦点 window 也会改变。下面是一些示例 MFC 代码:
// ignore CAutoDeleter, just a template that calls "delete this " in PostNcDestroy()
CPropertySheet* pSheet = new CAutoDeleter<CPropertySheet>(_T("Test Sheet"));
CTestPage* pPage = new CAutoDeleter<CTestPage>();
pSheet->AddPage(pPage);
DWORD style = WS_SYSMENU | WS_POPUP | WS_CAPTION | DS_MODALFRAME | DS_CONTEXTHELP;
// style |= WS_DISABLED; //does nothing to help
DWORD exStyle = 0;
//exStyle = WS_EX_NOPARENTNOTIFY|WS_EX_NOACTIVATE; // does nothing to help
pSheet->Create(AfxGetMainWnd(), style, exStyle); // adding
调用pSheet->Create()后,active/foreground/focus window发生变化,应用程序window在最上面。如果我使用 Spy++ 并查看创建的 window,就会发现 属性 sheet 是 DIALOG window class。当然,我假设它有一个不同的 WNDPROC。有趣的是,如果我使用创建一个不可见的无模式对话框,它不会出现问题。如果我创建不可见的无模式对话框,active/foreground/focus window 保持不变。
我尝试像代码片段中那样设置各种标志,但遗憾的是它们没有任何明显的效果——我仍然对闪烁和激活毫无意义。
我可以通过在 pSheet->Create()
之前和之后设置和清除钩子 (WH_CBT) 来获得一些改进--然后吃掉激活消息。当我这样做时,我没有可怕的闪烁,我的应用程序 window 也没有出现在顶部。但是,焦点(以及具有插入符号的 windows 的插入符号)确实离开了 window 在 Create() 之前拥有的焦点。
有谁知道在创建隐形 属性 sheet 时保持焦点和激活不变的方法吗? (在某些时候,属性 sheet 可能会或可能不会设置为可见。而且,如果 属性 sheet 在被销毁时不可见,它也会导致闪烁和激活更改。)
我尝试使用 GetUIThreadInfo() 中返回的值尝试在调用 Create() 后恢复内容,但它也会导致一些闪烁。
我只想知道如何创建一个不可见的 属性 Sheet,它不会导致活动、前景和焦点 window 发生变化。
不幸的是,在创建后 属性 sheet 主对话框上的基础 API 函数 PropertySheet
calls SetForegroundWindow
。没有简单的方法解决这个问题 - 使用 WH_CBT
钩子的拼凑可能是你最好的选择。
编辑:正如@stephen 在 this duplicate question, you may be able to prevent the activation/focus change using LockSetForegroundWindow
.
评论中所建议的
几周来我一直在为同一个问题苦苦挣扎,在一个类似的项目中,我的主应用程序启动了一个辅助 EXE 进程以充当音频应用程序中的服务器(它需要一个单独的进程来屏蔽插件故障的应用程序,因此它可以作为实时音频处理的高优先级。
我的辅助 EXE 是无模式的 CPropertySheet
,用于状态和诊断显示,但旨在隐藏并在后台启动。然而,它总是在启动时从主应用程序窃取激活,无论我尝试了什么解决方法(例如覆盖 OnWindowPosChanging
)。
我以为我要疯了,所以很高兴找到这个问题。 WH_CBT 技巧很有用,但我发现虽然它阻止了辅助 EXE 的激活,但它并没有阻止主应用程序的停用。
但后来我在 LockSetForegroundWindow
API(从 Win2K 开始可用)中发现了一个我以前从未听说过的优秀解决方案。看起来它正是为了这个目的而设计的,以禁用前台激活的更改并防止对等进程窃取它。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633532(v=vs.85).aspx
它非常有效地取消了在 属性 sheet 公共控件深处发生的对 SetForegroundWindow
的内部调用,并且无论在 [=之前在主应用程序中使用它都同样有效=15=] 或在辅助 EXE 中。我选择了后一种情况,以包装 属性 sheet 创建:
LockSetForegroundWindow(LSFW_LOCK);
pSheet->Create(NULL, dwStyle, dwExStyle);
LockSetForegroundWindow(LSFW_UNLOCK);
这最大限度地减少了干预范围,并使修复本地化到作为问题根源的进程。我希望这可以避免其他人像我一样在这个乏味的问题上浪费太多时间。
我正在调查与 windows 失去焦点和更改激活相关的问题。我发现如果我创建一个不可见的 属性 sheet,active/foreground window 会改变,焦点 window 也会改变。下面是一些示例 MFC 代码:
// ignore CAutoDeleter, just a template that calls "delete this " in PostNcDestroy()
CPropertySheet* pSheet = new CAutoDeleter<CPropertySheet>(_T("Test Sheet"));
CTestPage* pPage = new CAutoDeleter<CTestPage>();
pSheet->AddPage(pPage);
DWORD style = WS_SYSMENU | WS_POPUP | WS_CAPTION | DS_MODALFRAME | DS_CONTEXTHELP;
// style |= WS_DISABLED; //does nothing to help
DWORD exStyle = 0;
//exStyle = WS_EX_NOPARENTNOTIFY|WS_EX_NOACTIVATE; // does nothing to help
pSheet->Create(AfxGetMainWnd(), style, exStyle); // adding
调用pSheet->Create()后,active/foreground/focus window发生变化,应用程序window在最上面。如果我使用 Spy++ 并查看创建的 window,就会发现 属性 sheet 是 DIALOG window class。当然,我假设它有一个不同的 WNDPROC。有趣的是,如果我使用创建一个不可见的无模式对话框,它不会出现问题。如果我创建不可见的无模式对话框,active/foreground/focus window 保持不变。
我尝试像代码片段中那样设置各种标志,但遗憾的是它们没有任何明显的效果——我仍然对闪烁和激活毫无意义。
我可以通过在 pSheet->Create()
之前和之后设置和清除钩子 (WH_CBT) 来获得一些改进--然后吃掉激活消息。当我这样做时,我没有可怕的闪烁,我的应用程序 window 也没有出现在顶部。但是,焦点(以及具有插入符号的 windows 的插入符号)确实离开了 window 在 Create() 之前拥有的焦点。
有谁知道在创建隐形 属性 sheet 时保持焦点和激活不变的方法吗? (在某些时候,属性 sheet 可能会或可能不会设置为可见。而且,如果 属性 sheet 在被销毁时不可见,它也会导致闪烁和激活更改。)
我尝试使用 GetUIThreadInfo() 中返回的值尝试在调用 Create() 后恢复内容,但它也会导致一些闪烁。
我只想知道如何创建一个不可见的 属性 Sheet,它不会导致活动、前景和焦点 window 发生变化。
不幸的是,在创建后 属性 sheet 主对话框上的基础 API 函数 PropertySheet
calls SetForegroundWindow
。没有简单的方法解决这个问题 - 使用 WH_CBT
钩子的拼凑可能是你最好的选择。
编辑:正如@stephen 在 this duplicate question, you may be able to prevent the activation/focus change using LockSetForegroundWindow
.
几周来我一直在为同一个问题苦苦挣扎,在一个类似的项目中,我的主应用程序启动了一个辅助 EXE 进程以充当音频应用程序中的服务器(它需要一个单独的进程来屏蔽插件故障的应用程序,因此它可以作为实时音频处理的高优先级。
我的辅助 EXE 是无模式的 CPropertySheet
,用于状态和诊断显示,但旨在隐藏并在后台启动。然而,它总是在启动时从主应用程序窃取激活,无论我尝试了什么解决方法(例如覆盖 OnWindowPosChanging
)。
我以为我要疯了,所以很高兴找到这个问题。 WH_CBT 技巧很有用,但我发现虽然它阻止了辅助 EXE 的激活,但它并没有阻止主应用程序的停用。
但后来我在 LockSetForegroundWindow
API(从 Win2K 开始可用)中发现了一个我以前从未听说过的优秀解决方案。看起来它正是为了这个目的而设计的,以禁用前台激活的更改并防止对等进程窃取它。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633532(v=vs.85).aspx
它非常有效地取消了在 属性 sheet 公共控件深处发生的对 SetForegroundWindow
的内部调用,并且无论在 [=之前在主应用程序中使用它都同样有效=15=] 或在辅助 EXE 中。我选择了后一种情况,以包装 属性 sheet 创建:
LockSetForegroundWindow(LSFW_LOCK);
pSheet->Create(NULL, dwStyle, dwExStyle);
LockSetForegroundWindow(LSFW_UNLOCK);
这最大限度地减少了干预范围,并使修复本地化到作为问题根源的进程。我希望这可以避免其他人像我一样在这个乏味的问题上浪费太多时间。