根据CreateProcess
和the 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
:
所以CreateProcess
正试图乱写我的unicode字符串的null终止符。如果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);
答案 0 :(得分:3)
您可以用PChar(WideString(commandLine))替换PChar(commandLine)。这在Delphi XE6中对我有用。
我认为他们已经在字符串强制转换中破坏了一些东西,因为我在Delphi XE中的旧代码没有这么严格的转换。