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 callCreateProcess()
, 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;