关于winapi:如何在Delphi中调用CreateProcess?

How to call CreateProcess in Delphi?

本问题已经有最佳答案,请猛点这里访问。

按照CreateProcess的文档以及MSDN的示例,我试图调用CreateProcess

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var
   commandLine: string;
   si: TStartupInfo;
   pi: TProcessInformation;
begin
   commandLine := 'C:\\Windows\\System32\\cmd.exe';

   si := Default(TStartupInfo);
   si.cb := sizeof(si);

   CreateProcess(
        PChar(nil),         //no module name (use command line)
        PChar(commandLine), //Command Line
        nil,                //Process handle not inheritable
        nil,                //Thread handle not inheritable
        False,              //Don't inherit handles
        0,                  //No creation flags
        nil,                //Use parent's environment block
        PChar(nil),         //Use parent's starting directory
        si,                 //Startup Info
        pi                  //Process Info
   );

呼叫因访问冲突而崩溃:

Exception EAccessViolation in module kernel32.dll at 0003B77B.
Access violation at address 7671B77B in module 'kernel32.dll'. Write of address 00B47EA6.

现在我明白了为什么它崩溃了,但是我不明白为什么它没有因为MSDN上的示例代码而崩溃,我也不明白为什么它没有为您失败David 。

CreateProcess的文档说,如果第一个参数为null(如我的示例,MSDN示例和另一个示例),则CreateProcess将修改commandLine参数:

lpCommandLine [in, out, optional]

...

The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.

当我看到访问冲突时,它正在尝试写地址0x00B47EA6

enter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var
    commandLine: string;
    si: TStartupInfo;
    pi: TProcessInformation;
    l: Integer;
    buffer: TByteDynArray;

commandLine := 'C:\\Windows\\System32\\cmd.exe';

//Copy to writable buffer (including null terminator)    
l := (Length(commandLine)+1)*sizeof(Char);
SetLength(buffer, l);
Move(commandLine[1], buffer[0], l);

si := Default(TStartupInfo);
si.cb := sizeof(si);

if not CreateProcess(
            PChar(nil),               //no module name (use command line)
//          PChar(commandLine), //Command Line
            @buffer[0],
            nil,                //Process handle not inheritable
            nil,                //Thread handle not inheritable
            False,              //Don't inherit handles
            0,                  //No creation flags
            nil,                //Use parent's environment block
            PChar(nil),         //Use parent's starting directory
            si,                 //Startup Info
            {var}pi             //Process Info
);

那成功地工作了。

因此,在写完我的问题并进行研究之后,我已经回答了我自己的问题。但是我仍然想知道解决这个问题的一种体面的方法是

How to call CreateProcess in Delphi?

其他人怎么称呼它?其他所有人是否都将字符串复制到字节缓冲区?

奖励ShellExecute

他是您使用ShellExecute的方式:

1
2
3
4
5
6
7
8
9
var
   shi: TShellExecuteInfo;

shi := Default(TShellExecuteInfo);
shi.cbSize := SizeOf(TShellExecuteInfo);
shi.lpFile := PChar(commandLine);
shi.nShow := SW_SHOWNORMAL;

ShellExecuteEx(@shi);


您可以将PChar(commandLine)替换为PChar(WideString(commandLine))。这在Delphi XE6中对我有用。

我想他们已经破坏了字符串强制转换,因为我在Delphi XE中的旧代码无需进行严格的转换即可工作。