Delphi 7 - ShellExecute command not working in situations

限于喜欢 提交于 2021-02-07 10:37:17

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!