【问题标题】:Is there an API which exposes the paths searched by the start command?是否有公开 start 命令搜索的路径的 API?
【发布时间】:2019-08-14 16:41:31
【问题描述】:

start 搜索了哪些路径?此路径列表是否可通过 WMI、注册表、WSH shell 文件夹常量、.NET 方法或任何其他 Windows API 查询?

cmd 控制台中,start 命令有点神奇。假设您的默认网络浏览器是 Firefox。您还安装了 Chrome 和 Opera,但它们既没有设置为默认值,也没有与任何文件类型关联,也没有在您的 %PATH% 中。考虑以下示例:

start "" opera https://stackoverflow.com

...为什么会这样?

这很重要的原因是,尽管start 命令的所有优势,当应用程序以start 启动时检索应用程序的PID 或窗口句柄仍然是危险的。在cmd 环境中,我更愿意在for /F 循环中使用wmic process call create 来捕获PID。那么有没有一种方法可以让wmic process call create 在不完全限定drive:\\path\\to\\executable 的情况下像start 那样启动“opera”或“iexplore”或“outlook”或“winword”或其他应用程序?

我认为我正在通过递归扫描 HKLM\Software\Clients 以查找 shell\open\command,然后将每个引用的位置临时添加到 %PATH% 中找到解决方案:

rem // temp add installed clients to %PATH% to make "call :display" behave like "start"
setlocal enabledelayedexpansion
for %%a in (HKLM HKCU) do for /f "tokens=2*" %%I in (
    'REG QUERY %%a\Software\Clients /s /f command /k /ve ^| find "(Default)"'
) do if "%%~I"=="REG_EXPAND_SZ" (
    if /i "%%~xJ"==".exe" (
        if "!PATH:%%~J\..=!"=="!PATH!" path !PATH!;%%~J\..
    ) else for %%# in (%%J) do if /i "%%~x#"==".exe" (
        if "!PATH:%%~#\..=!"=="!PATH!" path !PATH!;%%~#\..
    )
) else (
    if /i "%%~xJ"==".exe" (
        if "!PATH:%%~dpJ=!"=="!PATH!" path !PATH!;%%~dpJ
    ) else (
        for %%# in (%%J) do if /i "%%~x#"==".exe" (
            if "!PATH:%%~dp#=!"=="!PATH!" path !PATH!;%%~dp#
        )
    )
)
endlocal & path %PATH%

这工作得相当好,但它仍然达不到 start 可以访问的内容。例如:

start "" wordpad

有效,而

wmic process call create "wordpad.exe"

失败。

【问题讨论】:

  • 如果我没记错的话,启动命令将搜索这个注册表路径。 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
  • 同时输入pathpath /?dpath /?(最后一个用于使Dos 1程序与Dos 2操作系统一起工作)。
  • 如果您发现可执行文件的多个位置,您的计划是什么?
  • @lit 我正在编写的提示这个问题的脚本已经使用 PowerShell 混合代码来实现 P/Invoke 函数。我接受了 Noodles 的建议并使用ShellExecute(通过Start-Process cmdlet)作为start 的替代品。我猜它按当前工作目录的顺序排列,然后是 %path%,然后是 App Paths。基本上,我并没有有意识地计划,只是把它留给机会,并相信用户如果不喜欢它会从一个短码头走很长一段路。

标签: batch-file winapi cmd


【解决方案1】:

编辑2

这可能与您正在做的事情有关(而不是为什么某事会以它的方式工作)。

上一个回答

Can I create shorthand names for use inside cmd?

Doskey /?

你可以这样做doskey cddesk=cd "%userprofile%\desktop"

然后输入cddesk

通过将所有宏放入批处理文件中,您可以自动加载。当然 你也可以用批处理文件来做到这一点。

从技术参考到 Windows 2000 注册表,Microsoft, 2000.

AutoRun HKCU\Software\Microsoft\Command Processor

数据类型范围默认值

REG_SZ 命令列表 此条目没有默认值。

说明

包含每次启动 Cmd.exe 时执行的命令。

另请参阅此批处理文件https://pastebin.com/A2qLw8r3 该列表 特殊名称。

在命令提示符start shell:desktop

或者在开始 - 运行 (Winkey + R) 中只需 shell:desktop

编辑

我将在这里添加一些警告。

这是关于使用Start 命令打开可执行文件。大量规则适用于非可执行文件。

不使用Start CMD 预处理命令行并将 FQFN 发送到CreateProcess - 因此搜索路径不是CreateProcess 的 CMD。


https://docs.microsoft.com/en-us/windows/desktop/shell/launch 是 ShellExecute 的文档。一切最终都会调用 CreateProcess https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessw。 Plus CMD 预处理在https://books.google.com.au/books/about/Windows_NT_Shell_Scripting.html?id=jrdQAAAAMAAJ&redir_esc=y 有详细说明。 start /? 还提供了所有三种启动文件的方法的文档。总结在这里Command to run a .bat file

一些有趣的事实。如果 CMD 无法识别文件扩展名,它将尝试执行它。 ShellExecute 将内容嗅探未知文件https://docs.microsoft.com/en-us/windows/desktop/com/filetype-key

来自 rojo 的引用:感谢链接转储。我很难理解ShellExecute 如何让我不必完全限定路径名。这是我的主要问题。“要使用 ShellExecute 或 ShellExecuteEx,您的应用程序必须指定要操作的文件或文件夹对象,以及指定操作的动词。” 我要问的是“指定文件或文件夹对象”部分。

它使用 CreateProcess 下的 6 个步骤,如果没有结果,它使用 App Paths。如果未指定动词,则使用默认动词(通常是 Open)。在这里查看我的答案How do i automate the simulation of right clicking a file and selecting the first option using vbscript

所以它是 4 种技术的交集。与 MSDos 的兼容性、IBM 对 OS/2 所做的更改以及 Microsoft 对 Windows 2000 的更新、标准 Windows 启动程序 CreateProcess 的方式,以及在 Windows 95 中我们获得了基于 OLE 的 shell 函数

来自 rojo 的报价:快!你说得对!在 PowerShell 中,我能够创建一个 System.Diagnostics.Process 对象,设置 $ps.StartInfo.UseShellExecute = $true,然后在没有任何文件扩展名或完全限定路径的情况下启动“写字板”。将.UseShellExecute property 设置为$false 会导致执行失败。多么有趣!

【讨论】:

    【解决方案2】:

    我记得在 DosTips.com 或 SO 上关于这个主题的讨论,但我找不到它。希望有人这样做,我们可以将此问题标记为重复。

    我们知道批处理文件将搜索当前目录,然后搜索路径变量以查找可执行文件。 START 命令还搜索以下注册表路径

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
    

    所以你有几个选项可以找到可执行文件。

    您可以使用WHERE 命令搜索当前目录和PATH 变量中的目录。

    where notepad.exe
    

    您也可以使用FOR 命令搜索路径变量。

    for %%I in (notepad.exe) do echo %%~$PATH:I
    

    当然,您可以通过执行 REG QUERY 来搜索我上面提到的注册表路径。

    【讨论】:

    • 如果已经在 SO 上询问过,您和我都找不到它。最好不要将此帖子标记为重复。也许我的问题措辞对搜索会更友好一些?在任何情况下,reg query "%apppaths%" /s /f "%exe%" /k /ve | find "(Default)" 似乎与start 在我所做的有限测试中的行为相匹配,并且还让我将问题中的 20 行代码 sn-p 减少到只有 3 行。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-09
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多