unit LibExecute;
interface
uses
Windows, SysUtils, ShellApi, WinBase, WinNT, WTSApi32,
LibLog, StrUtils;
function EXECUTE_RunEx( ApplicationName : PChar;
ProcessInfo : PProcessInformation;
Parameter : PChar = nil;
const Directory : PChar = nil;
const WaitForInputIdle : Boolean = FALSE;
const Show : Integer = SW_SHOW) : BOOL;
function EXECUTE_Run( ApplicationName : PChar;
Parameter : PChar = nil;
const Directory : PChar = nil;
const WaitForInputIdle : Boolean = FALSE;
const WaitForTermination : Boolean = FALSE;
const WaitingThread : THandle = 0;
const Show : Integer = SW_SHOW) : BOOL;
function SHELL_EXECUTE_RunEx( EI : PShellExecuteInfo;
const WaitForInputIdle : Boolean = FALSE;
const WaitForTermination : Boolean = FALSE;
const WaitingThread : THandle = 0) : BOOL;
function SHELL_EXECUTE_Run( FileName : PChar;
const Parameter : PChar = nil;
const Owner : HWND = 0;
const Operation : String = 'open';
const Directory : PChar = nil;
const WaitForInputIdle : Boolean = FALSE;
const WaitForTermination : Boolean = FALSE;
const WaitingThread : THandle = 0;
const Show : Integer = SW_SHOW) : BOOL;
function EXECUTE_RunAsUser( UserToken: THandle;
ApplicationName : PChar;
ProcessInfo : PProcessInformation;
Parameter : PChar = nil;
const Directory : PChar = nil;
const WaitForInputIdle : Boolean = FALSE;
const Show : Integer = SW_SHOW;
const Flags: DWORD = CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS) : BOOL;
function EXECUTE_RunAsConsoleUser(
ApplicationName : PChar;
ProcessInfo : PProcessInformation;
Parameter : PChar = nil;
const Directory : PChar = nil;
const WaitForInputIdle : Boolean = FALSE;
const Show : Integer = SW_SHOW;
const Flags: DWORD = DETACHED_PROCESS or NORMAL_PRIORITY_CLASS) : BOOL;
function EXECUTE_RunAndCaptureStdout( CmdLine: String;
var TextOut: String;
UserToken: THandle = 0;
EnvironmentBlock: Pointer = nil): BOOL;
function EXECUTE_GetLastError: DWORD;
implementation
const
DefaultDeskTop: String = 'winsta0\default';
var
FLastError: DWORD;
function EXECUTE_GetLastError: DWORD;
begin
RESULT := FLastError;
end;
function EXECUTE_RunEx( ApplicationName : PChar;
ProcessInfo : PProcessInformation;
Parameter : PChar = nil;
const Directory : PChar = nil;
const WaitForInputIdle : Boolean = FALSE;
const Show : Integer = SW_SHOW) : BOOL;
var
SUInfo : TStartupInfo;
ARGU : String;
TempPI : TProcessInformation;
TempPIP : PProcessInformation;
begin
ARGU := '"' + ApplicationName + '"';
if Parameter <> nil then begin
ARGU := Trim(ARGU + ' ' + Parameter);
end;
ZeroMemory(@SUInfo, SizeOf(SUInfo));
SUInfo.cb := SizeOf(SUInfo);
SUInfo.dwFlags := STARTF_USESHOWWINDOW;
SUInfo.wShowWindow := Show;
if ProcessInfo = nil
then TempPIP := @TempPI
else TempPIP := ProcessInfo;
try begin
FLastError := 0;
RESULT := CreateProcess(nil, PChar(ARGU), nil, nil, FALSE,
CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, Directory,
SUInfo, TempPIP^);
if not RESULT then FLastError := GetLastError();
if RESULT and WaitForInputIdle then Windows.WaitForInputIdle(TempPIP^.hProcess, INFINITE);
end;
except begin
RESULT := FALSE;
end;
end;
if RESULT and (ProcessInfo = nil) then begin
if TempPI.hProcess <> 0 then CloseHandle(TempPI.hProcess);
if TempPI.hThread <> 0 then CloseHandle(TempPI.hThread);
end;
end;
function EXECUTE_Run( ApplicationName : PChar;
Parameter : PChar = nil;
const Directory : PChar = nil;
const WaitForInputIdle : Boolean = FALSE;
const WaitForTermination : Boolean = FALSE;
const WaitingThread : THandle = 0;
const Show : Integer = SW_SHOW) : BOOL;
var
ProcessInfo : TProcessInformation;
begin
try begin
RESULT := EXECUTE_RunEx(ApplicationName, @ProcessInfo, Parameter, Directory, WaitForInputIdle, Show);
if RESULT then begin
RESULT := BOOL(ProcessInfo.hProcess);
if WaitForTermination then begin
if WaitingThread = 0 then begin
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
end
else begin
while (WaitForSingleObject(WaitingThread, 0) = WAIT_TIMEOUT) and
(WaitForSingleObject(ProcessInfo.hProcess, 1000) = WAIT_TIMEOUT) do Sleep(100);
end;
end;
end;
end;
except begin
RESULT := FALSE;
end;
end;
if RESULT then begin
if ProcessInfo.hProcess <> 0 then CloseHandle(ProcessInfo.hProcess);
if ProcessInfo.hThread <> 0 then CloseHandle(ProcessInfo.hThread);
end;
end;
function SHELL_EXECUTE_RunEx( EI : PShellExecuteInfo;
const WaitForInputIdle : Boolean = FALSE;
const WaitForTermination : Boolean = FALSE;
const WaitingThread : THandle = 0) : BOOL;
var
EI_OrigMask : DWORD;
begin
EI_OrigMask := EI^.fMask;
EI^.fMask := EI^.fMask or SEE_MASK_NOCLOSEPROCESS;
EI^.hProcess := 0;
try begin
FLastError := 0;
RESULT := ShellExecuteEx(EI) and (EI^.hInstApp > 32);
if not RESULT then FLastError := GetLastError();
if RESULT then begin
if WaitForInputIdle then begin
Windows.WaitForInputIdle(EI^.hProcess, INFINITE);
end;
if WaitForTermination then begin
if WaitingThread = 0 then begin
WaitForSingleObject(EI^.hProcess, INFINITE);
end
else begin
while (WaitForSingleObject(WaitingThread, 0) = WAIT_TIMEOUT) and
(WaitForSingleObject(EI^.hProcess, 1000) = WAIT_TIMEOUT) do Sleep(100);
end;
end;
end;
end;
except begin
RESULT := FALSE;
end;
end;
EI^.fMask := EI_OrigMask;
if (EI^.hProcess <> 0) and ((EI_OrigMask and SEE_MASK_NOCLOSEPROCESS) = 0) then begin
CloseHandle(EI^.hProcess);
EI^.hProcess := 0;
end;
end;
function SHELL_EXECUTE_Run( FileName : PChar;
const Parameter : PChar = nil;
const Owner : HWND = 0;
const Operation : String = 'open';
const Directory : PChar = nil;
const WaitForInputIdle : Boolean = FALSE;
const WaitForTermination : Boolean = FALSE;
const WaitingThread : THandle = 0;
const Show : Integer = SW_SHOW) : BOOL;
var
EI : TShellExecuteInfo;
begin
ZeroMemory(@EI, SizeOf(EI));
EI.cbSize := SizeOf(EI);
EI.Wnd := Owner;
EI.lpVerb := PChar(Operation);
EI.lpFile := FileName;
EI.lpParameters := Parameter;
EI.lpDirectory := Directory;
EI.nShow := Show;
RESULT := SHELL_EXECUTE_RunEx(@EI, WaitForInputIdle, WaitForTermination, WaitingThread);
end;
function EXECUTE_RunAsUser( UserToken: THandle;
ApplicationName : PChar;
ProcessInfo : PProcessInformation;
Parameter : PChar = nil;
const Directory : PChar = nil;
const WaitForInputIdle : Boolean = FALSE;
const Show : Integer = SW_SHOW;
const Flags: DWORD = CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS) : BOOL;
var
SUInfo : TStartupInfo;
ARGU : String;
TempPI : TProcessInformation;
TempPIP : PProcessInformation;
begin
ARGU := '"' + ApplicationName + '"';
if Parameter <> nil then begin
ARGU := Trim(ARGU + ' ' + Parameter);
end;
ZeroMemory(@SUInfo, SizeOf(SUInfo));
SUInfo.cb := SizeOf(SUInfo);
SUInfo.dwFlags := STARTF_USESHOWWINDOW;
SUInfo.wShowWindow := Show;
SUInfo.lpDesktop := PChar(DefaultDeskTop);
if ProcessInfo = nil
then TempPIP := @TempPI
else TempPIP := ProcessInfo;
try begin
FLastError := 0;
RESULT := CreateProcessAsUser(UserToken, nil, PChar(ARGU), nil, nil, FALSE,
Flags, nil, Directory,
SUInfo, TempPIP^);
if not RESULT then FLastError := GetLastError();
if RESULT and WaitForInputIdle then Windows.WaitForInputIdle(TempPIP^.hProcess, INFINITE);
end;
except begin
RESULT := FALSE;
end;
end;
if RESULT and (ProcessInfo = nil) then begin
if TempPI.hProcess <> 0 then CloseHandle(TempPI.hProcess);
if TempPI.hThread <> 0 then CloseHandle(TempPI.hThread);
end;
end;
function EXECUTE_RunAsConsoleUser(
ApplicationName : PChar;
ProcessInfo : PProcessInformation;
Parameter : PChar = nil;
const Directory : PChar = nil;
const WaitForInputIdle : Boolean = FALSE;
const Show : Integer = SW_SHOW;
const Flags: DWORD = DETACHED_PROCESS or NORMAL_PRIORITY_CLASS) : BOOL;
var
ACS_ID: DWORD;
Token: THandle;
begin
ACS_ID := WTSGetActiveConsoleSessionId();
if ACS_ID = $FFFFFFFF then begin
SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
RESULT := FALSE;
Exit;
end;
if not WTSQueryUserToken(ACS_ID, Token) then begin
RESULT := FALSE;
Exit;
end;
RESULT := EXECUTE_RunAsUser(Token, ApplicationName, ProcessInfo, Parameter,
Directory, WaitForInputIdle, Show, Flags);
CloseHandle(Token);
end;
function EXECUTE_RunAndCaptureStdout( CmdLine: String;
var TextOut: String;
UserToken: THandle = 0;
EnvironmentBlock: Pointer = nil): BOOL;
var
SA: TSecurityAttributes;
RP, WP : THandle;
SI: TStartupInfo;
PI: TProcessInformation;
Buffer: array[0..256] of AnsiChar;
Len: DWORD;
CF: DWORD;
begin
TextOut := '';
SA.nLength := SizeOf(SA);
SA.bInheritHandle := TRUE;
SA.lpSecurityDescriptor := nil;
CreatePipe(RP, WP, @SA, 0);
FillChar(SI, SizeOf(SI), 0);
SI.cb := SizeOf(SI);
SI.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
SI.wShowWindow := SW_HIDE;
SI.hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
SI.hStdOutput := WP;
SI.hStdError := WP;
SI.lpDesktop := PChar(DefaultDeskTop);
CF := 0;
if Assigned(EnvironmentBlock) then CF := CF or CREATE_UNICODE_ENVIRONMENT or CREATE_NEW_CONSOLE;
try
if UserToken = 0
then RESULT := CreateProcess ( nil, PChar(CmdLine), nil, nil, TRUE, CF, EnvironmentBlock, nil, SI, PI)
else RESULT := CreateProcessAsUser(UserToken, nil, PChar(CmdLine), nil, nil, TRUE, CF, EnvironmentBlock, nil, SI, PI);
except
RESULT := FALSE;
end;
CloseHandle(WP);
if RESULT then begin
try
while ReadFile(RP, Buffer, 256, Len, nil) and (Len > 0) do begin
Buffer[Len] := #0;
TextOut := TextOut + Buffer;
end;
WaitForSingleObject(PI.hProcess, INFINITE);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
end;
CloseHandle(RP);
end;