我制作了一个游戏启动器,我使用了这个命令:
procedure TFMain.ImgBtn1Click(Sender: TObject);
begin
ShellExecute(TForm(Owner).Handle, nil, 'starter.exe', '-lang rus', nil, SW_SHOWNORMAL);
end;
' -lang rus'作为参数。一切正常。游戏启动和语言是俄语(如果我把' -lang eng'它仍然正常,游戏是英语)。
starter.exe 应用程序位于名为'' bin ''的文件夹中。当我想将启动器重新定位在此文件夹之外时,我使用以下命令:
procedure TFMain.ImgBtn1Click(Sender: TObject);
begin
ShellExecute(TForm(Owner).Handle, nil, 'bin\starter.exe', '-lang rus', nil, SW_SHOWNORMAL);
end;
但是游戏还没有发布。实际上没有任何反应。 我应该改变什么?
答案 0 :(得分:5)
您必须使用您尝试启动的应用程序的完整路径。
ExtractFilePath(Application.ExeName)
将为您提供启动器执行程序的完整路径。
解决方案1:使用ShellExecute
procedure TFMain.ImgBtn1Click(Sender: TObject);
var
ExecuteResult: integer;
Path: string;
begin
Path := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
ExecuteResult := ShellExecute(0, nil, PChar(Path + 'bin\starter.exe'), '-lang rus', nil, SW_SHOWNORMAL);
if ExecuteResult <= 32 then ShowMessage('Error: ' + IntToStr(ExecuteResult));
end;
您可以在ShellExecute function documentation
找到错误代码列表最常见的错误代码:
ERROR_FILE_NOT_FOUND 0x2
ERROR_PATH_NOT_FOUND 0x3
解决方案2:使用ShellExecuteEx
var
FileName, Parameters, Folder: string;
sei: TShellExecuteInfo;
Error: DWORD;
OK: boolean;
begin
Folder := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName)) + 'bin\';
FileName := Folder + 'starter.exe';
Parameters := '-lang rus';
ZeroMemory(@sei, SizeOf(sei));
sei.cbSize := SizeOf(sei);
sei.lpFile := PChar(FileName);
sei.lpParameters := PChar(Parameters);
sei.lpDirectory := PChar(Folder);
sei.nShow := SW_SHOWNORMAL;
OK := ShellExecuteEx(@sei);
if not OK then
begin
Error := GetLastError;
ShowMessage('Error: ' + IntToStr(Error));
end;
end;
解决方案3:使用CreateProcess
function ExecuteProcess(const FileName, Params: string; Folder: string; WaitUntilTerminated, WaitUntilIdle, RunMinimized: boolean;
var ErrorCode: integer): boolean;
var
CmdLine: string;
WorkingDirP: pchar;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
begin
Result := true;
CmdLine := '"' + FileName + '" ' + Params;
if Folder = '' then Folder := ExcludeTrailingPathDelimiter(ExtractFilePath(FileName));
ZeroMemory(@StartupInfo, SizeOf(StartupInfo));
StartupInfo.cb := SizeOf(StartupInfo);
if RunMinimized then
begin
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow := SW_SHOWMINIMIZED;
end;
if Folder <> '' then WorkingDirP := pchar(Folder)
else WorkingDirP := nil;
if not CreateProcess(nil, pchar(CmdLine), nil, nil, false, 0, nil, WorkingDirP, StartupInfo, ProcessInfo) then
begin
Result := false;
ErrorCode := GetLastError;
exit;
end;
with ProcessInfo do
begin
CloseHandle(hThread);
if WaitUntilIdle then WaitForInputIdle(hProcess, INFINITE);
if WaitUntilTerminated then
repeat
Application.ProcessMessages;
until MsgWaitForMultipleObjects(1, hProcess, false, INFINITE, QS_ALLINPUT) <> WAIT_OBJECT_0 + 1;
CloseHandle(hProcess);
end;
end;
procedure TForm1.Button4Click(Sender: TObject);
var
FileName, Parameters, Folder: string;
Error: integer;
OK: boolean;
begin
Folder := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName)) + 'bin\';
FileName := Folder + 'starter.exe';
Parameters := '-lang rus';
OK := ExecuteProcess(FileName, Parameters, Folder, false, false, false, Error);
if not OK then
begin
Error := GetLastError;
ShowMessage('Error: ' + IntToStr(Error));
end;
end;
答案 1 :(得分:2)
您应该使用完全限定(绝对)路径。例如,如果您知道路径是
C:\Program Files (x86)\My Company\My Game\bin\starter.exe
你应该传递那个字符串。当然,您应该从不对这样的字符串进行硬编码,因为它可能在不同的系统上有所不同。如果您的应用程序是一般应用程序启动器,您将获得用户的路径。如果您的应用程序启动了您自己公司的游戏,您必须找到一种聪明的方式来传达路径。
您的问题并不清楚,但如果bin\starter.exe
与您的应用程序的路径相关,则可以使用
ExtractFilePath(Application.ExeName) + 'bin\starter.exe'
顺便说一下,你可以通过查看ShellExecute
的返回值自己想出这一切。当然,您已经仔细阅读了ShellExecute
documentation,因此您知道返回值是什么。因此,您很容易识别ERROR_FILE_NOT_FOUND
,并意识到您需要一个完全合格的路径。