BSOne.SFC/Tocsg.Module/SunkAssister/EXE_SunkAssister/WindowPage/ManageWindowPage.pas

354 lines
9.7 KiB
Plaintext

unit ManageWindowPage;
interface
uses
Tocsg.Obj, System.Classes, Winapi.Windows, Vcl.Forms, Vcl.ComCtrls,
System.Generics.Collections, System.SysUtils, Tocsg.Process, superobject,
Winapi.Messages;
const
DAT_WNDPAGES = 'WndPages.dat';
type
TWndTabSheet = class;
TWndFrame = class(TFrame)
protected
OwnerTabSheet_: TWndTabSheet;
public
Constructor Create(aOwner: TComponent); override;
property OwnerTabSheet: TWndTabSheet read OwnerTabSheet_;
end;
TWndFrameClass = class of TWndFrame;
TWndKind = (wkNormal);
PWndInfo = ^TWndInfo;
TWndInfo = record
WndKind: TWndKind;
ProcPath: String;
ProcID: NativeUInt;
WndHandle: HWND;
WndFrameClass: TWndFrameClass;
OrzWndRect: TRect; // 폼이 원상복구(폼이 포함되기 전) 될때의 위치/크기로 변하기 위해 사용 14_0421 22:21:37 sunk
OrzBorderStyle,
OrzBorderExStyle: NativeInt;
ProcInfo: TTgProcessInfo;
end;
TWndTabSheet = class(TTabSheet)
private
WndInfo_: TWndInfo;
WndFrame_: TWndFrame;
public
Constructor Create(aOwner: TComponent; aWndInfo: TWndInfo);
Destructor Destroy; override;
property WndInfo: TWndInfo read WndInfo_;
end;
TWndInfoEnumerator = TEnumerator<PWndInfo>;
TManagerWindowPage = class(TTgObject)
private
DcWndPages_: TDictionary<HWND,PWndInfo>;
// DcProcessTabSheet_: TDictionary<DWORD,TWndTabSheet>;
DcWndTabSheet_: TDictionary<HWND,TWndTabSheet>;
procedure OnWndPage(Sender: TObject; const Item: PWndInfo;
Action: TCollectionNotification);
procedure RemoveWndPage(WndHandle: HWND);
procedure SavePages;
procedure LoadPages;
// function GetWndTabSheetByPID(const dwPid: DWORD): TWndTabSheet;
function GetWndTabSheetByHWND(const hWindow: HWND): TWndTabSheet;
public
Constructor Create;
Destructor Destroy; override;
procedure ClearPages;
procedure AddWndPage(aWndInfo: TWndInfo);
function GetWndPage(aWndHandle: HWND): PWndInfo;
function GetWndTabSheet(aWndHandle: HWND): TWndTabSheet;
function GetWndInfoEnumerator: TWndInfoEnumerator;
procedure DeleteWndTabSheetFromHWND(const hWindow: HWND; bWndDestroyAfter: Boolean = false);
procedure DeleteWndTabSheetFromPid(const dwPid: DWORD);
// property WndTabSheet[const hWindow: HWND]: TWndTabSheet read GetWndTabSheetByHWND;
end;
var
gWndPage: TManagerWindowPage = nil;
implementation
uses
Vcl.Controls, Tocsg.Safe, Tocsg.JSON, Tocsg.Path,
Define, Tocsg.WndUtil, Tocsg.Convert;
{ TWndFrame }
Constructor TWndFrame.Create(aOwner: TComponent);
begin
Inherited Create(aOwner);
ASSERT(aOwner is TWndTabSheet);
OwnerTabSheet_ := aOwner as TWndTabSheet;
end;
{ TWndTabSheet }
Constructor TWndTabSheet.Create(aOwner: TComponent; aWndInfo: TWndInfo);
begin
Inherited Create(aOwner);
WndInfo_ := aWndInfo;
WndFrame_ := WndInfo_.WndFrameClass.Create(Self);
WndFrame_.Parent := Self;
WndFrame_.Align := alClient;
if gWndPage <> nil then
gWndPage.DcWndTabSheet_.Add(WndInfo_.WndHandle, Self);
// gWndPage.DcProcessTabSheet_.Add(WndInfo_.ProcID, Self);
end;
Destructor TWndTabSheet.Destroy;
begin
if gWndPage <> nil then
begin
// gWndPage.DcProcessTabSheet_.Remove(WndInfo_.ProcID);
gWndPage.DcWndTabSheet_.Remove(WndInfo_.WndHandle);
// todo : 포함 윈도우(프로세스)를 같이 닫을건지 아님 뺄건지 묻기/옵션
// if (GetProcessPathFromPID(WndInfo_.ProcID) <> '') and
// (MessageBox(Handle, '하위 프로세스도 함께 종료하시겠습니까?',
// APP_NAME, MB_ICONQUESTION or MB_YESNO) = IDYES) then
// begin
// TerminateProcessFromPID(WndInfo_.ProcID);
// WndInfo_.ProcID := 0;
// end;
// if IsWindow(WndInfo_.WndHandle) and
//// (GetProcessPathFromPID(WndInfo_.ProcID) <> '') and
// (MessageBox(Handle, '하위 윈도우도 함께 종료하시겠습니까?',
// APP_NAME, MB_ICONQUESTION or MB_YESNO) = IDYES) then
// begin
// PostMessage(WndInfo_.WndHandle, WM_CLOSE, 0, 0);
//// WndInfo_.ProcID := 0;
// end;
if GetProcessNameByPid(WndInfo_.ProcID) <> '' then
gWndPage.RemoveWndPage(WndInfo_.WndHandle);
end;
Inherited;
end;
{ TManagerWindowPage }
Constructor TManagerWindowPage.Create;
begin
Inherited Create;
ASSERT(gWndPage = nil);
gWndPage := Self;
DcWndPages_ := TDictionary<HWND,PWndInfo>.Create;
DcWndPages_.OnValueNotify := OnWndPage;
// DcProcessTabSheet_ := TDictionary<DWORD,TWndTabSheet>.Create;
DcWndTabSheet_ := TDictionary<HWND,TWndTabSheet>.Create;
LoadPages;
end;
Destructor TManagerWindowPage.Destroy;
begin
gWndPage := nil;
FreeAndNil(DcWndTabSheet_);
// 정상 종료되면 기존 포함 폼을 정상으로 돌려주고, 비정상 종료로 보이지 않게 비워준다 14_0421 22:32:23 sunk
DcWndPages_.Clear;
SavePages;
FreeAndNil(DcWndPages_);
Inherited;
end;
procedure TManagerWindowPage.OnWndPage(Sender: TObject; const Item: PWndInfo;
Action: TCollectionNotification);
var
WndPlacement: TWindowPlacement;
begin
case Action of
cnAdded:
begin
ZeroMemory(@Item.OrzWndRect, SizeOf(Item.OrzWndRect));
if GetWindowPlacement(Item.WndHandle, WndPlacement) then
Item.OrzWndRect := WndPlacement.rcNormalPosition;
Item.OrzBorderStyle := GetWindowStyle(Item.WndHandle);
Item.OrzBorderExStyle := GetWindowExStyle(Item.WndHandle);
end;
cnRemoved:
begin
if GetProcessNameByPid(Item.ProcID) <> '' then
begin
Winapi.Windows.SetParent(Item.WndHandle, GetDesktopWindow);
if (Item.OrzWndRect.Width <> 0) and (Item.OrzWndRect.Height <> 0) then
MoveWindow(Item.WndHandle, Item.OrzWndRect.Left, Item.OrzWndRect.Top, Item.OrzWndRect.Width, Item.OrzWndRect.Height, true);
SetWindowLong(Item.WndHandle, GWL_STYLE, Item.OrzBorderStyle);
SetWindowLong(Item.WndHandle, GWL_EXSTYLE, Item.OrzBorderExStyle);
end;
if Item.ProcInfo <> nil then
FreeAndNil(Item.ProcInfo);
Dispose(Item);
end;
cnExtracted: ;
end;
end;
procedure TManagerWindowPage.ClearPages;
begin
DcWndPages_.Clear;
SavePages;
end;
procedure TManagerWindowPage.AddWndPage(aWndInfo: TWndInfo);
var
pInfo: PWndInfo;
begin
if (aWndInfo.WndHandle <> 0) and not DcWndPages_.ContainsKey(aWndInfo.WndHandle) then
begin
New(pInfo);
pInfo^ := aWndInfo;
DcWndPages_.Add(pInfo.WndHandle, pInfo);
SavePages;
end;
end;
function TManagerWindowPage.GetWndPage(aWndHandle: HWND): PWndInfo;
begin
if DcWndPages_.ContainsKey(aWndHandle) then
Result := DcWndPages_[aWndHandle]
else
Result := nil;
end;
function TManagerWindowPage.GetWndTabSheet(aWndHandle: HWND): TWndTabSheet;
begin
if DcWndTabSheet_.ContainsKey(aWndHandle) then
Result := DcWndTabSheet_[aWndHandle]
else
Result := nil;
end;
//function TManagerWindowPage.GetWndTabSheetByPID(const dwPid: DWORD): TWndTabSheet;
function TManagerWindowPage.GetWndTabSheetByHWND(const hWindow: HWND): TWndTabSheet;
begin
if DcWndTabSheet_.ContainsKey(hWindow) then
Result := DcWndTabSheet_[hWindow]
else
Result := nil;
end;
procedure TManagerWindowPage.RemoveWndPage(WndHandle: HWND);
begin
if DcWndPages_.ContainsKey(WndHandle) then
begin
DcWndPages_.Remove(WndHandle);
SavePages;
end;
end;
function TManagerWindowPage.GetWndInfoEnumerator: TWndInfoEnumerator;
begin
Result := DcWndPages_.Values.GetEnumerator
end;
procedure TManagerWindowPage.DeleteWndTabSheetFromHWND(const hWindow: HWND; bWndDestroyAfter: Boolean = false);
var
WndTabSheet: TWndTabSheet;
begin
if DcWndTabSheet_.ContainsKey(hWindow) then
begin
WndTabSheet := DcWndTabSheet_[hWindow];
DcWndTabSheet_.Remove(hWindow);
if bWndDestroyAfter then
WndTabSheet.WndInfo_.WndHandle := 0;
WndTabSheet.Free;
end;
end;
procedure TManagerWindowPage.DeleteWndTabSheetFromPid(const dwPid: DWORD);
var
enum: TEnumerator<TWndTabSheet>;
begin
Guard(enum, DcWndTabSheet_.Values.GetEnumerator);
while enum.MoveNext do
begin
if enum.Current.WndInfo_.ProcID = dwPid then
begin
DcWndPages_.Remove(enum.Current.WndInfo_.WndHandle);
enum.Current.Free;
end;
end;
end;
procedure TManagerWindowPage.SavePages;
var
WndPageList: TStringList;
enum: TWndInfoEnumerator;
begin
Guard(WndPageList, TStringList.Create);
Guard(enum, GetWndInfoEnumerator);
while enum.MoveNext do
WndPageList.Add(TTgJson.ValueToJsonAsString<TWndInfo>(enum.Current^));
WndPageList.SaveToFile(GetRunExePathDir + DAT_WNDPAGES);
end;
procedure TManagerWindowPage.LoadPages;
var
sPath: String;
WndPageList: TStringList;
i: Integer;
O: ISuperObject;
WndInfo: TWndInfo;
pInfo: PWndInfo;
begin
sPath := GetRunExePathDir + DAT_WNDPAGES;
if FileExists(sPath) then
begin
Guard(WndPageList, TStringList.Create);
WndPageList.LoadFromFile(GetRunExePathDir + DAT_WNDPAGES);
for i := 0 to WndPageList.Count - 1 do
begin
pInfo := nil;
try
O := SO(WndPageList[i]);
WndInfo.WndKind := TTgRtti.Int64ToSetType<TWndKind>(O.I['WndKind']);
WndInfo.ProcPath := O.S['ProcPath'];
WndInfo.ProcID := O.I['ProcID'];
WndInfo.WndHandle := O.I['WndHandle'];
WndInfo.WndFrameClass := TTgJson.GetDataAsType<TWndFrameClass>(O['WndFrameClass']);
if UpperCase(ExtractFileName(WndInfo.ProcPath)) = UpperCase(GetProcessNameByPID(WndInfo.ProcID)) then
begin
WndInfo.ProcInfo := TTgProcessInfo.Create(WndInfo.ProcID);
New(pInfo);
pInfo^ := WndInfo;
ShowWindow(pInfo.WndHandle, SW_SHOWNORMAL);
// pInfo.WndHandle := GetWndHandleFromPID(WndInfo.ProcID);
DcWndPages_.Add(pInfo.WndHandle, pInfo);
end else
WndInfo.ProcInfo := nil;
except
if pInfo <> nil then
Dispose(pInfo);
continue;
end;
end;
SavePages;
end;
end;
end.