在Windows中使用AppID启动应用程序并获取pid

3

我正在尝试使用应用程序ID启动Windows应用程序,例如Microsoft.WindowsCalculator_8wekyb3d8bbwe!App,我通过调用Get-StartApps来获取该ID。

目前,我可以启动应用程序,但无法获得正确的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?


1
你可以调用 COM API,但即使如此,它也不会提供PID,除非你在Job中捕获它,但即便如此,UWP主机和其他WinRT垃圾可能会妨碍... - Anders
1
JOB_OBJECT_MSG_NEW_PROCESS - Anders
请查看我的更新,现在应该是健壮的。事实证明,计算器每个用户会话仅创建一个进程,因此识别相关进程变得简单且可靠。请注意,如果您想标识新创建的窗口,则需要更多工作。 - mklement0
谢谢,@TaylorRamirez。关于 CalculatorApp 的问题:这很奇怪,因为在我的 Windows 10 机器上它肯定是 Calculator - 你是在 Windows 11 上吗?启动计算器后,(Get-Process *calc*).Name 对你返回的是 CalculatorApp 吗?总的来说,通过进程名称搜索并不理想,但在这种情况下它是最好的解决方案。 - mklement0
1
@mklement0 嗯,这个测试机是 Windows 11。你认为微软会修复这个问题吗? - zeitue
显示剩余3条评论
1个回答

3

简而言之

// 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)

  • 原则上,你可以在 PowerShell 的 Start-Process (start) 命令中传递 -PassThru 参数,它会返回一个包含启动进程 PID 的进程信息对象,并输出该 PID。

  • 不幸的是,对于 UWP / AppX 应用程序,例如计算器,这种方法并不起作用,这是底层 .NET API 中存在的问题,至少在 .NET 6.0 中存在 - 参见 GitHub issue #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,但是,这个 PID 是正确的,因为 Start-Process 启动的 临时 进程只是将创建新的计算器窗口委托给现有进程。

    • 如果你想要识别新创建的 窗口,则需要更多的工作:你需要枚举进程的窗口并找到 z-order 最高的那个。

PowerShell 代码(注意:在 Windows 11 中,请将 Calculator 替换为 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

注意,我使用了URL方案calculator:作为启动计算器的更简单方法。

注意:

  • Where-Object SessionId -eq (Get-Process -ID $PID).SessionId用于防止错误地将其他用户在其自己的会话中创建的潜在Calculator进程考虑在内(Get-Process返回在本地机器上运行的所有进程,跨所有用户会话)。通过.SessionID过滤,即按照活动用户会话(窗口工作站)进行过滤,可以避免此问题。

作为PowerShellCLI调用:

powershell.exe -NoProfile -Command "Start-Process -ErrorAction Stop calculator: ; (Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接