About/Contact

Steve Trefethen

Steve Trefethen is a Director of Engineering at Reply. Contact me

View my LinkedIn profile


Powered by discountASP.NET
referal ID: sdtref
Why recommend discountASP.NET?
$720 in referrals so far!


Calendar

<<  February 2012  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
2728291234
567891011

View posts in large calendar

Disclaimer

The posts on this weblog are provided AS IS with no warranties, and confer no rights. The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.



User handle leak in TOleControl.CMDialogKey calling IOleControl.GetControlInfo

March 23 2006 5:22PM
In versions of Delphi prior to Delphi 2006 there is a bug in TOleControl.CMDialogKey which can cause a USER handle leak when certain keys are pressed. The issue is that the method always calls IOleControl.GetControlInfo(...) which takes a CONTROLINFO structure that has an hAccel member which is, according to MSDN, a:
Handle to an array of Windows ACCEL structures, each structure describing a keyboard mnemonic. The array is allocated with the GlobalAlloc function. The control always maintains the memory for this array; the caller of IOleControl::GetControlInfo should not attempt to free the memory.

The problem with calling IOleControl.GetControlInfo is that each time it's called you get a new Windows USER handle allocated. In Delphi 2005, the problem is apparent when the Welcome page is visible and you press the Enter key when the focus is on some other window like the structure pane. This results in the "loss" of a Windows USER handle with each keypress. In Delphi 2006, we've addressed this by adding a TControlInfo data member to TOleControl and caching the result from the first call to IOleControl.GetControlInfo in TOleControl.CMDialogKey. So, for example if you've been using the TWebBrowser control and are experiencing loss of Windows USER handles at an alarming rate this could/should help explain why.

Update #1:
To be perfectly clear, this bug was fixed in TOleControl in the RTM release of BDS 2006 which means subsequently the TWebBrowser component no longer suffers from this problem.
Update #2:
Here is the code that was changed to correct this problem:

Add the following data member to TOleControl:

  TOleControl = class(TWinControl, IUnknown, IOleClientSite,
IOleControlSite, IOleInPlaceSite, IOleInPlaceFrame, IDispatch,
IPropertyNotifySink, ISimpleFrameSite, IServiceProvider)
private
...
FControlInfo: TControlInfo; // Added new data member
...
end;
Change TOleControl.CreateControl by inserting the following two lines (marked below):
procedure TOleControl.CreateControl;
var
Stream: IStream;
CS: IOleClientSite;
X: Integer;
begin
if FOleControl = nil then
try
try // work around ATL bug
...
OleCheck(FOleObject.QueryInterface(IOleControl, FOleControl));
FControlInfo.cb := SizeOf(FControlInfo); //*** Inserted ***
FOleControl.GetControlInfo(FControlInfo); //*** Inserted ***
OleCheck(FOleObject.QueryInterface(IDispatch, FControlDispatch));
...
except
DestroyControl;
raise;
end;
end;
Change the TOleControl.CMDialogKey method to read:
procedure TOleControl.CMDialogKey(var Message: TMessage);
var
Msg: TMsg;
Cmd: Word;
begin
if CanFocus then
begin
if (FControlInfo.cAccel <> 0) then
begin
FillChar(Msg, SizeOf(Msg), 0);
Msg.hwnd := Handle;
Msg.message := WM_KEYDOWN;
Msg.wParam := Message.WParam;
Msg.lParam := Message.LParam;
if IsAccelerator(FControlInfo.hAccel,
FControlInfo.cAccel, @Msg, Cmd) then
begin
FOleControl.OnMnemonic(@Msg);
Message.Result := 1;
Exit;
end;
end;
end;
inherited;
end;
That's it. Now, when TOleControl.CMDialogKey is called it won't try to fetch the control info again and thus prevents the USER handle lleak.

FacebookDel.icio.usDigg It!

Tags:

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading