How to pass command-line arguments to a Windows application correctly?
在Linux中将命令行参数传递给应用程序恰好与exec *命令配合使用,在该命令中您可以清楚地自行传递每个参数。如果要控制标准管道,则在Windows上使用相同功能的方法不是一种选择。由于这些函数基于CreateProcess(),因此对于如何转义特殊字符(如双引号)有一些明确的规则。
遗憾的是,只有在被调用的应用程序通过main(),wmain()或CommandLineToArgvW()检索其命令行参数时,此方法才能正常工作。但是,如果被调用的应用程序通过WinMain(),wWinMain(),GetCommandLineA()或GetCommandLineW()获取这些参数,则由应用程序决定如何解析命令行参数,因为它将获取整个命令行而不是参数根据参数。
这意味着使用main()作为入口点的名为test的简单应用程序如果被称为test.exe "abc",则将获得" abc"。以cmd.exe /c"echo "abc""身份调用cmd.exe不会按预期方式输出" abc",而是" abc "。
这引起了我的问题:尽管有这些怪癖,如何以通用方式将命令行参数传递给Windows应用程序?
- 只要应用程序可以随意按自己喜欢的方式解析命令行,就定义而言,就没有通用的发送参数的方式。您有要解决的特定问题吗?您需要什么通用解决方案?
-
任何应用程序(包括具有main入口点的应用程序)都可以按自己喜欢的方式解析命令行。任何应用程序(包括具有WinMain入口点的应用程序)都可以使用__argv来获取使用通用规则解析的单个参数。而且,所有Windows应用程序的实际入口点都没有任何参数。命令行在启动时从PEB中提取为单个字符串。
-
链接到的规则参考是对Microsoft运行时库如何解析参数的描述。我认为CommandLineToArgvW有所不同。无论如何,您在API级别上没有这些规则。除了基本的双引号字符外,在Windows中没有通用的引号约定。当您将文件拖到可执行文件上时,通用的GUI外壳程序仅将它们引号(您可以尝试使用它来查看如何自己传递它们)。
-
我正在尝试编写一个例如在用户定义的shell中运行命令。因此,由用户决定在cmd.exe或sh.exe中执行回显" abc"(例如来自Cygwin或MSys的回显)。我正在读取已执行应用程序的输出以进行进一步处理。
-
您似乎使命令行解释器的解析与应用程序所做的混淆。好像您将解析器解释为应用程序一样。除非您提供有关您真正想要什么的简要说明,以及为什么它不表现出预期的行为,否则此问题将是题外话,并且有待解决。
-
这意味着我不能将参数abc\"xyz传递给任何应用程序,同时如果我不完全知道该应用程序的命令行解析器如何工作,以便我可以引用特殊字符,则保留所有给定的字符,就像那里给定的那样。
在Windows中,您需要考虑整个命令,而不是单个参数的列表。应用程序没有义务以任何特定的方式或者根本不将命令解析为参数;考虑echo命令的示例,该示例将命令行视为单个字符串。
这对于运行时库开发人员可能是个问题,因为这意味着没有可靠的方法来实现类似POSIX的exec函数。一些库开发人员采用直接的方法,并要求程序员在必要时提供引号,而另一些库则尝试自动对参数进行引用。在后一种情况下,必须为程序员提供某种方法来整体指定命令行,从而禁用任何自动引号,即使这意味着Windows特定的扩展。
但是,在您的情况下(如评论中所述)应该没有问题。所有您需要做的就是确保您询问用户一个命令,而不是一个参数列表。您的程序根本不需要知道如何将命令拆分为参数。理解命令的语法是用户的工作。 [注意:如果您认为不正确,则需要更清楚地说明您的情况。提供一个示例,说明用户可能输入的内容以及您认为应用程序需要如何处理它。]
PS:由于您提到了C库_exec函数,因此请注意,它们无法正常运行。参数是不会单独传递给孩子的,因为这是不可能的。在Microsoft C运行时中,如果我没记错的话,将参数简单地组合在一起成为单个字符串,并以单个空格作为定界符,因此("hello there")与("hello","there")是无法区分的。
PPS:请注意,调用cmd.exe来解析命令会引入附加的(并且要复杂得多)处理层。一般来说,考虑到这一点仍然是用户的工作,但是您可能要意识到这一点。 cmd.exe处理的转义字符是插入符号。
- 我很担心,但是我接受了这个答案,因为它证实了我的想法:没有通用的方式可以保留所有字符,并且仍然像Windows一样在Linux中逐个参数地传递给另一个应用程序,因为Windows在该方面的工作原理根本不同部分。我将留给用户提供正确的报价方案。我也只需要用户提供可执行文件的路径,因为如果我要支持cmd.exe和co,则无法为CreateProcess()自动检索该路径。
这是C语言,您需要在C代码中的双引号之前使用反斜杠。对于外壳处理,没有这样的规则。因此,如果您编写代码以调用CreateProcess并传递文字字符串"abc",则需要使用反斜杠,因为您是用C语言编写的。但是如果编写要传递的shell脚本,则应调用您的应用程序以传递"abc",例如例如Echo例子,那么您就不会使用反斜杠,因为其中不涉及C代码。