英文:
Launch Applications in WIndows using AppID and get the pid
问题
我正在尝试使用应用程序的AppID(例如Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
)来启动Windows应用程序,我通过调用Get-StartApps
来获取AppID。
目前我可以启动应用程序,但无法获取正确的PID。
cmd = exec.Command("powershell", "start", `shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App`)
err := cmd.Start()
fmt.Println(cmd.Process.Pid)
这将返回powershell的PID。
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe start shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
有没有办法通过AppID启动应用程序并仍然获取正确的PID?
英文:
I'm trying to launch Windows applications using their AppID such as Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
which I get by calling Get-StartApps
Currently I can launch the applications but can't get the correct PID
cmd = exec.Command("powershell", "start", `shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App`)
err := cmd.Start()
fmt.Println(cmd.Process.Pid)
This returns the PID of powershell
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe start shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
Is there a way to launch the application by the AppID and still get the correct PID?
答案1
得分: 3
tl;dr
// 让 PowerShell 不仅启动计算器,还要确定并输出其 PID,如下一节所述。
out, _ :=
exec.Command(
`powershell.exe`,
`-NoProfile`,
`-Command`,
`Start-Process -ErrorAction Stop calculator: ; (Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID`,
).Output()
// 将包含 PID 的 stdout 输出解析为整数
var pid int
fmt.Sscanf(string(out), "%d\n", &pid)
-
原则上,你可以在 PowerShell 的
Start-Process
(start
) 命令中传递-PassThru
,它会返回一个包含启动进程 PID 的进程信息对象,并将其输出。 -
然而,对于特定的 UWP / AppX 应用程序,比如计算器,这种方法不起作用,这是底层 .NET API 的一个问题,至少在 .NET 6.0 之前如此 - 参见 GitHub 问题 #10996。
你可以尝试以下 解决方法:
-
使用
Start-Process
启动 AppX 应用程序,这将间接创建一个名为Calculator
(Windows 10)/CalculatorApp
(Windows 11)的进程。- 如果你启动计算器后运行
(Get-Process *calc*).Name
,你可以自己确定这个名称。Get-Process *calc* | Select-Object Name, Path
还会显示可执行文件路径,但请注意,这个可执行文件应该被视为实现细节,不能直接调用。
- 如果你启动计算器后运行
-
返回该
Calculator
/CalculatorApp
进程的 ID。计算器在给定的用户会话中只会创建一个这样的进程,这使得识别该进程变得容易。-
请注意,这意味着可能会返回一个 已存在的 计算器进程的 PID,然而,这是正确的,因为
Start-Process
启动的 临时 进程只是将创建新的计算器窗口的任务委托给现有进程。 -
如果你想要识别新创建的 窗口,则需要更多的工作:你需要枚举进程的窗口,并识别最高 z-order 的窗口。
-
PowerShell 代码(注意:在 Windows 11 中,将 Calculator
替换为 CalculatorApp
):
# 启动计算器 - 它可能会重用现有实例并仅创建一个新的 *窗口* - 并报告 PID。
Start-Process -ErrorAction Stop calculator:
(Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID
<sup>请注意,我使用了 URL 方案 calculator:
作为启动计算器的简单方法。</sup>
注意:
Where-Object SessionId -eq (Get-Process -ID $PID).SessionId
防止错误地将由_其他用户_在_他们自己的会话_中创建的潜在Calculator
进程考虑在内(Get-Process
返回在本地机器上运行的_所有_进程,跨越所有用户会话)。通过.SessionID
进行过滤,即通过活动用户会话(窗口站),可以解决这个问题。
作为 PowerShell CLI 调用:
powershell.exe -NoProfile -Command "Start-Process -ErrorAction Stop calculator: ; (Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID"
英文:
tl;dr
// Make PowerShell not only launch Calculator, but also
// determine and output its PID, as described in the next section.
out, _ :=
exec.Command(
`powershell.exe`,
`-NoProfile`,
`-Command`,
`Start-Process -ErrorAction Stop calculator: ; (Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID`,
).Output()
// Parse stdout output, which contains the PID, into an int
var pid int
fmt.Sscanf(string(out), "%d\n", &pid)
-
In principle, you can pass
-PassThru
to PowerShell'sStart-Process
(start
) cmd, which returns a process-info object that has an.Id
property containing the launched process' PID, and output the latter. -
Unfortunately, with UWP / AppX applications specifically, such as Calculator, this does not work, which is a problem that exists in the underlying .NET APIs, up to at least .NET 6.0 - see GitHub issue #10996.
You can try the following workaround:
-
Launch the AppX application with
Start-Process
, which indirectly creates a process whose name isCalculator
(Windows 10) /CalculatorApp
(Windows 11).- You can identify this name yourself if you run
(Get-Process *calc*).Name
after launching Calculator.Get-Process *calc* | Select-Object Name, Path
would show the executable path too, but note that this executable should be considered an implementation detail and can not be invoked directly.
- You can identify this name yourself if you run
-
Return the ID of that
Calculator
/CalculatorApp
process. The fact that Calculator only ever creates one such process in a given user session actually makes identifying that process easy.-
Note that this means that the PID of a preexisting Calculator process may be returned, which, however, is the correct one, because the transient process launched by
Start-Process
simply delegates creation of a new Calculator window to an existing process. -
If you wanted to identify the newly created window, more work would be required: You'd have to enumerate the process' windows and identify the one with the highest z-order.
-
PowerShell code (note: in Windows 11, replace Calculator
with CalculatorApp
):
# Launch Calculator - which may reuse an existing instance and
# merely create a new *window* - and report the PID.
Start-Process -ErrorAction Stop calculator:
(Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID
<sup>Note that I've used the URL scheme calculator:
as a simpler way to launch Calculator.</sup>
Note:
- The
Where-Object SessionId -eq (Get-Process -ID $PID).SessionId
guards against mistakenly considering potentialCalculator
processes created by other users in their own sessions (Get-Process
returns all processes running on the local machine, across all user sessions). Filtering by.SessionID
, i.e. by the active user session (window station), prevents this problem.
As a PowerShell CLI call:
powershell.exe -NoProfile -Command "Start-Process -ErrorAction Stop calculator: ; (Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论