简体   繁体   English

当IDE与启动器启动应用程序时,为什么命令行参数的数量会发生变化?

[英]Why the quantity of command-line arguments changes when the application is started by the IDE vs an launcher?

Considering the following command-line arguments 考虑以下命令行参数

"alfa" "beta" "4"

When I specify the Run>Parameters... for an project I'm working the application shows on Process Explorer as command-line: 当我为我正在工作的项目指定Run> Parameters ...时,应用程序在Process Explorer上显示为命令行:

"c:\myapp\myapp.exe" "alfa" "beta" "4"

And ParamCount shows 4 parameters. ParamCount显示4个参数。 But when I start the same executable from an launcher application (which does access control), Process Explorer shows: 但是当我从启动器应用程序(执行访问控制)启动相同的可执行文件时,Process Explorer显示:

"alfa" "beta" "4"

ParamCount show 3 paramers. ParamCount显示3个参数。 The command-line was extracted from the launcher application. 命令行是从启动器应用程序中提取的。 In theory it would work, since when started from launcher the application work flawlessly. 理论上它可以工作,因为从启动器启动应用程序工作完美无缺。 When started from IDE it tries to do StrToInt on the "4" above, but retrieves just the "beta" parameter instead. 从IDE启动时,它会尝试在上面的"4"上执行StrToInt,但只检索"beta"参数。

Sample code from launcher application: 来自启动器应用程序的示例代码:

var
  StartupInfo: TSTARTUPINFO;
  ProcessInfo: PROCESS_INFORMATION;
  CurrentDirPath: String;
begin
  Result := 0;
  ZeroMemory(@StartupInfo, SizeOf(StartupInfo));
  StartupInfo.cb := SizeOf(StartupInfo);
  DirCorrente := ExtractFilePath(sExe);

  if CreateProcess(PChar(sExe), PChar(sParam), nil, nil, true,
    NORMAL_PRIORITY_CLASS, nil, PChar(CurrentDirPath),
    StartupInfo, ProcessInfo) then

The content of sParam is the command-line arguments above and sExe is the executable path. sParam的内容是上面的命令行参数,sExe是可执行路径。 Why this happens? 为什么会这样?

NOTE :I already devised how to change the command-line arguments interpretation to be robust for this edge case - the point here is WHY this happens. 注意 :我已经设计了如何将命令行参数解释更改为此边缘情况的健壮 - 这里的重点是为什么会发生这种情况。

Your launcher program isn't calling CreateProcess properly. 您的启动程序未正确调用CreateProcess Consider this excerpt from the documentation (emphasis added): 请考虑文档中的摘录(强调添加):

If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. 如果lpApplicationName和lpCommandLine都是非NULL,则lpApplicationName指向的以null结尾的字符串指定要执行的模块,lpCommandLine指向的以null结尾的字符串指定命令行。 The new process can use GetCommandLine to retrieve the entire command line. 新进程可以使用GetCommandLine来检索整个命令行。 Console processes written in C can use the argc and argv arguments to parse the command line. 用C编写的控制台进程可以使用argc和argv参数来解析命令行。 Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line. 因为argv [0]是模块名称,所以C程序员通常会重复模块名称作为命令行中的第一个标记。

Ignore the bit about "C programmers"; 忽略“C程序员”; it applies to everyone writing programs for Windows, regardless of the language. 它适用于为Windows编写程序的每个人,无论语言如何。

Your launcher is providing values for both the lpApplicationName and lpCommandLine parameters, but it is not following the convention of repeating the program file name as the first parameter in the command line. 您的启动程序为lpApplicationName和lpCommandLine参数提供了值,但它没有遵循重复程序文件名作为命令行中第一个参数的约定。 Delphi's ParamStr and ParamCount functions know to follow the convention, so they skip the first token on the command line. Delphi的ParamStrParamCount函数知道遵循约定,因此它们跳过命令行上的第一个标记。 If the caller didn't follow the convention, then the receiver ends up thinking the intended second parameter is really the first, the third is really the second, and so on. 如果调用者没有遵循惯例,那么接收者最终认为预期的第二个参数实际上是第一个,第三个实际上是第二个,依此类推。

The second parameter is passed as-is as the command-line to the launched process. 第二个参数按原样作为命令行传递给已启动的进程。 Most RTLs (including Delphi's) expect the first delimited value in the command-line to be the EXE path. 大多数RTL(包括Delphi)期望命令行中的第一个分隔值为EXE路径。 This is stated in the CreateProcess() documentation: 这在CreateProcess()文档中说明:

If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. 如果两个lpApplicationNamelpCommandLine是非NULL,则空终止字符串指向lpApplicationName指定执行的模块和空终止字符串指向lpCommandLine指定命令行。 The new process can use GetCommandLine to retrieve the entire command line. 新进程可以使用GetCommandLine来检索整个命令行。 Console processes written in C can use the argc and argv arguments to parse the command line. 用C编写的控制台进程可以使用argc和argv参数来解析命令行。 Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line. 因为argv [0]是模块名称,所以C程序员通常会重复模块名称作为命令行中的第一个标记。

The OS handles that automatically when a user launches an executable, but an application has to manage it manually when launching a process via code. 当用户启动可执行文件时,操作系统会自动处理,但是当通过代码启动进程时,应用程序必须手动管理它。

The launcher is not including the EXE path as the first delimited value of the command-line that it passes to CreateProcess() . 启动程序不包括EXE路径作为它传递给CreateProcess()的命令行的第一个分隔值。 It needs to do so: 它需要这样做:

var
  StartupInfo: TSTARTUPINFO;
  ProcessInfo: PROCESS_INFORMATION;
  ...
  CmdLine: String;
begin
  Result := 0;
  ZeroMemory(@StartupInfo, SizeOf(StartupInfo));
  StartupInfo.cb := SizeOf(StartupInfo);
  ...
  CmdLine := TrimRight(AnsiQuotedStr(sExe, '"') + ' ' + sParam);
  ...    
  if CreateProcess(PChar(sExe), PChar(CmdLine), ...) then

In which case, it can omit the first parameter value altogether, per the CreateProcess() documentation: 在这种情况下,根据CreateProcess()文档,它可以完全省略第一个参数值:

The lpApplicationName parameter can be NULL. lpApplicationName参数可以为NULL。 In that case, the module name must be the first white space–delimited token in the lpCommandLine string . 在这种情况下, 模块名称必须是lpCommandLine字符串中第一个以空格分隔的标记

var
  StartupInfo: TSTARTUPINFO;
  ProcessInfo: PROCESS_INFORMATION;
  ...
  CmdLine: String;
begin
  Result := 0;
  ZeroMemory(@StartupInfo, SizeOf(StartupInfo));
  StartupInfo.cb := SizeOf(StartupInfo);
  ...
  CmdLine := TrimRight(AnsiQuotedStr(sExe, '"') + ' ' + sParam);
  ...    
  if CreateProcess(nil, PChar(CmdLine), ...) then

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Delphi 5 IDE命令行返回码 - Delphi 5 IDE command-line return codes 替换了Explorer.exe后如何将命令行参数传递给我的应用程序 - How to pass command-line args to my application when it has replaced Explorer.exe Delphi命令行编译器 - Delphi command-line compiler 为什么Delphi 2009 IDE生成的可执行文件与命令行生成的可执行文件不同? - Why is the executable produced by Delphi 2009 IDE different to that produced on the command line? 为什么Delphi Command Line给我不同的IDE输出? - Why is Delphi Command Line giving me a different output to the IDE? 从Windows XP的Delphi应用程序中的命令行程序获取输出 - Getting output from a command-line program in a Delphi application on Windows XP 如何获取应用程序中某些按钮单击的命令行参数? - How do I get the command-line parameters for certain button clicks in a application? 通过 ShellExecute() 执行命令行应用程序并获取其返回值 - Execute a command-line Application via ShellExecute() and get its return value 传递给Delphi控制台应用程序的命令行参数的最大长度 - Maximum length of command line arguments passed to Delphi console application 命令行shell中的参数 - Arguments in command line shell
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM