CreateProcess - lpApplicationName与lpCommandLine的区别

4
我是一名有用的助手,可以为您翻译文本。
我一直在使用CreateProcess Win API,并且想知道使用lpApplicationName和lpCommandLine参数与仅使用lpCommandLine参数之间的区别。
例如:
CreateProcess(NULL, L"C:\Path\To\Notepad.exe", L"C:\Path\To\File\To\Load.txt"... etc
CreateProcess(NULL, NULL, L"C:\Path\To\Notepad.exe C:\Path\To\File\To\Load.txt"... etc

我假设第二个选项只使用 lpCommandLine 就像打开 cmd.exe 并运行那个确切的命令。但是第一行呢?它是否以不同的方式加载应用程序并指定命令行参数?
我查看了 MSDN 的 API 文档,但它似乎没有详细说明正在发生的事情,这些参数可以包含什么,这很好,但我只是困惑当有多种方法可供选择时我该怎么做。
请注意,我知道两个示例行可能无法工作,因为 lpCommandLine 需要 LPTSTR 而不是 LPCTSTR。这只是为了方便理解。
感谢您的帮助!
安迪

1
你为什么说MSDN没有详细解释正在发生的事情?它几乎不能再详细了。简而言之,lpApplicationName基本上只做你要求的事情,而不多做其他事情,而lpCommandLine则添加了很多解释和魔法(附加扩展名,搜索PATH等)。而且,正如John所说,通常最好的方法是同时使用两者。 - Damon
1
好的,也许有些细节我没有理解或者第一次错过了,但是对我来说仍然感觉有点模糊不清。 - Andy
3个回答

6
推荐的做法是同时使用这两个参数。如果你不指定lpApplicationName,Windows会解析lpCommandLine以找出应用程序名称。由于空格在文件名和目录名中是一个有效的字符,所以这可能会导致错误的应用程序被运行(例如,在Windows XP中,如果你有c:\program.exe,并且你在c:\program files下启动一个程序)。
在这两种情况下,你都应该在lpCommandLine中使用应用程序名称,因为它用于计算Argv[0]。

2
推荐的方法是仅使用命令行,并将 NULL 传递给 lpApplicationName 参数。如果应用程序名称包含空格,则需要将其加引号。仅在需要传递非标准命令行(不包含可执行映像路径名作为第一个参数的命令行)到正在创建的进程时才使用两个参数。 - IInspectable
2
@IInspectable,您的建议基于什么?请阅读MSDN页面中CreateProcess下的“安全注意事项”部分,其中描述了该问题...“为避免此问题,请勿将lpApplicationName设置为NULL。如果您确实将lpApplicationName设置为NULL...”。因此,Microsoft建议不要传递NULL,但如果您这样做,则使用引号。 - John
3
该建议基于逻辑推理。大多数应用程序期望将启动进程的可执行映像作为第一个参数(argv[0])。对于这些情况,传递 lpCommandLine 是足够的,并且可以防止生成重复、冗余的信息。同时传递 lpApplicationNamelpCommandLine 可以构造一个命令行,该命令行不包含可执行映像作为其第一个参数。应该在那些应用程序期望(非标准)命令行不将可执行映像作为其第一个参数的罕见情况下使用。 - IInspectable
2
如果您使用 lpApplicationName,那么系统将不会使用 PATH 环境变量来定位可执行文件,这可能不是您想要的。因此,我必须支持 @IInspectable 的建议,使用带有正确引号的路径的 lpCommandLine 作为首选选项。仅在已知要启动的确切可执行文件的绝对路径的情况下才应使用 lpApplicationName - Yakov Galka

3
我从不使用lpApplicationName,并且总是引用lpCommandLine的应用程序部分。在您的示例中,我会执行"C:\Path\To\Notepad.exe" "C:\Path\To\File\To\Load.txt"(引用传递给CreateProcess的所有路径是个好主意)。仅使用lpApplicationName可能会导致访问argv [0]的子进程出现问题,这就是为什么我远离它的原因。
<rant> 除了自己之外,在任何其他地方使用CreateProcess都可能存在问题,因为NT6+随时可以决定由于应用程序兼容性shims和/或安装程序检测,你正在执行的东西需要管理员权限,然后CreateProcess就会失败。除非需要使用调试或跳出作业标志,否则建议只调用ShellExecute [Ex]以保险起见...</rant>

你提到使用ShellExecute的最后一点很有趣,这是我们最初使用的方法,但是我们不得不转而使用CreateProcess,因为Adobe Reader需要指定当前用户的环境块(以便查找用户文档文件夹而不是系统配置文件夹),我认为你不能使用ShellExecute来实现这一点。如果我们使用ShellExecute并且Adobe Reader是默认处理程序,则它会加载,但由于被拒绝访问systemprofile文件夹而崩溃。有什么建议吗? :) - Andy
@Andy:这只是一次发泄,请不要认真对待。真正的问题在于执行随机字符串,例如来自注册表,而不知道它们指向什么。如果你不知道自己在执行什么,那么你可能会尝试启动安装程序。至于启动Adobe Reader,那就是一个明显的ShellExecute案例。不要猜测我使用什么作为PDF阅读器。我没有使用Adobe,部分原因是它有漏洞。 - MSalters

1

根据MSDN的说法, lpApplicationName是可选的,可以为NULL。在这种情况下,模块名称必须是lpCommandLine字符串中第一个以空格分隔的标记。

如果可执行模块是16位应用程序,则lpApplicationName应为NULL,并且由lpCommandLine指向的字符串应指定可执行模块及其参数。


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