如何在Delphi中调用CreateProcess?
根据和的文档,我正在尝试呼叫: 呼叫因访问冲突而崩溃: 0003B77B模块kernel32.dll中的异常EAccessViolation。如何在Delphi中调用CreateProcess?,delphi,winapi,delphi-xe6,Delphi,Winapi,Delphi Xe6,根据和的文档,我正在尝试呼叫: 呼叫因访问冲突而崩溃: 0003B77B模块kernel32.dll中的异常EAccessViolation。 模块“kernel32.dll”中地址7671B77B处的访问冲突。写入地址00B47EA6 现在我明白了为什么它会让我崩溃,但我不明白为什么,我也不明白 CreateProcess的文档说明,如果第一个参数是null(在我的示例、MSDN示例和其他示例中都是如此),则CreateProcess将修改命令行参数: lpCommandLine[输入、输出、
模块“kernel32.dll”中地址7671B77B处的访问冲突。写入地址00B47EA6 现在我明白了为什么它会让我崩溃,但我不明白为什么,我也不明白
CreateProcess
的文档说明,如果第一个参数是null(在我的示例、MSDN示例和其他示例中都是如此),则CreateProcess
将修改命令行
参数:
lpCommandLine[输入、输出、可选]
此函数的Unicode版本,CreateProcessW,可以修改此字符串的内容。因此,此参数不能是指向只读内存(例如常量变量或文字字符串)的指针。如果此参数是常量字符串,则函数可能会导致访问冲突
当我查看访问冲突时,它试图写入地址0x00B47EA6
:
所以,CreateProcess
试图在我的unicode字符串的空终止符上涂鸦。如果CreateProcess
试图修改命令行而不是使其变长,则在CreateProcess
页面注释中存在一些争议
完全有可能我的绳子
C:\Windows\System32\cmd.exe
位于只读数据节中。字符串本身的引用计数为-1
:
当常量字符串来自常量时会发生这种情况
我可以通过将字符串复制到缓冲区来测试这一点:
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);
您可以将PChar(命令行)替换为PChar(宽字符串(命令行))。这在Delphi XE6中对我有效
我想他们破坏了字符串类型转换中的某些内容,因为我在Delphi XE中的旧代码在没有严格转换的情况下工作。另请参见完整示例使用单独的缓冲区正是MSDN代码和David的代码所做的。在C和C++中,<>代码> ARGV 是可写字符数组指针的可写数组。在Delphi中,动态构造的字符串是可写的。不过,您不需要字节缓冲区;在我看来,调用UniqueString是确保字符串缓冲区可写的惯用方法,而不需要WideString。我们可以用UniqueString创建一个可写的UniqueString。
var
shi: TShellExecuteInfo;
shi := Default(TShellExecuteInfo);
shi.cbSize := SizeOf(TShellExecuteInfo);
shi.lpFile := PChar(commandLine);
shi.nShow := SW_SHOWNORMAL;
ShellExecuteEx(@shi);