Delphi 如何知道表单已创建?
我想找到一种方法来知道表单是在运行时创建的(或已销毁)。 这适用于德尔福或fpc。 非常感谢Delphi 如何知道表单已创建?,delphi,runtime,oncreate,lazarus,Delphi,Runtime,Oncreate,Lazarus,我想找到一种方法来知道表单是在运行时创建的(或已销毁)。 这适用于德尔福或fpc。 非常感谢 PS:有没有一种方法可以检索所有对象的信息?使用t表单的OnCreate事件以任何方式通知您想要的人 我希望有一个事件告诉我一个新对象是在运行时创建的(或销毁的) 没有在创建或销毁对象时触发的内置事件 因为我喜欢编写代码挂钩,所以我提供以下单元。这将钩住系统单元中的\u AfterConstruction方法。理想情况下,它应该使用蹦床,但我从未学会如何实现这些。如果你使用一个真正的钩图书馆,你会做得更
PS:有没有一种方法可以检索所有对象的信息?使用
t表单的OnCreate
事件以任何方式通知您想要的人
我希望有一个事件告诉我一个新对象是在运行时创建的(或销毁的)
没有在创建或销毁对象时触发的内置事件
因为我喜欢编写代码挂钩,所以我提供以下单元。这将钩住系统
单元中的\u AfterConstruction
方法。理想情况下,它应该使用蹦床,但我从未学会如何实现这些。如果你使用一个真正的钩图书馆,你会做得更好。无论如何,这是:
unit AfterConstructionEvent;
interface
var
OnAfterConstruction: procedure(Instance: TObject);
implementation
uses
Windows;
procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
OldProtect: DWORD;
begin
if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
begin
Move(NewCode, Address^, Size);
FlushInstructionCache(GetCurrentProcess, Address, Size);
VirtualProtect(Address, Size, OldProtect, @OldProtect);
end;
end;
type
PInstruction = ^TInstruction;
TInstruction = packed record
Opcode: Byte;
Offset: Integer;
end;
procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
NewCode: TInstruction;
begin
NewCode.Opcode := $E9;//jump relative
NewCode.Offset := NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode);
PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;
function System_AfterConstruction: Pointer;
asm
MOV EAX, offset System.@AfterConstruction
end;
function System_BeforeDestruction: Pointer;
asm
MOV EAX, offset System.@BeforeDestruction
end;
var
_BeforeDestruction: procedure(const Instance: TObject; OuterMost: ShortInt);
function _AfterConstruction(const Instance: TObject): TObject;
begin
try
Instance.AfterConstruction;
Result := Instance;
if Assigned(OnAfterConstruction) then
OnAfterConstruction(Instance);
except
_BeforeDestruction(Instance, 1);
raise;
end;
end;
initialization
@_BeforeDestruction := System_BeforeDestruction;
RedirectProcedure(System_AfterConstruction, @_AfterConstruction);
end.
将处理程序分配给OnAfterConstruction
,每当创建对象时都会调用该处理程序
我把它作为一个练习留给读者添加一个onbeforedescrosition
事件处理程序
请注意,我并不是说这种方法是一件好事。我只是回答你直接提出的问题。你可以自己决定是否使用这个。我知道我不会这么做 在MS Windows中,您可以使用以下小模板钩住流程的事件:
{$mode objfpc}{$H+}
uses
Windows, JwaWinUser;
function ShellProc(nCode: longint; wParam: WPARAM; lParam: LPARAM): longint; stdcall;
var
wnd: HWND;
begin
Result := 0;
case nCode of
HSHELL_WINDOWCREATED:
begin
wnd := wParam;
// Check window
// Get task handle
// Get window icon
// Add task to the list
// Call event
end;
HSHELL_WINDOWDESTROYED:
begin
wnd := wParam;
// Check window
// Get task handle
// Get window icon
// Remove task to the list
// Call event
end;
HSHELL_LANGUAGE:
begin
// Get language
// Call event
end;
HSHELL_REDRAW:
begin
// Call event
end;
HSHELL_WINDOWACTIVATED:
begin
// Get language
// Call event
end;
//HSHELL_APPCOMMAND:
//begin
// { TODO 1 -ond -csys : Specify return value for this code }
// Result := -1;
//end;
end;
// Call next hook in the chain
Result := CallNextHookEx(
0,
nCode,
wParam,
lParam);
end;
var
FCallbackProc: HOOKPROC;
function InitShellHook(AProc: HOOKPROC): HHOOK; stdcall; export;
begin
FCallbackProc := AProc;
Result := SetWindowsHookEx(WH_SHELL, @ShellProc, 0, 0);
end;
procedure DoneShellHook(AHook: HHOOK); stdcall; export;
begin
UnhookWindowsHookEx(AHook);
end;
HSHELL_WINDOWCREATED将通知您,您的过程是创建新窗口
使用您的过程地址调用InitShellHook
(请参阅HOOCPROC
声明)。“有没有办法检索所有对象的信息?”这意味着什么?我想让一个事件告诉我,新对象刚刚在运行时创建(或销毁)。您能解释一下为什么需要这样一个事件吗?一点背景知识可能会为您的问题提供其他可能的解决方案。好的,这是我的想法,但您如何为所有创建的新表单分配常规事件,例如对话框?更清楚地说,是否可以为所有将创建的新表单分配新的OnCreate事件?@user2418856是-只分配一个。当您执行NewForm:=TNewForm.Create
,后跟NewForm.OnCreate:=MyOnCreateHandler代码>我认为最好在一个祖先窗体中编写一个事件,并为所有其他窗体继承它。通常,要创建一个继承窗体,请进入菜单:File/New/Other//选择您的窗体,确保标记了inherited,然后使用它。我不知道其他版本,我正在使用Delphi7。+1,但在我看来,在大多数情况下,他可以简单地继承一个共同的祖先形式。这将更简单,更容易理解manage@MatheusFreitas的确读一读我的最后一段。我不提倡使用此代码。@MatheusFreitas是的,这不是一个很好的实践,但无论如何它非常优雅…@David Heffernan:你很棒,很慷慨,我会研究你的代码,非常感谢。你应该研究更多他说“不要使用此”的评论。很难将其与Delphi对象联系起来。不仅仅是VCL中的窗口重建技术。@DavidHeffernan它适用于任何窗口(我记得问题也是关于ShowMessage的)。对于常规的Delphi表单,我将尝试查看应用程序对象或尝试编写TForm helper,而不是任何窗口。只有顶层无主窗口。我的观点更多的是关于再创造。在窗体的生命周期中,您会多次收到这些通知,而不是在最初创建窗体时。@DavidHeffernan此挂钩适用于调用进程的任何事件:新建窗口、nwe keybd布局等(还记得我关于win taskbar的问题吗?这是其中的一部分)。我知道。我自己也用同样的钩子。我只是指出,它不会一次触发,而且只有在创建Delphi表单时才会触发。