PostThreadMessage失败了"干净"关闭申请

时间:2015-05-27 14:09:09

标签: vb.net winapi

我一直在开发一个应用程序(VB.Net),它允许用户通过Adobe Acrobat打开PDF文件。这些文件在任何给定时刻都可能发生变化,因此我不是直接从服务器打开,而是将文件复制到本地驱动器并打开它。使用文件系统观察器,我能够通知用户已对文件进行了更改。

我想要完成的是“干净利落”。如果用户对消息对话框回答“是”,请关闭该文件并为其重新打开。

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

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

即使我能够让窗口退出(仅使用WM_QUIT),当我尝试使用以下命令重新打开文件时:

Process.Start(FilePath)

Acrobat声明 - &#34;打开此文档时出错。此文件已被其他应用程序打开或正在使用。&#34;

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

我已从此链接获得参考 - https://support.microsoft.com/en-us/kb/178893

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

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

2 个答案:

答案 0 :(得分:4)

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

我首先要分开您的意见:

  

hWnd是从Win32函数获取的:GetForegroundWindow()   当活动窗口发生变化时由WinEventHook调用。

这是一种检测Adobe Reader的笨拙方法。有更好的选项,例如FindWindow(),不需要用户互动或挂钩。

此外,如果我将活动窗口更改为Adobe Reader以外的其他内容会发生什么?现在,您正在与一个根本不是Adobe Reader的外部窗口进行交互!您的代码将关闭/退出/等。一个随机的程序,你永远不会意识到它。这是GetForegroundWindow()是一个错误的原因之一,there are far worse things that you can do with the foreground window handle

  

ID始终返回0,不确定原因

我不确定为什么,但是......

  

PostThreadMessageW

这很糟糕,因为if the program is in a modal loop, your thread message disappears。但是你有一个窗把手; SendMessage() documentation表示它将为您处理跨进程和跨线程窗口消息。

  

WM_CLOSE

此外,使用PostThreadMessage()发布的消息未提供给特定窗口(您可以直接在消息泵中处理它们)。 WM_CLOSE是窗口处理的消息;你需要把它发送到一个窗口,而不是一个线程。

  

WM_CLOSE似乎没有关闭[window],但WM_QUIT总是关闭窗口

WM_QUIT告诉消息泵它应该停止处理消息。您没有告诉窗口关闭,您告诉程序要终止!

  

WaitForSingleObject的(HWND

WaitForSingleObject()等待内核对象,例如互斥锁和事件对象。窗口句柄不是内核对象(它们是窗口管理器对象),因此您无法使用WaitForSingleObject()等待窗口关闭。使用WinEvents。

  

TerminateProcess(hWnd,0)

同样,窗口句柄与进程句柄是分开的,所以你不能通过给它一个窗口句柄来终止进程。

通过像这样终止Adobe Reader,你最终会做其他邪恶的事情,比如关闭我当时碰巧打开的其他PDF文件,或者不让注释插件自行清理。

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

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

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

祝你好运!

答案 1 :(得分:3)

实现您所需要的正确方法是使用官方Acrobat Interapplication Communication。它支持您希望通过DDE MessagesOLE Automation使用的所有操作。

Acrobat SDK可以使用link