【问题标题】:Why does WM_CLOSE/DESTROY only partially close my Notepad window?为什么 WM_CLOSE/DESTROY 只部分关闭我的记事本窗口?
【发布时间】:2018-06-26 05:52:15
【问题描述】:

我的场景是一个程序调用我的 DLL,我使用 Process.Start(notepad) 在 Windows 10 x64 上启动记事本窗口。我不保存已启动进程的进程 ID。然后过了一段时间,一个程序再次调用我的 DLL,我找到了记事本窗口句柄(通过匹配标题字符串)。

问题是当我使用句柄向窗口发送 WM_CLOSE 或 DESTROY 消息时,作业没有完成。窗口确实从我的屏幕上消失了。它确实从任务栏中消失了。但是当我用 Alt-TAB 查看窗口时,它就在那里。它并没有真正消失。它只是从任务栏中隐藏。我正在使用这个 Win32 API 调用来尝试关闭窗口。

[DllImport ("user32.dll", SetLastError = true)]
public static extern bool CloseWindow (IntPtr hWnd);

(1) 我做错了什么?

(2) 我的期望是否超出预期?我(作为在一个进程下运行的 DLL)甚至可以命令另一个进程中的记事本关闭吗?

我想,有了记事本句柄,我可以将它带到前台,然后以某种方式将 Alt+F4 发送到它的键盘缓冲区,以假装它以为我正在向它输入字符。但是,这似乎是一个漫长的过程。

(3) 我如何以编程方式告诉应用程序关闭其窗口,而不会将它们带到前台并向它们发送击键,或者不向它们发送鼠标点击 X 关闭按钮?

我查看了论坛上的其他帖子,但他们大多谈论使用进程 API 终止进程 - 一种蛮力终止方法,这并不是我真正想做的。 (此外,我想关闭我感兴趣的单个窗口,而不是可能运行像 MS Word 这样的十几个不同窗口的整个进程......)

【问题讨论】:

  • 这种黑客攻击可能需要针对不同程序使用不同的方法。记事本真的是你的目标吗?
  • 记事本确实是我的目标之一。我使用语音识别命令启动应用程序、切换到应用程序、关闭窗口、发送文本等。关闭应用程序(我希望是任何应用程序)是所需的操作之一。
  • 为什么不使用 UIAutomation?毕竟是平台自动化API
  • 感谢您对 UIAutomation 的引用 - 我从未听说过。据我所知,那里有很多材料要阅读。我会做更多的阅读,看看我可以如何使用它。

标签: winapi notepad


【解决方案1】:

我正在使用 [CloseWindow] 尝试关闭窗口。

CloseWindow 不会关闭窗口——它会将其最小化。

改为向窗口发送WM_CLOSE 消息:

SendMessage(h, WM_CLOSE, 0, 0);

【讨论】:

  • 这可以解释这个动作。我会尝试您对 SendMessage 的建议。 (在阅读了 Petzold 以及有关该主题的大量帖子和代码之后,我现在感觉不聪明。我一直认为 CloseWindow 为我发送了 WM_CLOSE 消息,并且它会在 WndProc 中很好地破坏窗口. 我会在这里报告我的发现。谢谢
  • 试试我的建议,凯文,它有更广泛的应用。 @DavidHeffernan 对于屏幕键盘(运行提升/特权)确实工作(例如,当发送 WM_CLOSE 失败时)。
  • 我会尽职尽责地尝试您的建议,对此毫无疑问。要学的东西太多,时间太少了(不幸的是,这是一个业余爱好项目,需要花费大量时间)。
【解决方案2】:

尝试这样做:

SendMessage (hWnd, WM_SYSCOMMAND, SC_CLOSE, 0);  // or PostMessage perhaps better

这是当您单击关闭框时 Windows 发送的内容,并且更有可能在更广泛的应用程序中运行,因为应用程序会认为它已被用户关闭并应采取相应措施。

【讨论】:

  • 谢谢你,保罗 - 我也会尝试这种方法。很明显,我需要回到我的 Petzold 书并深入研究 WM_* 消息,现在我可以看到发送消息和调用 API(如 CloseWindow)之间的区别。
  • PostMessage 是异步的,如果我没记错的话,而我的调用应用程序必须等待 SendMessage 的响应。现在我必须弄清楚如何对我 WM_CLOSE 记事本时弹出的对话框说“不保存”。
  • 使用PostMessage 的好处是,如果目标应用程序因任何原因无响应,它不会挂起调用应用程序。你也可以使用SendMessageTimeout,如果你想知道目标应用程序何时处理了消息,但又不想永远挂起,如果它永远不会回复你。弹出窗口祝你好运。
  • 我在网上做了更多关于 PostMessage 的阅读(由于您提到的原因,这对我很有吸引力)但是这个词不应该使用它,因为它不会重置键盘状态并且可能会被混淆国际键盘/语言等。我想我是在 Raymond Chen 的网站上读到的。 SendInput 是模拟输入到具有焦点的活动应用程序的推荐路径。我猜 Save 弹出窗口会成为焦点,所以 SendInput 应该可以解决这个问题。 (如果可以的话,我宁愿直接向它发送一条消息。也许我可以通过某种方式从父应用程序的句柄中识别它。
  • Paul,我刚刚尝试了上面的WM_SYSCOMMAND 方法,效果也很好。我删除了尾随的 0 参数之一,因为据我所知,SendMessage 需要四个参数而不是五个。再次感谢你的帮助。我将保留 SYSCOMMAND 调用,因为您说它适用于更广泛的情况。
猜你喜欢
  • 1970-01-01
  • 2023-03-19
  • 2011-09-26
  • 1970-01-01
  • 2023-02-17
  • 2022-01-24
  • 2020-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多