unit WindowFinderThread; interface uses System.Classes, System.SysUtils, Winapi.Windows, System.Generics.Collections; type TWindowFinderThread = class(TThread) private FTargetPID: DWORD; FIsBlocked: Boolean; CapBlockWndList_: TList; sProcessName_: string; procedure ApplyCaptureBlock(h: HWND); // Â÷´Ü ·ÎÁ÷ (±¸Çö ÇÊ¿ä) protected procedure Execute; override; public constructor Create(TargetPID: DWORD; sProcessName: string); destructor Destroy; override; procedure ReleaseCaptureBlock(); // ÇØÁ¦ ·ÎÁ÷ (±¸Çö ÇÊ¿ä) function GetTopWindowHwndListByPID_Enum(TargetPID: DWORD; HwndList: TList): Boolean; end; implementation { TWindowFinderThread ±¸Çö } constructor TWindowFinderThread.Create(TargetPID: DWORD; sProcessName: string); begin inherited Create(True); FTargetPID := TargetPID; FIsBlocked := False; FreeOnTerminate := False; sProcessName_:= sProcessName; CapBlockWndList_ := TList.Create; Resume; end; destructor TWindowFinderThread.Destroy; begin // ½º·¹µå°¡ ÆÄ±«µÉ ¶§ Â÷´Ü ÇØÁ¦ ·ÎÁ÷ÀÌ ÇÊ¿äÇÏ´Ù¸é ¿©±â¼­ ¼öÇà // (ÇÏÁö¸¸ º¸Åë Stop ·ÎÁ÷¿¡¼­ ¸í½ÃÀûÀ¸·Î ºÎ¸£´Â °Ô ´õ ¾ÈÀüÇÔ) FreeAndNil(CapBlockWndList_); inherited; end; type // EnumWindowsProc¿¡ ³Ñ°ÜÁÙ µ¥ÀÌÅÍ ±¸Á¶Ã¼ PEnumWindowParams = ^TEnumWindowParams; TEnumWindowParams = record TargetPID: DWORD; List: TList; end; function EnumWindowsProc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall; var pParams: PEnumWindowParams; dwWndPID: DWORD; wp: TWindowPlacement; begin Result := True; // True¸¦ ¹ÝÈ¯ÇØ¾ß ´ÙÀ½ À©µµ¿ì¸¦ °è¼Ó °Ë»öÇÕ´Ï´Ù. // lParamÀ» ¿ì¸®°¡ Á¤ÀÇÇÑ ±¸Á¶Ã¼ Æ÷ÀÎÅÍ·Î º¯È¯ pParams := PEnumWindowParams(lParam); // 1. PID °Ë»ç GetWindowThreadProcessId(hwnd, dwWndPID); if dwWndPID = pParams.TargetPID then begin // 2. ºÎ¸ð À©µµ¿ì°¡ ¾ø´Â ÃÖ»óÀ§ À©µµ¿ìÀÎÁö °Ë»ç if GetParent(hwnd) = 0 then begin // 3. º¸ÀÌ´Â À©µµ¿ìÀÎÁö °Ë»ç if IsWindowVisible(hwnd) then begin // 4. ÃÖ¼ÒÈ­ »óÅ °Ë»ç wp.length := SizeOf(TWindowPlacement); if GetWindowPlacement(hwnd, @wp) then begin if wp.showCmd <> SW_SHOWMINIMIZED then begin // Á¶°ÇÀ» ¸ðµÎ ¸¸Á·ÇÏ¸é ¸®½ºÆ®¿¡ Ãß°¡ // EnumWindows´Â Z-Order »óÀ§(È­¸é ¾Õ)ºÎÅÍ ¼ø¼­´ë·Î È£ÃâÇØÁÝ´Ï´Ù. if Assigned(pParams.List) then begin // C++ ÄÚµå(push_front)¿Í µ¿ÀÏÇÑ ¿ª¼ø ÀúÀåÀ» ¿øÇϸé: pParams.List.Insert(0, hwnd); // Z-Order ¼ø¼­´ë·Î(Top -> Bottom) ÀúÀåÀ» ¿øÇϸé: pParams.List.Add(hwnd); end; end; end; end; end; end; end; // ----------------------------------------------------------------------------- // ¸ÞÀÎ ÇÔ¼ö: EnumWindows¸¦ ½ÇÇàÇÏ´Â ·¡ÆÛ ÇÔ¼ö // ----------------------------------------------------------------------------- function TWindowFinderThread.GetTopWindowHwndListByPID_Enum(TargetPID: DWORD; HwndList: TList): Boolean; var Params: TEnumWindowParams; begin Result := False; if HwndList = nil then Exit; // Äݹé ÇÔ¼ö¿¡ ³Ñ±æ ÆÄ¶ó¹ÌÅÍ ¼¼ÆÃ Params.TargetPID := TargetPID; Params.List := HwndList; // EnumWindows È£Ãâ (ÆÄ¶ó¹ÌÅÍÀÇ Æ÷ÀÎÅ͸¦ lParamÀ¸·Î Àü´Þ) if EnumWindows(@EnumWindowsProc, LPARAM(@Params)) then begin Result := True; end; end; procedure TWindowFinderThread.Execute; var List: TList; h: HWND; className: array[0..255] of Char; Title: array[0..255] of Char; begin List := TList.Create; try // ½º·¹µå°¡ Á¾·á(Terminated) ½ÅÈ£¸¦ ¹ÞÀ» ¶§±îÁö ¹«ÇÑ ¹Ýº¹ while not Terminated do begin List.Clear; // ¾Õ¼­ ¸¸µç EnumWindows ±â¹Ý À©µµ¿ì °Ë»ö ÇÔ¼ö È£Ãâ if GetTopWindowHwndListByPID_Enum(FTargetPID, List) then begin for h in List do begin GetClassName(h, className, Length(className)); GetWindowText(h, Title, Length(Title)); OutputDebugString(PChar(Format('[BSONE] TWindowFinderThread.Execute, h(%p), className(%s), Title(%s)', [Pointer(h), className, Title]))); if CompareText(sProcessName_, 'excel.exe') = 0 then begin if className = 'XLMAIN' then begin FIsBlocked := True; end; end else if CompareText(sProcessName_, 'winword.exe') = 0 then begin if className = 'OpusApp' then begin FIsBlocked := True; end; end else if CompareText(sProcessName_, 'powerpnt.exe') = 0 then begin if className = 'PPTFrameClass' then begin FIsBlocked := True; end; end else if CompareText(sProcessName_, 'acrobat.exe') = 0 then begin if className = 'AcrobatSDIWindow' then begin FIsBlocked := True; end; end else begin FIsBlocked := True; end; if FIsBlocked then begin OutputDebugString(PChar(Format('[BSONE] TWindowFinderThread.FIsBlocked, h(%p)', [Pointer(h)]))); ApplyCaptureBlock(h); break; end; end; end; if FIsBlocked then Break; // 0.5ÃÊ ´ë±â (CPU Á¡À¯À² ¹æÁö) // SleepÀ» Âɰ³¼­ Çϸé Terminated ¹ÝÀÀ ¼Óµµ¸¦ ³ôÀÏ ¼ö ÀÖÀ½ if Terminated and FIsBlocked then Break; Sleep(500); end; finally // ·çÇÁ¸¦ ºüÁ®³ª¿À¸é(Stop ¿äû ½Ã) Â÷´Ü ÇØÁ¦ ¼öÇà if FIsBlocked then begin // ÇÊ¿äÇÏ´Ù¸é ¸¶Áö¸·À¸·Î °Ë»öÇØ¼­ ÇØÁ¦Çϰųª, // ÀúÀåÇØµÐ ÇÚµé·Î ÇØÁ¦ // ReleaseCaptureBlock(...); end; List.Free; end; end; procedure TWindowFinderThread.ApplyCaptureBlock(h: HWND); begin // [¿©±â¿¡ ĸó Â÷´Ü API È£Ãâ ÄÚµå ÀÛ¼º] if h = 0 then exit; if CapBlockWndList_.IndexOf(h) = -1 then CapBlockWndList_.Add(h); SetWindowDisplayAffinity(h, WDA_MONITOR); OutputDebugString(PChar(Format('[BSONE] Capture Block Applying to HWND: %p', [Pointer(h)]))); end; procedure TWindowFinderThread.ReleaseCaptureBlock(); var i: Integer; begin // [¿©±â¿¡ ĸó Â÷´Ü ÇØÁ¦ API È£Ãâ ÄÚµå ÀÛ¼º] try if CapBlockWndList_.Count = 0 then exit; for i := 0 to CapBlockWndList_.Count - 1 do begin OutputDebugString(PChar(Format('[BSONE] Capture Releasing HWND: %p', [Pointer(CapBlockWndList_[i])]))); SetWindowDisplayAffinity(CapBlockWndList_[i], WDA_NONE); end; CapBlockWndList_.Clear; except // .. end; end; end.