AppActivate working inconsistently in Powershell

2020-08-01 15:50发布

I have the following two line code which will bring the respective window to the front that will help me take screenshots automatically. But the problem is that, sometimes, it works like a charm and sometimes it doesn't. And when I say it doesn't work, I don't mean that it is failing with any error message or warnings. Nothing happens. Just the code runs and the windows doesn't come to the front.

I would like to know if there is any hidden prerequisites for this snippet to run successfully? Should the window in question should be in any state before I run this code to bring that window upfront?

Here is the code:

[void][System.Reflection.Assembly]::LoadWithPartialName("'Microsoft.VisualBasic")
[Microsoft.VisualBasic.Interaction]::AppActivate("R")

标签: powershell
5条回答
\"骚年 ilove
2楼-- · 2020-08-01 16:30

I've had trouble using the Title-overload before. Also, a single change in the windows title will break AppActivate(string Title).

Does it work better with the ProcessID-overload? Ex.

$excelpid = (Get-Process excel).ID
[Microsoft.VisualBasic.Interaction]::AppActivate($excelpid)

If you're using a COM-application, you need to get the process based on the MainWindowHandle, like this:

[void][System.Reflection.Assembly]::LoadWithPartialName("'Microsoft.VisualBasic")

#start excel
$excel = New-Object -ComObject excel.application

#make excel visible
$excel.Visible = $true

#get pid from windows handle
$excelpid = (Get-Process | Where-Object { $_.MainWindowHandle -eq $excel.Hwnd }).Id

#Activate window
[Microsoft.VisualBasic.Interaction]::AppActivate($excelpid)
查看更多
贼婆χ
3楼-- · 2020-08-01 16:36

Possibilities are that the program takes the control back as soon as powershell switches control to the desired program... Try to loop the activate until you take the screenshot...

查看更多
聊天终结者
4楼-- · 2020-08-01 16:48

Using AppActivate to bring out window title sometimes behaves indeed quite weird: no exception occurs and checking foreground window handle(using Win32 API: GetForegroundWindow) is accurate either, except that the window is still not showing anyway. To make sure the window does show before everything is completed, here is an alternative to using AppActivate. I tried using win32 API: "ShowWindowAsync" and "SetForegroundWindow" together, and check the return value to make sure. It works much more consistently than AppActivate.

(P.S. ShowWindowAsync: "Sets the show state of a window without waiting for the operation to complete.", according to Microsoft online docs). Code example: Assuming that the window title "R" already exists.

Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class SFW {
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetForegroundWindow(IntPtr hWnd);
     [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
    }
"@
$Target_Title="R"
$hwnd =(Get-Process | Where-Object { $_.MainWindowTitle -eq $Target_Title } ).MainWindowHandle
Do
{
try
{
$r1=[SFW]::ShowWindowAsync($hwnd, 3)
$r2=[SFW]::SetForegroundWindow($hwnd) 
}
catch
{
    Write-Host "Error activating! Press any key to exit!"
    cmd /c pause | out-null
    exit
    }
    }while(($r1 -or $r2) -eq $false)
查看更多
该账号已被封号
5楼-- · 2020-08-01 16:53

$IEtitles=get-process iexplore |?{$_.MainWindowTitle}|select -exp MainWindowTitle

foreach($IEtitle in $IEtitles) {

    Add-Type -AssemblyName Microsoft.VisualBasic
    [Microsoft.VisualBasic.Interaction]::AppActivate("$IEtitle") | Out-Null

}

查看更多
我想做一个坏孩纸
6楼-- · 2020-08-01 16:56

I simply iterate AppActivate several times.I know this is not beautiful solution. But it works for me.

sample code here.

for ($i = 1; $i -lt 5; $i++)
{
    [Microsoft.VisualBasic.Interaction]::AppActivate("R")
}
查看更多
登录 后发表回答