2010. december 6., hétfő

How to remove the client edge of a MDI parent form


Problem/Question/Abstract:

How to remove the client edge of a MDI parent form

Answer:

Apparently, in Delphi 4, the logic for the MDI client window edge was changed. If you have the source for Forms.pas, you can see the MDI client window procedure (TCustomForm.ClientWndProc) explicitly changes the client edge on a certain mysterious message ($3F) by calling ShowMDIClientEdge.

Unfortunately, simply replacing the client window procedure doesn't work well. I've finally been able to work out a hack, that replaces the client window procedure, and changes the form style on the fly. This makes sure the form's FormStyle property is not fsMDIForm when the client window procedure wants to call ShowMDIClientEdge, which it does only if the FormStyle property is fsMDIForm. When the FormStyle property changes, however, the window is destroyed (to be recreated when needed). To prevent this, I've overriden the DestroyWnd method.

The following unit is my MDI main form, displayed without a sunken edge:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FUpdating: Boolean;
    OldWndProc: TFarProc;
    NewWndProc: Pointer;
    procedure ClientWndProc(var Message: TMessage);
  protected
    procedure DestroyWnd; override;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.ClientWndProc(var Message: TMessage);

  procedure DefProc;
  begin
    with Message do
      Result := CallWindowProc(OldWndProc, ClientHandle, Msg, wParam, lParam);
  end;

begin
  if Message.Msg = $3F then
  begin
    FUpdating := True;
    FormStyle := fsNormal;
    DefProc;
    FormStyle := fsMDIForm;
    FUpdating := False;
  end
  else
    DefProc;
end;

procedure TForm1.DestroyWnd;
begin
  if not FUpdating then
    inherited DestroyWnd;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  OldWndProc := Pointer(GetWindowLong(ClientHandle, GWL_WNDPROC));
  NewWndProc := MakeObjectInstance(ClientWndProc);
  SetWindowLong(ClientHandle, GWL_WNDPROC, Longint(NewWndProc));
  SetWindowLong(ClientHandle, GWL_EXSTYLE, GetWindowLong(ClientHandle,
    GWL_EXSTYLE) and not WS_EX_CLIENTEDGE);
  SetWindowPos(ClientHandle, 0, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE
    or SWP_NOSIZE or SWP_NOZORDER or SWP_FRAMECHANGED);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if Pointer(GetWindowLong(ClientHandle, GWL_WNDPROC)) = NewWndProc then
  begin
    SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(OldWndProc));
    FreeObjectInstance(NewWndProc);
  end;
end;

end.

Nincsenek megjegyzések:

Megjegyzés küldése