如何知道表单是否已创建?

时间:2013-06-11 11:00:22

标签: delphi runtime oncreate lazarus

我想找到一种方法来了解表单是在运行时创建的(或销毁的)。 这适用于Delphi或fpc。 非常感谢

PS:有没有办法检索所有对象的信息?

3 个答案:

答案 0 :(得分:5)

  

我希望有一个事件告诉我一个新对象刚刚在运行时创建(或被破坏)。

创建或销毁对象时,不会触发内置事件。

因为我喜欢编写代码钩子,所以我提供以下单元。这会挂钩_AfterConstruction单元中的System方法。理想情况下它应该使用蹦床但我从未学会如何实施这些。如果您使用了真正的挂钩库,那么您可以做得更好。无论如何,这是:

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分配一个处理程序,只要创建了一个对象,就会调用该处理程序。

我将它作为练习留给读者添加OnBeforeDestruction事件处理程序。

请注意,我并不是说这种做法是件好事。我只是回答你提出的直接问题。您可以自己决定是否要使用它。我知道我不会这样做!

答案 1 :(得分:0)

使用TForm的{​​{1}}事件以您想要的任何方式通知您。

答案 2 :(得分:0)

在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声明)。