在mfc开发中,我遇到了一个需求,具体逻辑是:浏览器门户调用别人的websocket,websocket调用我的dll库,我的dll库会有一个mfc对话框。要求是对话框弹出后浏览器无法做别的操作,于是我想到了mfc的模态弹框,但是模态只对调用方的线程起作用,但是直接调用方是这个websocket。于是我先使用AttachThreadInput函数将调用方线程和浏览器门户的活动线程关联起来后,再通过domodal弹出的我模态对话框。通过这种方式成功实现了我的需求,但是只有第一次调用成功实现了这个需求,后面再次调用时对话框只是弹出了并没有实现模态。除非我重启websocket服务才能再次实现。
DWORD dwForeID, dwCurID;
HWND hForeWnd = ::GetForegroundWindow();//获取当前活动窗口的窗口句柄,
g_hForeWnd = NULL;
g_hForeWnd = hForeWnd;
dwForeID = ::GetWindowThreadProcessId( hForeWnd, NULL );
dwCurID = ::GetCurrentThreadId();
::AttachThreadInput( dwForeID, dwCurID, TRUE);
CPin secpin;
secpin.DoModal();
::AttachThreadInput( dwForeID, dwCurID, FALSE);
这是我的代码片段,其中CPin是我的对话框的类。且其中AttachThreadInput没有报错,为什么会出现只有第一次才能成功的情况呢,或者有什么别的方法能够以实现我的需求吗?
模态对话框被创建后,如果没有正确处理对话框的关闭或销毁,可能会导致后续调用无法正常工作。
出现这种情况可能是因为你在第二次调用时没有成功关联线程,或者在第一次调用结束后没有正确地解除关联。为了解决这个问题,你可以尝试在第二次调用时再次使用AttachThreadInput函数将两个线程关联起来,并且在对话框关闭后使用DetachThreadInput函数将它们解除关联。
是不是第二次调用时,前台窗口程序发生了变化,导致第二次时没有正确的关联线程,导致模态对话框没有正确锁定模态状态。调试看一下第二次的时候的线程id是否正确关联。
你先把Attach函数的返回值打印出来,判断一下成功失败。写代码注意原则,所有函数调用都应判断成功失败,除非你确定该函数失败不影响功能。
您的问题可能是因为在第一次调用模态对话框后,AttachThreadInput函数未能正确地断开与活动线程的输入关联,导致第二次调用时无法正确地进行模态对话框。
建议您在每次调用模态对话框之前重新执行AttachThreadInput函数以确保正确的输入关联。示例如下:
// 关联输入
DWORD dwForeID, dwCurID;
HWND hForeWnd = ::GetForegroundWindow();
dwForeID = ::GetWindowThreadProcessId(hForeWnd, NULL);
dwCurID = ::GetCurrentThreadId();
::AttachThreadInput(dwForeID, dwCurID, TRUE);
// 创建并显示模态对话框
CPin secpin;
secpin.DoModal();
// 断开输入关联
::AttachThreadInput(dwForeID, dwCurID, FALSE);
另外,如果您需要在模态对话框打开期间阻止用户在浏览器窗口执行任何操作,您可以在模态对话框打开时设置禁用钩子,以捕获并禁止在浏览器窗口上执行的所有用户输入事件。示例代码如下:
BOOL CALLBACK DisableHook(int code, WPARAM wParam, LPARAM lParam) {
// 禁用用户输入事件
return TRUE;
}
void MyDialog::DoModal() {
// 设置禁用钩子
::SetWindowsHookEx(WH_CBT, (HOOKPROC) DisableHook, NULL, ::GetCurrentThreadId());
// 创建并显示模态对话框
CDialog::DoModal();
// 移除禁用钩子
::UnhookWindowsHookEx((HHOOK) DisableHook);
}
希望这些方法可以帮助您实现您的需求。
VC/MFC 将窗口置顶
非常详细,可以借鉴下
https://blog.csdn.net/gll028/article/details/8496136
问题应该就是出在第一次调用弹出框之后,没有正确的关闭掉之前的连接或关联,因为你是通过AttachThreadInput函数将调用方线程和浏览器门户的活动线程关联起来了,因此可能需要考虑在结束调用之后,把之前的关联也需要正确解除调才行,要不就是第二次调用的时候没有正确的关联上。具体出现在哪个地方的问题,建议还是要通过调试或者日志的方式定位下。
参考 https://blog.csdn.net/qq_45662588/article/details/116994243
基于new bing部分指引作答:
在你的代码中,使用了AttachThreadInput函数将调用方线程和浏览器门户的活动线程关联起来,以实现模态对话框的效果。然而,你遇到了只有第一次调用成功实现模态的问题。
这个问题可能是由于调用方线程和浏览器门户的活动线程在后续调用中的状态发生了变化,导致AttachThreadInput函数无法正确关联这两个线程。这可能是因为线程之间的关联是一种复杂的操作,容易受到外部因素的干扰。
为了解决这个问题,你可以尝试使用其他的方式来实现模态对话框的效果。以下是几种可能的解决方案:
1、使用全局钩子:你可以创建一个全局钩子,监视浏览器门户的消息,并在需要时禁用或过滤掉其他操作。这样,无论线程的状态如何变化,你都能够控制对话框的模态性。
2、使用MessageBox或其他非模态对话框:如果你只需要简单的信息提示或确认对话框,可以考虑使用MessageBox或其他非模态对话框来替代模态对话框。这样,你无需处理线程关联的复杂性,而且通常情况下这些对话框会阻塞用户操作。
3、调整设计:如果可能的话,重新考虑你的设计,避免需要在非常特殊的情况下实现这样的模态对话框。模态对话框会限制用户的操作,可能会对用户体验产生负面影响。如果有其他的方式来满足你的需求,可以尝试避免使用模态对话框。
总之,通过使用全局钩子或其他替代方案,你可以尝试解决只有第一次调用成功实现模态的问题。
要解决你的问题,你可以尝试以下修改:
DWORD dwForeID, dwCurID;
HWND hForeWnd = ::GetForegroundWindow(); // 获取当前活动窗口的窗口句柄
g_hForeWnd = NULL;
g_hForeWnd = hForeWnd;
dwForeID = ::GetWindowThreadProcessId(hForeWnd, NULL);
dwCurID = ::GetCurrentThreadId();
::AttachThreadInput(dwForeID, dwCurID, TRUE);
CPin secpin;
INT_PTR nResult = secpin.DoModal();
::AttachThreadInput(dwForeID, dwCurID, FALSE);
if (nResult == IDCANCEL)
{
// 处理用户取消操作
}
上述代码只是对你提供的代码进行了部分修改,主要是在模态对话框的调用后添加了对返回值的判断,以便处理用户取消操作。请注意,这仅是针对你当前代码的修改建议,并不能保证解决你所遇到的问题。