在 VBA shell 命令中使用 AppActivate 和 Sendkeys

发布于 2024-10-11 17:26:49 字数 1987 浏览 1 评论 0原文

我想使用 VBA 中的 shell 命令在应用程序之间来回切换。 我正在使用 SendKeys 在进程 A 中执行操作,然后移动到进程 B,然后处理 A,然后处理 B。它对于第一次迭代运行良好。当我使用 AppActivate 返回进程 B 时,它实际上确实将焦点切换回进程 B。但是,它忽略了来自 SendKeys 的后续命令。

示例代码:

Sub pastePDF2TXT_v3(pdfName As String, txtName As String)


Dim acrobatID
Dim acrobatInvokeCmd As String
Dim acrobatLocation As String

Dim notepadID

Dim acrobatID2
Dim notepadID2

Debug.Print "here"


acrobatLocation = "C:\Program Files\Adobe\Acrobat 9.0\Acrobat\Acrobat.exe"

acrobatInvokeCmd = acrobatLocation & " " & pdfName

acrobatID = Shell(acrobatInvokeCmd, 1)
AppActivate acrobatID
SendKeys "^a", True  '^A selects everything already in the pdf file.
SendKeys "^c", True  '^C copies the selection to the clipboard.



notepadID = Shell("NOTEPAD.EXE " & txtName, 1)  ' invoke notepad on the text file.
AppActivate notepadID                           ' set the new app as teh active task.

SendKeys "^a", True  '^A selects everything already in the text file.
SendKeys "^v", True  '^V pastes the new stuff over the top of the old text file (deleting the old stuff)
SendKeys "%{END}", True ' makre sure last line of text file 
SendKeys "{ENTER}", True



AppActivate acrobatID  ' NOTE: APPEARS TO WORK UP TO THIS POINT.

SendKeys "{ENTER}", True  ' NOTE: SECOND APP IGNORES SUBSEQUENT COMMANDS FROM HERE DOWN.
SendKeys "^a", True  '^A selects everything already in the pdf file.
SendKeys "^c", True  '^C copies the selection to the clipboard.
SendKeys "%f", True  'alt f, x to exit Notepad.exe
SendKeys "x", True
'acrobatID.Quit


Debug.Print "start second"

AppActivate notepadID                           ' set the new app as teh active task.


SendKeys "%{END}", True 'Go to end of text file.
SendKeys "^v", True  '^V pastes the new stuff at end of file.
SendKeys "{ENTER}", True

SendKeys "^s", True   

SendKeys "%f", True   'alt f, x to exit Notepad.exe
SendKeys "x", True

notepadID.Quit
acrobatID.Quit

End Sub

I want to switch back and forth between application with the shell command in VBA.
I am using SendKeys to do stuff in process A then move to process B, then to process A then process B. It works fine for the first iteration. When I use AppActivate to go back to process B, it actually does switch focus back to process B. HOWEVER, it ignores subsequent commands from SendKeys.

Example code:

Sub pastePDF2TXT_v3(pdfName As String, txtName As String)


Dim acrobatID
Dim acrobatInvokeCmd As String
Dim acrobatLocation As String

Dim notepadID

Dim acrobatID2
Dim notepadID2

Debug.Print "here"


acrobatLocation = "C:\Program Files\Adobe\Acrobat 9.0\Acrobat\Acrobat.exe"

acrobatInvokeCmd = acrobatLocation & " " & pdfName

acrobatID = Shell(acrobatInvokeCmd, 1)
AppActivate acrobatID
SendKeys "^a", True  '^A selects everything already in the pdf file.
SendKeys "^c", True  '^C copies the selection to the clipboard.



notepadID = Shell("NOTEPAD.EXE " & txtName, 1)  ' invoke notepad on the text file.
AppActivate notepadID                           ' set the new app as teh active task.

SendKeys "^a", True  '^A selects everything already in the text file.
SendKeys "^v", True  '^V pastes the new stuff over the top of the old text file (deleting the old stuff)
SendKeys "%{END}", True ' makre sure last line of text file 
SendKeys "{ENTER}", True



AppActivate acrobatID  ' NOTE: APPEARS TO WORK UP TO THIS POINT.

SendKeys "{ENTER}", True  ' NOTE: SECOND APP IGNORES SUBSEQUENT COMMANDS FROM HERE DOWN.
SendKeys "^a", True  '^A selects everything already in the pdf file.
SendKeys "^c", True  '^C copies the selection to the clipboard.
SendKeys "%f", True  'alt f, x to exit Notepad.exe
SendKeys "x", True
'acrobatID.Quit


Debug.Print "start second"

AppActivate notepadID                           ' set the new app as teh active task.


SendKeys "%{END}", True 'Go to end of text file.
SendKeys "^v", True  '^V pastes the new stuff at end of file.
SendKeys "{ENTER}", True

SendKeys "^s", True   

SendKeys "%f", True   'alt f, x to exit Notepad.exe
SendKeys "x", True

notepadID.Quit
acrobatID.Quit

End Sub

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

何必那么矫情 2024-10-18 17:26:49

我知道这个问题很旧,但我也遇到过同样的问题,但我认为选择的答案不是正确的。

当您调用 AppActivate 时,脚本将停止,等待目标应用程序终止。应用程序终止后,脚本将继续运行。我认为这个问题没有解决办法。

编辑:

我使用批处理文件为 AppActivate 命令调用 CSCRIPT,并且我注意到您严格使用 VBS 文件。尝试将 CMD 作为新窗口调用,并传递 CSCRIPT //NoLogo //B WScript.CreateObject("WSCript.shell").AppActivate("Window Name") 作为论证,看看是否绕过了问题。

I know this question is old, but I have run into this same problem, but I don't think the answer that was chosen is the correct one.

When you call AppActivate, the script goes on halt, waiting for the target application to terminate. After the application is terminated, the script continues. I see no solution to this issue.

EDIT:

I use a batch-file to call CSCRIPT for the AppActivate command, and I notice you are strictly using a VBS file. Try calling CMD as a new window and pass CSCRIPT //NoLogo //B WScript.CreateObject("WSCript.shell").AppActivate("Window Name") as the argument, and see if that bypasses the issue.

草莓味的萝莉 2024-10-18 17:26:49

同样,我尝试对使用 shell 命令打开的 pdf 文档使用 AppActivate,以便我可以在其上使用 SendKeys。它总是会生成运行时错误“5”。我的解决方案最终是根本不使用 AppActivate,事实上打开文档无论如何都会将其带到最前面。问题是 SendKeys 语句在 shell 命令之后立即执行,但 pdf 需要一两秒钟才能打开。我的解决方案是在执行 sendkeys 语句之前暂停代码几秒钟。

我使用了延迟屈膝的方法。在这里查看线程:
http://www.dbforums.com/microsoft-access/1219379 -时间延迟-vba.html

Similarly, I was trying to use AppActivate on a pdf document I had opened with a shell command so that I could use SendKeys on it. It would always generate Run Time Error '5'. My solution, eventually was to NOT use AppActivate at all, in fact opening the document brings it to the forefront anyway. The problem is that the SendKeys statement executes immediately after the shell command but the pdf needs a second or two to open up. My solution is to pause the code for a couple seconds before excuting the sendkeys statement.

I used a time delay curtosy of pootle flump. Check out the thread here:
http://www.dbforums.com/microsoft-access/1219379-time-delay-vba.html

ペ泪落弦音 2024-10-18 17:26:49

经过在各个论坛上进行数小时的研究后,我发现我无法通过 Adob​​e Reader 使用 Adob​​e 库对象和函数。剩下的唯一可行的选择是使用 Shell 命令来使用 Adob​​e Reader 文件菜单中提供的“另存为文本”选项。快捷键为Alt+f+a+x+s。我在下面的代码中实现了这些,尽管我需要在某些步骤中插入延迟,但它运行得很好。

Sub SavePDFasText()
Dim AdobeReaderPath As String
Dim PdfFilePath As String
Dim PDFid, NotepdId As Double

AdobeReaderPath = "C:\Program Files\Adobe\Reader 10.0\Reader\AcroRd32.exe"
PdfFilePath = "D:\PowerGenMacro\opm_11.pdf"
PDFid = Shell(AdobeReaderPath & " " & PdfFilePath, vbNormalFocus)
Application.Wait TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + 5)
'Alt+f+a+x is required to save the pdf as text in the adobe reader
SendKeys "%(FAX)", True
Application.Wait TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + 2)
SendKeys "%S", True
SendKeys "^q", True

End Sub

After hours of research on various forums, I could figure out that I wont be able to use Adobe library objects and functions with Adobe Reader. The only viable option left was to use Shell Commands to use "save as text" option available in the Adobe Reader's file menu. The shortcut key is Alt+f+a+x+s. I implemented these in the below code which worked perfectly, although I was required to insert delays in some steps.

Sub SavePDFasText()
Dim AdobeReaderPath As String
Dim PdfFilePath As String
Dim PDFid, NotepdId As Double

AdobeReaderPath = "C:\Program Files\Adobe\Reader 10.0\Reader\AcroRd32.exe"
PdfFilePath = "D:\PowerGenMacro\opm_11.pdf"
PDFid = Shell(AdobeReaderPath & " " & PdfFilePath, vbNormalFocus)
Application.Wait TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + 5)
'Alt+f+a+x is required to save the pdf as text in the adobe reader
SendKeys "%(FAX)", True
Application.Wait TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + 2)
SendKeys "%S", True
SendKeys "^q", True

End Sub
帅冕 2024-10-18 17:26:49

这可能更像是一条评论,而不是一个答案,但我似乎不被允许“评论”,所以……

你能走到这一步真是令人惊讶。很有可能,你永远无法可靠地完成这项工作——就这样。一旦你让它工作起来,在未来的版本中,Acrobat UI 的行为方式就会发生一些变化,或者 Windows 将会对哪些东西可以向其他东西发送事件的规则进行另一次更改,然后你再次陷入困境。

在这种情况下,您可能遇到的情况是,当用户显然正忙于与第一个应用程序交互时,Windows 试图阻止某个应用程序从另一个应用程序中窃取焦点。在尝试执行诸如在一个应用程序中使用按钮将数据写入临时文件并打开 MS Word 进行编辑之类的操作时,您会看到相同类型的问题。 Windows 会阻止焦点从当前应用程序转移到 MS Word,因为您刚刚单击了当前应用程序中的按钮。

因此,我们不要试图解决这个不可能的技术问题,而是退后一步,问一下您最初希望通过执行所有这些操作来实现什么目标。通过这种方式,也许我们可以带您到达您想去的地方:)

This might be more of a comment than an answer, but I don't seem to be allowed to "comment", so...

It's amazing you've gotten as far as you did. Chances are, you're never going to be able to make this work reliably -- period. As soon as you do make it work, something will change about how the Acrobat UI behaves in a future release, or Windows will make another change to the rules for what things can send events to what other things, and then you're hosed again.

What you are probably running into in this case is Windows trying to prevent an application stealing the focus from another when a user is apparently busy interacting with the first one. You see the same kinds of problems trying to do things like have a button in one application write data to a temporary file and open MS Word to edit it. Windows prevents the focus from transferring away from the current app and over to MS Word because you just clicked a button in the current app.

So -- instead of trying to solve this impossible technical issue, let's take a step back and ask what you were originally hoping to accomplish by doing all of this. In that way, perhaps, we can get you where you're trying to go :)

甜宝宝 2024-10-18 17:26:49

尝试
发送键“%{tab}”
切换窗口
但只保留 2 个活动窗口。

或尝试
appactivate 仅在 sendkeys {Tab} 之后,以便在 switchibg windows cmd 之前不会选择文本输入框。

或尝试
尝试 appactivate 窗口名称,1
然后睡眠 2000°,以便有时间让该窗口成为焦点

Try
sendkeys "%{tab}"
to switch windows
but then keep only 2 active windows.

or try
appactivate only after sendkeys {Tab} so that text entry box is not selected before switchibg windows cmd.

or try
try appactivate window name, 1
then sleep 2000 °to allow time to bring that window into focus

-小熊_ 2024-10-18 17:26:49

您忘记在每个发送键之间添加“DoEvents”和某种延迟/等待时间,以给它一些执行时间。

You forgot to add "DoEvents" between each sendkeys and kind of delay/wait period, to give it some time to execute.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文