如何在Delphi中调用CreateProcess?

时间:2014-10-31 15:41:22

标签: delphi winapi delphi-xe6

根据CreateProcessthe example from MSDN的文档,我正在尝试致电CreateProcess

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
   );

呼叫因访问冲突而崩溃:

  

0003B77B模块kernel32.dll中的异常EAccessViolation   模块'kernel32.dll'中地址为7671B77B的访问冲突。写地址00B47EA6。

现在我理解为什么它会让我崩溃,但我不明白为什么it isn't crashing for the sample code on MSDN,我也不理解why it wasn't failing for you David

CreateProcess的文档说如果第一个参数是 null (就像我的示例,MSDN示例和另一个示例那样),那么CreateProcess修改 commandLine参数:

  

lpCommandLine [in,out,optional]

     

...

     

此函数的Unicode版本 CreateProcessW 可以修改此字符串的内容。因此,此参数不能是只读内存的指针(例如const变量或文字字符串)。如果此参数是常量字符串,则该函数可能会导致访问冲突。

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

enter image description here

所以CreateProcess正试图乱写我的unicode字符串的null终止符。如果CreateProcess尝试修改命令行而不是延长命令行,CreateProcess页评论中存在争议。

完全可能是我的字符串

  

C:\ Windows \ System32下\ cmd.exe的

位于只读数据部分。字符串本身的引用计数为-1

enter image description here

当常量字符串来自常量时会发生。

我可以通过将字符串复制到缓冲区来测试它:

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
);

这是成功的。

因此,在撰写我的问题并研究之后,我已经回答了我自己的问题。但我仍然想知道处理这个问题的正确方法是什么

  

如何在Delphi中调用CreateProcess?

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

奖金ShellExecute

他是你如何使用ShellExecute

var
   shi: TShellExecuteInfo;

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

ShellExecuteEx(@shi);

1 个答案:

答案 0 :(得分:3)

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

我认为他们已经在字符串强制转换中破坏了一些东西,因为我在Delphi XE中的旧代码没有这么严格的转换。