Home > Mobile >  Delphi CreateProcess as administrator
Delphi CreateProcess as administrator

Time:11-24

I am executing a command line program from Delphi.

I am using CreateProcess as I need to capture the output and display it in a memo.

My problem now is that the program I am executing needs to run "as administrator" to work properly. If I run it in an "as administrator" command prompt it executes fine.

How do I tell the CreateProcess to run as administrator? I see ShellExecute has an lpVerb parameter that can be set to 'runas' for this to work, but I need CreateProcess to be able to capture the command line output and display it.

I thought if I run my exe as administrator those rights would be passed down to the CreateProcess cmd, but it does not look like that happens.

Any ideas on how I can tell CreateProcess I want to run the process elevated?

Here is the working code now that launches a command line fine (just not as admin)

var
  SA: TSecurityAttributes;
  SI: TStartupInfo;
  PI: TProcessInformation;
  StdOutPipeRead, StdOutPipeWrite: THandle;
  Handle: Boolean;
begin
  with SA do begin
    nLength := SizeOf(SA);
    bInheritHandle := True;
    lpSecurityDescriptor := nil;
  end;
  CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
  try
    with SI do
    begin
      FillChar(SI, SizeOf(SI), 0);
      cb := SizeOf(SI);
      dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
      wShowWindow := SW_HIDE;
      hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
      hStdOutput := StdOutPipeWrite;
      hStdError := StdOutPipeWrite;
    end;
    Handle := CreateProcess(nil, PWideChar('cmd.exe /C '   CommandLine),
                            nil, nil, True, 0, nil,
                            PWideChar(WorkDir), SI, PI);

CodePudding user response:

the program I am executing needs to run "as administrator" to work properly.

If that is true, then that program should have a UAC manifest that specifies a requestedExecutionLevel of requireAdministrator. In which case, CreateProcess() would fail with an ERROR_ELEVATION_REQUIRED error code if your program is not also running as an elevated administrator. If that is not the case then that other program is not designed properly.

How do I tell the CreateProcess to run as administrator?

You cannot, as it does not have that capability.

Your options are to either:

  • run your program as an elevated admin, so that calling CreateProcess() will run the command in the same elevated admin context.

  • use ShellExecute/Ex() with the "runas" verb to run the command as an elevated admin (as you already know). But then, you can't capture the output of the new process, unless you instruct the command to pipe its output to a temp file, which you can then read once the command has terminated.

  • have your main program use ShellExecute/Ex("runas") to run a separate copy of itself as an elevated admin, and then that process can call CreateProcess(), capture the output, and send it back to your main process via an IPC mechanism of your own choosing.

  • refactor your CreateProcess capturing code into a separate COM object, and then use the COM Elevation Moniker to instantiate that object in an elevated admin context when needed.

  • use the unofficial CreateProcessElevated() API that is described in this article: Vista UAC: The Definitive Guide

I thought if I run my exe as administrator those rights would be passed down to the CreateProcess cmd, but it does not look like that happens.

Yes, it will.

CodePudding user response:

I have used this in my programs

function RunAsAdmin(hWnd: hWnd; filename: string; Parameters: string; Visible: Boolean = true): Boolean;
{
  See Step 3: Redesign for UAC Compatibility (UAC)
  http://msdn.microsoft.com/en-us/library/bb756922.aspx
  This code is released into the public domain. No attribution required.
}
var
  sei: TShellExecuteInfo;
begin
  ZeroMemory(@sei, SizeOf(sei));
  sei.cbSize := SizeOf(TShellExecuteInfo);
  sei.Wnd := hWnd;
  sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
  sei.lpVerb := PChar('runas');
  sei.lpFile := PChar(filename); // PAnsiChar;
  if Parameters <> '' then
    sei.lpParameters := PChar(Parameters); // PAnsiChar;
  if Visible then
    sei.nShow := SW_SHOWNORMAL // Integer;
  else
    sei.nShow := SW_HIDE;

  Result := ShellExecuteEx(@sei);
end;
  • Related