【发布时间】:2015-09-26 22:31:09
【问题描述】:
我想运行用户在 INI 文件中定义的命令。
命令可以是EXE文件,也可以是其他文件(如DOC文件)和参数。
由于 WinExec() 可以处理参数(例如“cmd /?”),但 ShellExec() 可以处理非 EXE 文件(例如“Letter.doc”),因此我将两者结合使用。
我担心未来的 Windows 版本,因为 WinExec() 已被弃用,甚至从 16 位时代开始。
这是我目前的功能:
procedure RunCMD(cmdLine: string; WindowMode: integer);
procedure ShowWindowsErrorMessage(r: integer);
begin
MessageDlg(SysErrorMessage(r), mtError, [mbOK], 0);
end;
var
r, g: Cardinal;
begin
// We need a function which does following:
// 1. Replace the Environment strings, e.g. %SystemRoot% --> ExpandEnvStr
// 2. Runs EXE files with parameters (e.g. "cmd.exe /?") --> WinExec
// 3. Runs EXE files without path (e.g. "calc.exe") --> WinExec
// 4. Runs EXE files without extension (e.g. "calc") --> WinExec
// 5. Runs non-EXE files (e.g. "Letter.doc") --> ShellExecute
// 6. Commands with white spaces (e.g. "C:\Program Files\xyz.exe") must be enclosed in quotes.
cmdLine := ExpandEnvStr(cmdLine);
// TODO: Attention: WinExec() is deprecated, but there is no acceptable replacement
g := WinExec(PChar(cmdLine), WindowMode);
r := GetLastError;
if g = ERROR_BAD_FORMAT then
begin
// e.g. if the user tries to open a non-EXE file
ShellExecute(0, nil, PChar(cmdLine), '', '', WindowMode);
r := GetLastError;
end;
if r <> 0 then ShowWindowsErrorMessage(r);
end;
function ExpandEnvStr(const szInput: string): string;
// http://stackoverflow.com/a/2833147/3544341
const
MAXSIZE = 32768;
begin
SetLength(Result, MAXSIZE);
SetLength(Result, ExpandEnvironmentStrings(pchar(szInput),
@Result[1],length(Result)));
end;
Microsoft 建议使用 CreateProcess(),但我不接受它作为 WinExec() 的真正替代品。
例如,给定以下命令行:
"C:\Program Files\xyz.exe" /a /b /c
由于 ShellExecute() 和 CreateProcess() 需要严格分离命令和参数,我必须自己解析这个字符串。这真的是我唯一可以走的路吗?是否有人编写了具有此功能的公开可用代码?
附加说明:进程不应附加到调用者。我的程序将在命令启动后立即关闭。
【问题讨论】:
-
请注意,CreateProcess 不 要求您将参数与命令分开。检查文档。推荐的做法是为第一个参数传递
NULL,在第二个参数中传递整个命令行。 -
“自己解析这个字符串” - 不是真的。您需要做的就是找到第一个未加引号的空格,以了解命令的结束位置和参数的开始位置。
ShellExecuteEx可以满足您的所有需求。 -
@HarryJohnston 我用 CreateProcess() 试过了,但它似乎不接受非 EXE 文件。例如,INI 文件不会与其关联的应用程序一起打开:pastebin.com/ye7XMSCm。
-
WinExec 也没有,是吗?但乔纳森是对的,将命令字符串拆分为 ShellExecute 或 ShellExecuteEx 所需的两部分并不难。
-
CreateProcess 替换 WinExec。文档清楚地说明了这一点。您的错误检查严重损坏。 ShellExecute 无论如何都不支持正确检查错误。使用 ShellExecuteEx。需要更多地关注文档。