独立的 Windows 应用程序在焦点更改时挂起

Posted

技术标签:

【中文标题】独立的 Windows 应用程序在焦点更改时挂起【英文标题】:Standalone Windows app hangs upon change of focus 【发布时间】:2014-03-31 14:42:16 【问题描述】:

我从 Visual Studio 2008 用 C++ 编写了一个应用程序,在 Windows 7 上运行,运行良好,在调试器的控制下使用调试或发布版本,但在独立运行时,使用调试或发布版本,它也运行良好,除非我点击任何不相关的窗口,比如文件资源管理器窗口,然后应用程序挂起,没有来自 Windows 的任何警告,我看到了小圆圈。

代码正在执行一些计算密集型操作,从 10Mb 全局数组访问数据,并且完全在 32 位 Windows 的 2Gb 限制范围内。我检查了明显的东西,例如未初始化的变量,无限循环等,我没有分配任何大的本地数组,但没有发现任何问题。代码直接从 UI 线程运行,阻塞,但我不在乎,因为在该任务完成之前没有其他事情可做。或者,我可以将此代码放在它自己的工作线程中,通过互锁缓冲区与 UI 线程通信,但这似乎是多余的。我已经在运行 Windows 7 的两台不同机器上进行了尝试,并获得了相同的行为。我忽略了有关 Windows 进程管理的某些内容吗?有没有办法判断是否存在某种内存损坏,可能导致其他进程影响应用程序的进程?

[Edit1 by spektre] 刚刚从评论中复制了 user3481340 的代码以便阅读

我不认为计算时间,大约是一个小时 与问题有关。 相反,编辑框的 Windows 消息传递变得混乱。

相关代码为:

int textlen=GetWindowTextLength(Editwin);
int k=strcspn(messagebuf,"\n");
if(k<strlen(messagebuf))textlength=strlen(messagebuf)-k;
 else textlength+=k;
SendMessage (Editwin, EM_SETSEL, (WPARAM)textlen, (LPARAM)textlen);
SendMessage (Editwin, EM_REPLACESEL, 0, (LPARAM) messagebuf);

Windows 不知何故停止响应这些消息。

【问题讨论】:

计算需要多长时间? 您是否尝试过放入任何调试语句(例如 OutputDebugString)并使用 DebugView 来监控您的应用正在/未在做什么?也许它根本没有挂起? 我不知道 DebugView。它表明代码的计算部分根本没有挂起,而是文本输出正在停止。我正在将文本写入一个大的编辑框,并且在单击另一个窗口时,文本流会以某种方式停止。 回答 AndyT 的问题。这也可能是您自己问题的答案。 我认为大约一个小时的计算时间与问题无关。相反,编辑框的 Windows 消息传递变得混乱。相关代码为: int textlen=GetWindowTextLength(Editwin); int k=strcspn(messagebuf,"\n"); if(k 【参考方案1】:

Windows7 有一些变化(从以前的 Windows 版本开始)

    在进程调度中

    这可能会弄乱在旧版本 Windows 上运行 100% 线程安全的无锁多线程应用程序。与此无关(除非添加一些安全睡眠或锁定)

    关键部分

    我不是 100% 相信关键部分在 Win7SP1 上可以正常工作,因为我在特定机器设置上遇到了一些问题,它们不能与以下组合一起工作:

    重型 USB HS 批量数据传输 OpenGL 使用 使用繁重的多个关键部分的多线程

    但它可能是一个隐藏的错误或混乱的 Windows7 安装,甚至是硬件错误

    WindowProc

    如果您的消息循环卡住了更长时间,那么它应该会导致程序被检测为无响应,即使它不是。通常在兼容 XPSP3 的情况下运行会有所帮助,但遗憾的是不是在所有机器或所有应用程序上运行 :( 这是许多游戏无法在 Win7 上运行的主要原因

    我怀疑这是你的情况,根据你最后的评论,我是对的。

    将关键处理转移到某个线程,这样WindowProc 就不会被阻塞。如果您在计算完成后需要一个事件,则将某个变量标记为已完成并在某个计时器中对其进行扫描,以便您可以在主线程内响应(以避免在主线程外调用 winapi)。

    在 x64 窗口 (WOW64) 上使用 32 位驱动程序+应用程序

    如果您的应用程序正在访问任何驱动程序,那么在 WOW64 上,您需要特殊的驱动程序构建来访问真实硬件,而不是由 WOW64 模拟!!!如果您不这样做,那么您的应用程序很可能正在等待真实设备响应,而不是被模拟一个,这可能会有所不同并导致真正的挂断。在这种情况下,您需要将您的应用程序编译为 x64

    或者使用某种 WOW64.x86 -> x64 桥

    或者使用可以自己处理的驱动(通常链接做不同的dll)

【讨论】:

即使 Windows 说我的应用程序“无响应”,它不应该在调用新的 SendMessage() 后返回吗?或者,是否一旦消息循环被认为被卡住,它就会一直卡住?如何将核心计算移动到其自己的工作线程,并带有一个用于文本输出的互锁缓冲区来解决这个问题(或不解决这个问题)?正如我所说,核心计算需要一段时间才能运行,我想看看它到底发生了什么。 你不能在 WindowProc 之外使用 winapi,因为它会弄乱窗口!之后,当您停止 windproc 的时间超过其超时时间(仅几毫秒)时,视觉内容的行为会被破坏(混乱的 gfx、错误的文本、冻结、不正确的时间......)然后 win7 冻结/杀死您的 WindowProc 线程! !并且不会将CPU返回给它!您还应该在 WinApi 调用之前检查文本指针是否包含正确的数据(只是为了确保您不会扫描 ~100MB 文本以获取随机数据中的第一个零) 能否通过使用计时器以小于超时值的周期生成周期性 WM_TIMER 事件来解决此问题? 我尝试将长计算放在它自己的工作线程中,这工作正常,但只要我点击任何其他不相关的窗口,应用程序输出就会停止,与以前的行为相同。我认为问题在于 5 秒窗口超时以外的其他问题。 然后尝试禁用程序的所有部分,只保留 GUI。然后尝试问题是否仍然存在...如果没有,则逐个启用,直到出现问题。这样你应该发现问题出在哪里。 (可能是与 winapi 无关的东西,例如内存泄漏或数组过度/不足运行访问......)......没有实际的源代码只是猜测工作......

以上是关于独立的 Windows 应用程序在焦点更改时挂起的主要内容,如果未能解决你的问题,请参考以下文章

在Mac上完成多处理时挂起,但不在Windows上挂起

HttpClient 在执行第二个请求时挂起

在 Windows 上安装 Yarn 时挂起的 Fibers/node-gyp

Python for Windows 在调用 MinGW-w64 编译库的函数时挂起

如何修复 pip 在安装 sqlalchemy 时挂起的问题

Ruby on Rails 控制台在加载时挂起