441 lines
11 KiB
Plaintext
441 lines
11 KiB
Plaintext
{*******************************************************}
|
|
{ }
|
|
{ Tocsg.WndUtil }
|
|
{ }
|
|
{ Copyright (C) 2022 kku }
|
|
{ }
|
|
{*******************************************************}
|
|
|
|
unit Tocsg.WndUtil;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils, Winapi.Windows, Winapi.Messages, Vcl.Forms, Tocsg.Thread,
|
|
System.Generics.Collections;
|
|
|
|
|
|
|
|
type
|
|
TEvActiveWndNotify = procedure(aSender: TObject; hActiveWnd: HWND) of object;
|
|
TThdActiveWndMon = class(TTgThread)
|
|
protected
|
|
bSync_: Boolean;
|
|
evNotify_: TEvActiveWndNotify;
|
|
hActiveWnd_: HWND;
|
|
procedure ProcessNotify;
|
|
procedure Execute; override;
|
|
public
|
|
Constructor Create(bSync: Boolean = true);
|
|
|
|
property OnActiveWndNotify: TEvActiveWndNotify write evNotify_;
|
|
end;
|
|
|
|
const
|
|
// GWL_STYLE
|
|
WS_VAL: array [0..19] of DWORD = (
|
|
WS_OVERLAPPED, WS_POPUP, WS_CHILD, WS_MINIMIZE, WS_VISIBLE, WS_DISABLED,
|
|
WS_CLIPSIBLINGS, WS_CLIPCHILDREN, WS_MAXIMIZE, WS_CAPTION, WS_BORDER,
|
|
WS_DLGFRAME, WS_VSCROLL, WS_HSCROLL, WS_SYSMENU, WS_THICKFRAME, WS_GROUP,
|
|
WS_TABSTOP, WS_MINIMIZEBOX, WS_MAXIMIZEBOX
|
|
);
|
|
|
|
WS_STR: array [0..19] of String = (
|
|
'WS_OVERLAPPED', 'WS_POPUP', 'WS_CHILD', 'WS_MINIMIZE', 'WS_VISIBLE', 'WS_DISABLED',
|
|
'WS_CLIPSIBLINGS', 'WS_CLIPCHILDREN', 'WS_MAXIMIZE', 'WS_CAPTION', 'WS_BORDER',
|
|
'WS_DLGFRAME', 'WS_VSCROLL', 'WS_HSCROLL', 'WS_SYSMENU', 'WS_THICKFRAME', 'WS_GROUP',
|
|
'WS_TABSTOP', 'WS_MINIMIZEBOX', 'WS_MAXIMIZEBOX'
|
|
);
|
|
|
|
// GWL_EXSTYLE
|
|
WS_EX_VAL: array [0..23] of LongInt = (
|
|
WS_EX_DLGMODALFRAME, WS_EX_NOPARENTNOTIFY, WS_EX_TOPMOST, WS_EX_ACCEPTFILES,
|
|
WS_EX_TRANSPARENT, WS_EX_MDICHILD, WS_EX_TOOLWINDOW, WS_EX_WINDOWEDGE,
|
|
WS_EX_CLIENTEDGE, WS_EX_CONTEXTHELP, WS_EX_RIGHT, WS_EX_LEFT, WS_EX_RTLREADING,
|
|
WS_EX_LTRREADING, WS_EX_LEFTSCROLLBAR, WS_EX_RIGHTSCROLLBAR, WS_EX_CONTROLPARENT,
|
|
WS_EX_STATICEDGE, WS_EX_APPWINDOW, WS_EX_LAYERED, WS_EX_NOINHERITLAYOUT,
|
|
WS_EX_LAYOUTRTL, WS_EX_COMPOSITED, WS_EX_NOACTIVATE
|
|
);
|
|
|
|
WS_EX_STR: array [0..23] of String = (
|
|
'WS_EX_DLGMODALFRAME', 'WS_EX_NOPARENTNOTIFY', 'WS_EX_TOPMOST', 'WS_EX_ACCEPTFILES',
|
|
'WS_EX_TRANSPARENT', 'WS_EX_MDICHILD', 'WS_EX_TOOLWINDOW', 'WS_EX_WINDOWEDGE',
|
|
'WS_EX_CLIENTEDGE', 'WS_EX_CONTEXTHELP', 'WS_EX_RIGHT', 'WS_EX_LEFT', 'WS_EX_RTLREADING',
|
|
'WS_EX_LTRREADING', 'WS_EX_LEFTSCROLLBAR', 'WS_EX_RIGHTSCROLLBAR', 'WS_EX_CONTROLPARENT',
|
|
'WS_EX_STATICEDGE', 'WS_EX_APPWINDOW', 'WS_EX_LAYERED', 'WS_EX_NOINHERITLAYOUT',
|
|
'WS_EX_LAYOUTRTL', 'WS_EX_COMPOSITED', 'WS_EX_NOACTIVATE'
|
|
);
|
|
|
|
function GetWindowStyle(h: HWND): NativeInt;
|
|
function GetWindowStyleStr(h: HWND): String;
|
|
|
|
function GetWindowExStyle(h: HWND): NativeInt;
|
|
function GetWindowExStyleStr(h: HWND): String;
|
|
|
|
function GetWindowCaption(h: HWND): String;
|
|
function GetEditText(h: HWND): String;
|
|
procedure SetEditText(h: HWND; const sText: String);
|
|
function GetTopParentHWND(h: HWND): HWND;
|
|
function GetWndChildClass(h: HWND; const sClassName: String; hNextChild: HWND = 0): HWND;
|
|
function GetWndChildByCaption(h: HWND; const sFindCaption: String; hNextChild: HWND = 0): HWND;
|
|
function GetWndClassName(h: HWND): String;
|
|
function HasWndChild(hParent, hSrc: HWND): Boolean;
|
|
|
|
function GetProgressMax(h: HWND): Integer; // for "msctls_progress32" class
|
|
function GetProgressPos(h: HWND): Integer; // for "msctls_progress32" class
|
|
|
|
procedure SetScreenCenterForm(aForm: TForm);
|
|
|
|
function FindWindowFromProcessName(sPName: String; bIncInvisible: Boolean = false): HWND;
|
|
|
|
function SendData(h: HWND; dwCmd: DWORD; const sData: String): LONGLONG;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Tocsg.Trace, Tocsg.Exception, Tocsg.Process;
|
|
|
|
{ TThdActiveWndMon }
|
|
|
|
Constructor TThdActiveWndMon.Create(bSync: Boolean = true);
|
|
begin
|
|
Inherited Create;
|
|
bSync_ := bSync;
|
|
hActiveWnd_ := 0;
|
|
@evNotify_ := nil;
|
|
end;
|
|
|
|
procedure TThdActiveWndMon.ProcessNotify;
|
|
begin
|
|
if Assigned(evNotify_) and (hActiveWnd_ <> 0) then
|
|
evNotify_(Self, hActiveWnd_);
|
|
end;
|
|
|
|
procedure TThdActiveWndMon.Execute;
|
|
var
|
|
h, hRecentWnd: HWND;
|
|
begin
|
|
hRecentWnd := 0;
|
|
while not Terminated and not GetWorkStop do
|
|
begin
|
|
h := GetForegroundWindow;
|
|
if h <> hRecentWnd then
|
|
begin
|
|
hRecentWnd := h;
|
|
if bSync_ then
|
|
begin
|
|
hActiveWnd_ := h;
|
|
Synchronize(ProcessNotify);
|
|
end else
|
|
if Assigned(evNotify_) then
|
|
evNotify_(Self, h);
|
|
end;
|
|
Sleep(500);
|
|
end;
|
|
end;
|
|
|
|
|
|
{ Other }
|
|
|
|
// GWL_STYLE
|
|
function GetWindowStyle(h: HWND): NativeInt;
|
|
begin
|
|
Result := 0;
|
|
if h <> 0 then
|
|
Result := GetWindowLong(h, GWL_STYLE);
|
|
end;
|
|
|
|
function GetWindowStyleStr(h: HWND): String;
|
|
var
|
|
i: Integer;
|
|
wStyle: LongInt;
|
|
begin
|
|
Result := '';
|
|
|
|
wStyle := GetWindowStyle(h);
|
|
if wStyle <> 0 then
|
|
for i := 0 to Length(WS_VAL) - 1 do
|
|
if (WS_VAL[i] and wStyle) = WS_VAL[i] then
|
|
begin
|
|
if Length(Result) > 0 then
|
|
Result := Result + '|' + WS_STR[i]
|
|
else
|
|
Result := WS_STR[i];
|
|
end;
|
|
end;
|
|
|
|
|
|
// GWL_EXSTYLE
|
|
function GetWindowExStyle(h: HWND): NativeInt;
|
|
begin
|
|
Result := 0;
|
|
if h <> 0 then
|
|
Result := GetWindowLong(h, GWL_EXSTYLE);
|
|
end;
|
|
|
|
|
|
function GetWindowExStyleStr(h: HWND): String;
|
|
var
|
|
i: Integer;
|
|
wExStyle: LongInt;
|
|
begin
|
|
Result := '';
|
|
|
|
wExStyle := GetWindowExStyle(h);
|
|
if wExStyle <> 0 then
|
|
begin
|
|
for i := 0 to Length(WS_EX_VAL) - 1 do
|
|
begin
|
|
if (WS_EX_VAL[i] and wExStyle) = WS_EX_VAL[i] then
|
|
begin
|
|
if Length(Result) > 0 then
|
|
Result := Result + '|' + WS_EX_STR[i]
|
|
else
|
|
Result := WS_EX_STR[i];
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetWindowCaption(h: HWND): String;
|
|
var
|
|
nLen: Integer;
|
|
str: array of Char;
|
|
begin
|
|
|
|
Result := '';
|
|
nLen := GetWindowTextLength(h);
|
|
if nLen > 0 then
|
|
begin
|
|
Inc(nLen); // GetWindowText()에서 1 더해줘야 정상 처리 되는 경우 있음 24_1209 13:39:07 kku
|
|
|
|
SetLength(str, nLen);
|
|
ZeroMemory(@str[0], nLen * 2);
|
|
if GetWindowText(h, @str[0], nLen) <> 0 then
|
|
Result := String(PChar(@str[0]));
|
|
end;
|
|
end;
|
|
|
|
function GetEditText(h: HWND): String;
|
|
var
|
|
str: array of Char;
|
|
dwResult: DWORD;
|
|
begin
|
|
Result := '';
|
|
|
|
SetLength(str, 1024);
|
|
try
|
|
// SendMessageTimeout(h, WM_GETTEXT, 1024, LPARAM(str), SMTO_NORMAL, 3000, @dwResult);
|
|
SendMessage(h, WM_GETTEXT, 1024, LPARAM(str));
|
|
Result := PChar(@str[0]);
|
|
finally
|
|
SetLength(str, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure SetEditText(h: HWND; const sText: String);
|
|
begin
|
|
SendMessage(h, WM_SETTEXT, 0, LPARAM(@sText[1]));
|
|
end;
|
|
|
|
function GetTopParentHWND(h: HWND): HWND;
|
|
begin
|
|
Result := h;
|
|
while Result <> 0 do
|
|
begin
|
|
if GetParent(Result) = 0 then
|
|
exit;
|
|
Result:= GetParent(Result);
|
|
end;
|
|
end;
|
|
|
|
function GetWndChildClass(h: HWND; const sClassName: String; hNextChild: HWND = 0): HWND;
|
|
var
|
|
hChild: HWND;
|
|
arrClassName: array [0..255] of Char;
|
|
begin
|
|
Result := 0;
|
|
hChild := GetWindow(h, GW_CHILD);
|
|
|
|
if hChild <> 0 then
|
|
begin
|
|
if hNextChild <> 0 then
|
|
hChild := GetWindow(hNextChild, GW_HWNDNEXT);
|
|
|
|
while hChild <> 0 do
|
|
begin
|
|
if GetClassName(hChild, arrClassName, SizeOf(arrClassName)) > 0 then
|
|
begin
|
|
if CompareMem(@arrClassName[0], @sClassName[1], Length(sClassName)) then
|
|
begin
|
|
Result := hChild;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if GetWindow(hChild, GW_CHILD) <> 0 then
|
|
begin
|
|
Result := GetWndChildClass(hChild, sClassName);
|
|
if Result <> 0 then
|
|
exit;
|
|
end;
|
|
|
|
hChild := GetWindow(hChild, GW_HWNDNEXT);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetWndChildByCaption(h: HWND; const sFindCaption: String; hNextChild: HWND = 0): HWND;
|
|
var
|
|
hChild: HWND;
|
|
sCaption: String;
|
|
begin
|
|
Result := 0;
|
|
hChild := GetWindow(h, GW_CHILD);
|
|
|
|
if hChild <> 0 then
|
|
begin
|
|
if hNextChild <> 0 then
|
|
while hNextChild <> hChild do
|
|
hChild := GetWindow(hChild, GW_HWNDNEXT);
|
|
|
|
while hChild <> 0 do
|
|
begin
|
|
sCaption := GetWindowCaption(hChild);
|
|
if sCaption = sFindCaption then
|
|
begin
|
|
Result := hChild;
|
|
exit;
|
|
end;
|
|
|
|
if GetWindow(hChild, GW_CHILD) <> 0 then
|
|
begin
|
|
Result := GetWndChildClass(hChild, sFindCaption);
|
|
if Result <> 0 then
|
|
exit;
|
|
end;
|
|
|
|
hChild := GetWindow(hChild, GW_HWNDNEXT);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetWndClassName(h: HWND): String;
|
|
var
|
|
arrClassName: array [0..255] of Char;
|
|
begin
|
|
Result := '';
|
|
if h <> 0 then
|
|
if GetClassName(h, arrClassName, SizeOf(arrClassName)) > 0 then
|
|
Result := String(arrClassName);
|
|
end;
|
|
|
|
function HasWndChild(hParent, hSrc: HWND): Boolean;
|
|
var
|
|
hChild: HWND;
|
|
begin
|
|
Result := false;
|
|
hChild := GetWindow(hParent, GW_CHILD);
|
|
|
|
while hChild <> 0 do
|
|
begin
|
|
if hChild = hSrc then
|
|
begin
|
|
Result := true;
|
|
exit;
|
|
end;
|
|
|
|
if HasWndChild(hChild, hSrc) then
|
|
begin
|
|
Result := true;
|
|
exit;
|
|
end;
|
|
|
|
hChild := GetWindow(hChild, GW_HWNDNEXT);
|
|
end;
|
|
end;
|
|
|
|
function GetProgressMax(h: HWND): Integer; // for "msctls_progress32" class
|
|
const
|
|
PBM_GETRANGE = $0407;
|
|
begin
|
|
Result := SendMessage(h, PBM_GETRANGE, 0, 0);
|
|
end;
|
|
|
|
function GetProgressPos(h: HWND): Integer; // for "msctls_progress32" class
|
|
const
|
|
PBM_GETPOS = $0408;
|
|
begin
|
|
Result := SendMessage(h, PBM_GETPOS, 0, 0);
|
|
end;
|
|
|
|
procedure SetScreenCenterForm(aForm: TForm);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to Screen.MonitorCount - 1 do
|
|
if Screen.Monitors[i].Primary then
|
|
begin
|
|
if (Screen.Monitors[i].Width > aForm.Width) and
|
|
(Screen.Monitors[i].Height > aForm.Height) then
|
|
begin
|
|
aForm.Left := (Screen.Monitors[i].Width div 2) - (aForm.Width div 2);
|
|
aForm.Top := (Screen.Monitors[i].Height div 2) - (aForm.Height div 2);
|
|
end else begin
|
|
aForm.Left := 0;
|
|
aForm.Top := 0;
|
|
end;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function FindWindowFromProcessName(sPName: String; bIncInvisible: Boolean = false): HWND;
|
|
var
|
|
h: HWND;
|
|
llStyle: LONGLONG;
|
|
sTemp: String;
|
|
begin
|
|
Result := 0;
|
|
try
|
|
h := FindWindow(nil, nil);
|
|
while h <> 0 do
|
|
begin
|
|
llStyle := GetWindowStyle(h);
|
|
if bIncInvisible or
|
|
( ((llStyle and WS_VISIBLE) <> 0) and
|
|
((llStyle and WS_MINIMIZE) = 0) ) then
|
|
begin
|
|
sTemp := GetWindowCaption(h);
|
|
if sTemp <> '' then
|
|
begin
|
|
sTemp := GetProcessNameFromWndHandle(h);
|
|
if sTemp = sPName then
|
|
begin
|
|
Result := h;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
h := GetWindow(h, GW_HWNDNEXT);
|
|
end;
|
|
except
|
|
on E: ETgException do
|
|
ETgException.TraceException(E, 'Fail .. FindWindowFromProcessName()');
|
|
end;
|
|
end;
|
|
|
|
function SendData(h: HWND; dwCmd: DWORD; const sData: String): LONGLONG;
|
|
var
|
|
CopyData: TCopyDataStruct;
|
|
begin
|
|
CopyData.dwData := dwCmd;
|
|
|
|
CopyData.cbData := (Length(sData) + 1) * 2;
|
|
CopyData.lpData := PChar(sData);
|
|
|
|
Result := SendMessage(h, WM_COPYDATA, 0, NativeInt(@CopyData));
|
|
Application.ProcessMessages;
|
|
end;
|
|
|
|
end.
|