我一直在开发一个应用程序(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()。我收到了与之前提到的相同的消息。
我不知道为什么这些选项不起作用,但很明显我做错了。任何帮助都将非常感激,或完成我的最终目标的替代方法。谢谢!
答案 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 Messages或OLE Automation使用的所有操作。
此Acrobat SDK可以使用link。