프로그래밍 초보 탈출

Libraries/Delphi Library

[System] Execute Library

째즈토끼 2022. 6. 17. 17:23
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;

'Libraries > Delphi Library' 카테고리의 다른 글

[Protocol] Modbus RTU Packet Library  (0) 2022.06.17
[System] Execute Library 2  (0) 2022.06.17
[System] Process Token Library  (0) 2022.06.17
[System] Process Information Library  (0) 2022.06.17
[TCP/IP] Mac Address 추출하기  (0) 2022.06.15