unit uHCLProcessUtils;

{$mode objfpc}{$H+}

/// <summary>
/// Process launch utilities for HC Launcher.
/// Clean-room replacement for the license-incompatible FmxUtils.pas.
/// </summary>

interface

/// <summary>
/// Launches a file or executable with optional parameters and working directory.
/// On Windows, delegates to ShellExecute. On other platforms, uses TProcess.
/// </summary>
/// <param name="AFileName">The file or executable to launch.</param>
/// <param name="AParams">Command-line parameters to pass to the process.</param>
/// <param name="ADefaultDir">The working directory for the launched process.</param>
/// <param name="AShowCmd">Window show command (SW_* constant). Used on Windows only.</param>
/// <returns>True if the process was launched successfully; False otherwise.</returns>
function ExecuteFile(const AFileName, AParams, ADefaultDir: String;
  AShowCmd: Integer): Boolean;

implementation

{$IFDEF MSWINDOWS}
uses
  Windows, ShellAPI;

function ExecuteFile(const AFileName, AParams, ADefaultDir: String;
  AShowCmd: Integer): Boolean;
begin
  Result := ShellExecute(0, nil, PChar(AFileName), PChar(AParams),
    PChar(ADefaultDir), AShowCmd) > 32;
end;

{$ELSE}
uses
  SysUtils, Process;

function ExecuteFile(const AFileName, AParams, ADefaultDir: String;
  AShowCmd: Integer): Boolean;
var
  lProcess: TProcess;
  lParamList: TStringList;
  i: Integer;
  lToken: String;
begin
  Result := False;
  lProcess := TProcess.Create(nil);
  lParamList := TStringList.Create;
  try
    try
      lProcess.Executable := AFileName;
      lProcess.CurrentDirectory := ADefaultDir;
      lProcess.Options := [poNoConsole];

      { Parse AParams into individual tokens, respecting double-quoted groups. }
      if AParams <> '' then
      begin
        lToken := '';
        i := 1;
        while i <= Length(AParams) do
        begin
          if AParams[i] = '"' then
          begin
            Inc(i);
            while (i <= Length(AParams)) and (AParams[i] <> '"') do
            begin
              lToken := lToken + AParams[i];
              Inc(i);
            end;
            { Skip closing quote. }
            if i <= Length(AParams) then
              Inc(i);
          end
          else if AParams[i] = ' ' then
          begin
            if lToken <> '' then
            begin
              lParamList.Add(lToken);
              lToken := '';
            end;
            Inc(i);
          end
          else
          begin
            lToken := lToken + AParams[i];
            Inc(i);
          end;
        end;
        if lToken <> '' then
          lParamList.Add(lToken);
      end;

      for i := 0 to lParamList.Count - 1 do
        lProcess.Parameters.Add(lParamList[i]);

      lProcess.Execute;
      Result := True;
    except
      Result := False;
    end;
  finally
    lParamList.Free;
    lProcess.Free;
  end;
end;
{$ENDIF}

end.
