win32: redirect messages sent by win32 after call to DestroyWindow to a specific window proc (disabled by default through a define). Those messages can lead to access to LCL objects after destruction with potential crashes.

git-svn-id: trunk@34377 -
This commit is contained in:
blikblum 2011-12-24 01:08:30 +00:00
parent 3c74914f9c
commit 9c630b6274
5 changed files with 83 additions and 17 deletions

View File

@ -209,6 +209,18 @@ begin
Result := Result or (Assigned(AWinControl) and ([csParentBackground, csOpaque] * AWinControl.ControlStyle = [csParentBackground]));
end;
procedure DisposeComboEditWindowInfo(ComboBox: TCustomComboBox);
var
Buddy: HWND;
Info: TComboboxInfo;
begin
Info.cbSize := SizeOf(Info);
Win32Extra.GetComboBoxInfo(Combobox.Handle, @Info);
Buddy := Info.hwndItem;
if (Buddy <> Info.hwndCombo) and (Buddy <> 0) then
DisposeWindowInfo(Buddy);
end;
{------------------------------------------------------------------------------
Function: WindowProc
Params: Window - The window that receives a message
@ -605,21 +617,6 @@ var
end;
end;
procedure DisposeComboEditWindowInfo(ComboBox: TCustomComboBox);
var
Buddy: HWND;
Info: TComboboxInfo;
begin
Info.cbSize := SizeOf(Info);
Win32Extra.GetComboBoxInfo(Combobox.Handle, @Info);
if Info.hwndItem <> Info.hwndCombo then
Buddy := Info.hwndItem
else
Buddy := 0;
if Buddy <> 0 then
DisposeWindowInfo(Buddy);
end;
procedure HandleScrollMessage(LMsg: integer);
var
ScrollInfo: TScrollInfo;
@ -1037,7 +1034,8 @@ begin
WindowInfo^.IMEComposed:=True;
// filter messages we want to pass on to LCL
if (Msg <> WM_KILLFOCUS) and (Msg <> WM_SETFOCUS) and (Msg <> WM_NCDESTROY)
if (Msg <> WM_KILLFOCUS) and (Msg <> WM_SETFOCUS)
{$ifndef RedirectDestroyMessages}and (Msg <> WM_NCDESTROY){$endif}
and not ((Msg >= WM_CUT) and (Msg <= WM_CLEAR))
and ((Msg < WM_KEYFIRST) or (Msg > WM_KEYLAST))
and ((Msg < WM_MOUSEFIRST) or (Msg > WM_MOUSELAST)) then
@ -1373,6 +1371,7 @@ begin
begin
LMessage.Msg := LM_CUT;
end;
{$ifndef RedirectDestroyMessages}
WM_DESTROY:
begin
if CurrentWindow=Window then
@ -1383,6 +1382,7 @@ begin
Windows.DestroyWindow(WindowInfo^.Overlay);
LMessage.Msg := LM_DESTROY;
end;
{$endif}
WM_DESTROYCLIPBOARD:
begin
if assigned(OnClipBoardRequest) then begin
@ -2449,6 +2449,7 @@ begin
if MouseDownFocusStatus = mfFocusSense then
MouseDownFocusStatus := mfNone;
end;
{$ifndef RedirectDestroyMessages}
WM_NCDESTROY:
begin
// free our own data associated with window
@ -2456,6 +2457,7 @@ begin
WindowInfo := nil;
EnumProps(Window, @PropEnumProc);
end;
{$endif}
end;
end;
@ -2648,6 +2650,57 @@ begin
end;
end;
{$ifdef RedirectDestroyMessages}
{------------------------------------------------------------------------------
Function: DestroyWindowProc
Params: Window - The window that receives a message
Msg - The message received
WParam - Word parameter
LParam - Long-integer parameter
Returns: 0 if Msg is handled; non-zero long-integer result otherwise
Handles messages after handle is destroyed
------------------------------------------------------------------------------}
function DestroyWindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
LParam: Windows.LParam): LResult; stdcall;
var
LMessage: TLMessage;
WindowInfo: PWin32WindowInfo;
lWinControl: TWinControl;
begin
CallDefaultWindowProc(Window, Msg, WParam, LParam);
case Msg of
WM_DESTROY:
begin
WindowInfo := GetWin32WindowInfo(Window);
if WindowInfo^.isChildEdit then
lWinControl := WindowInfo^.AWinControl
else
lWinControl := WindowInfo^.WinControl;
if CurrentWindow = Window then
CurrentWindow := 0;
if lWinControl is TCustomComboBox then
DisposeComboEditWindowInfo(TCustomComboBox(lWinControl));
if WindowInfo^.Overlay<>HWND(nil) then
Windows.DestroyWindow(WindowInfo^.Overlay);
if lWinControl <> nil then
begin
FillChar(LMessage, SizeOf(LMessage), 0);
LMessage.Msg := LM_DESTROY;
DeliverMessage(lWinControl, LMessage);
end;
end;
WM_NCDESTROY:
begin
// free our own data associated with window
DisposeWindowInfo(Window);
EnumProps(Window, @PropEnumProc);
end;
end;
end;
{$endif}
{------------------------------------------------------------------------------
Procedure: TimerCallBackProc
Params: window_hnd - handle of window for timer message, not set in this implementation

View File

@ -41,4 +41,5 @@
{$ENDIF}
{$ENDIF}
{$DEFINE UseVistaDialogs}
{$DEFINE UseVistaDialogs}
{.$DEFINE RedirectDestroyMessages}

View File

@ -237,6 +237,10 @@ function WindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
LParam: Windows.LParam): LResult; stdcall;
function CallDefaultWindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
LParam: Windows.LParam): LResult;
{$ifdef RedirectDestroyMessages}
function DestroyWindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
LParam: Windows.LParam): LResult; stdcall;
{$endif}
implementation

View File

@ -82,7 +82,12 @@ begin
DeleteObject(FDotsPatternBitmap);
if FAppHandle <> 0 then
begin
{$ifdef RedirectDestroyMessages}
SetWindowLong(FAppHandle, GWL_WNDPROC, PtrInt(@DestroyWindowProc));
{$endif}
DestroyWindow(FAppHandle);
end;
if UnicodeEnabledOS then
begin

View File

@ -574,6 +574,9 @@ var
Handle: HWND;
begin
Handle := AWinControl.Handle;
{$ifdef RedirectDestroyMessages}
SetWindowLong(Handle, GWL_WNDPROC, PtrInt(@DestroyWindowProc));
{$endif}
DestroyWindow(Handle);
end;