问题
I have made a Game Launcher and I use this command:
procedure TFMain.ImgBtn1Click(Sender: TObject);
begin
ShellExecute(TForm(Owner).Handle, nil, 'starter.exe', '-lang rus', nil, SW_SHOWNORMAL);
end;
with '-lang rus' as a parameter. Everything works fine. The Game Launches and the language is in russian(if i put '-lang eng' it still works fine and the game is in english).
The starter.exe application is inside a folder named ''bin''. When i want to relocate the launcher outside this folder i use this command:
procedure TFMain.ImgBtn1Click(Sender: TObject);
begin
ShellExecute(TForm(Owner).Handle, nil, 'bin\starter.exe', '-lang rus', nil, SW_SHOWNORMAL);
end;
But then the game isn't launching. Actually nothing happens. What should i change?
回答1:
You have to use full path to the application you are trying to start.
ExtractFilePath(Application.ExeName)
will give you full path to your launcher exe.
Solution 1: using 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;
You can find list of error codes at: ShellExecute function documentation
Most common error codes:
ERROR_FILE_NOT_FOUND 0x2
ERROR_PATH_NOT_FOUND 0x3
Solution 2: using 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;
ShellExecuteEx documentation
Solution 3: using 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;
CreateProcess documentation
回答2:
You should use fully-qualified (absolute) paths. For instance, if you know that the path is
C:\Program Files (x86)\My Company\My Game\bin\starter.exe
you should pass that string. Of course, you should never hard-code such a string, since it may be different on different systems. If your application is a general application launcher, you get the path from the user. If your application launches your own company's games, you have to figure out a clever way to communicate paths.
It is not clear from your question, but if bin\starter.exe
is relative to the path of your application, you can use
ExtractFilePath(Application.ExeName) + 'bin\starter.exe'
By the way, you could have figured all this out by yourself by looking at the return value of ShellExecute
. Of course, you have read the ShellExecute
documentation carefully, so you know what the return values are. So, you would easily have recognised ERROR_FILE_NOT_FOUND
and realised you need a fully-qualified path.
来源:https://stackoverflow.com/questions/27249995/delphi-7-shellexecute-command-not-working-in-situations