PostThreadMessage 无法 "Cleanly" 关闭应用程序

PostThreadMessage Fails to "Cleanly" Close Application

我一直在开发一个应用程序 (VB.Net),它允许用户通过 Adob​​e Acrobat 打开 PDF 文件。这些文件随时可能更改,因此我没有直接从服务器打开,而是将文件复制到本地驱动器并打开它。使用文件系统观察器,我可以通知用户文件已更改。

我想要完成的是 'cleanly' 关闭文件并为用户重新打开它,如果他们对消息对话框的响应是肯定的话。

到目前为止,这是我所做的:

Dim threadId As Int32 = 0
Dim id As Int32 = 0

'hWnd is obtained from the Win32 Function: GetForegroundWindow()
'when called by a WinEventHook when the Active Window changes.

threadId = GetWindowThreadProcessId(hWnd, id)    'Id always returns 0, Not sure why
PostThreadMessageW(threadId, WM_CLOSE, 0, 0)    'WM_CLOSE Does not seem to close the
                                                ', however WM_QUIT always closes the window

If WaitForSingleObject(hWnd, 1000) <> WAIT_OBJECT_0 Then  'The returned result always seems to be -1
    TerminateProcess(hWnd, 0) 'This does not do what it's supposed to do.
End If

即使我能够让 Window 退出(仅使用 WM_QUIT),当我尝试使用以下方法重新打开文件时:

Process.Start(FilePath)

Acrobat 状态 - "There was an error opening this document. This file is already open or in use by another application."

我觉得这条消息很奇怪,因为在我到达 Process.Start() 之前,我删除了文件(如果存在)并重新创建它。 Visual Studio 中没有抛出异常,所以我不知道为什么这不起作用。

我已从中获得参考 link - https://support.microsoft.com/en-us/kb/178893

我还应该注意,我曾尝试通过跟踪应用程序打开的每个 window 的 ProcessId 来采用类似的方法。我使用 Id 创建了一个我使用的新进程对象:Process.Close()、Process.CloseMainWindow() 和 Process.Kill()。我收到了与之前提到的相同的消息提醒。

我不知道为什么这些选项不起作用,但很明显我做错了什么。任何帮助将不胜感激,或替代方法来实现我的最终目标。谢谢!

你的方法存在根本性的缺陷,虽然我知道你正在尝试学习如何做事,但这是一个相当高级的事情,你代码中的注释表明你还不够了解Windows 如何做这些事情。

我将首先整理您的评论:

hWnd is obtained from the Win32 Function: GetForegroundWindow() when called by a WinEventHook when the Active Window changes.

这是检测 Adob​​e Reader 的笨拙方法。还有更好的选项,例如 FindWindow(),不需要用户交互或挂钩。

此外,如果我将活动 window 更改为 Adob​​e Reader 以外的其他内容会怎样?现在您正在与一个根本不是 Adob​​e Reader 的外国 window 互动!您的代码将 close/quit/etc。一个随机程序,你永远不会意识到它。这就是为什么 GetForegroundWindow() 是一个错误,而 there are far worse things that you can do with the foreground window handle.

的部分原因

Id always returns 0, Not sure why

我也不知道为什么,但是...

PostThreadMessageW

这很糟糕,因为 if the program is in a modal loop, your thread message disappears. But you have a window handle; the SendMessage() documentation 说它将为您处理跨进程和跨线程 window 消息。

WM_CLOSE

此外,使用 PostThreadMessage() 发布的消息不会提供给特定的 window(您直接在 消息泵 中处理它们)。 WM_CLOSE 是 windows 处理的消息;您需要将其发送到 window,而不是线程。

WM_CLOSE Does not seem to close the [window], however WM_QUIT always closes the window

WM_QUIT 告诉消息泵它应该停止处理消息。你不是在告诉 window 关闭,你是在告诉程序终止!

WaitForSingleObject(hWnd

WaitForSingleObject() 等待内核对象,例如互斥对象和事件对象。 Window 句柄不是内核对象(它们是 window 管理器对象),因此您不能使用 WaitForSingleObject() 等待 window 关闭。为此使用 WinEvents。

TerminateProcess(hWnd, 0)

同样,window 句柄与进程句柄是分开的,因此您不能通过给它一个 window 句柄来终止进程。

并且通过像这样终止 Adob​​e Reader,你最终会做其他邪恶的事情,比如关闭我当时打开的任何其他 PDF,或者不让注释插件自行清理。


我不确定我会建议您从什么开始,因为我不知道您对 Windows API 有多熟悉。但我建议在尝试类似的东西之前尝试编写一个中等大小的纯 Windows-API 应用程序,因为这里显示的误解是 Windows 编程的基础。

但让我们来解决您最初的问题:您想要创建一个经常更改的 PDF 文件,并希望 Reader 在 PDF 更改时自行更新。但是你认为你这样做的方式有问题。如果此人正在查看特定页面怎么办?除非他们的 Reader 被设置为保存 PDF 文件中的位置,否则当 PDF 重新打开时,他们将返回到第 1 页。 reader 可能所做的注释也将丢失。

您应该调查 Reader 是否提供实时更新功能(如果没有 API)。 Mabye 甚至考虑尝试为 Reader 编写一个插件来执行此操作,如果还没有的话。

祝你好运!

实现你所追求的正确方法是使用官方Acrobat Interapplication Communication. It supports all operations you wish to use through DDE Messages, or OLE Automation

Acrobat SDK is available through this link.