[TC 8.01 RC3 x32] Unwanted text selection in Search-dialog

The behaviour described in the bug report is either by design, or would be far too complex/time-consuming to be changed

Moderators: Hacker, petermad, Stefan2, white

User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

The cause of this problem is really inside system COMBOBOX class, there are complaints in the Internet about this. Interestingly, this problem occurs only under Windows NT family - does not occur under Windows 9x family. There must be also at least one string added to the drop-down list to see this problem.

There is a simple workaround. It could be even simpler, but Delphi 2 (in opposite to more recent Delphi versions) caused massive flickering during resizing. So here is a fully compatible solution (note: typecasting to HINST(@...) is to maintain compatibility with both 32-bit and 64-bit code). Tested with Win2k and WinXP - as 32-bit code, but should also work as 64-bit without any problems.

Add declarations to the TMyComboBox class definition:

Code: Select all

TMyComboBox = class(TComboBox)
...
...
  protected
    procedure CreateWnd; override;
    procedure WMDestroy(var Message : TWMDestroy); message WM_DESTROY;
    procedure WMSize(var Message : TWMSize); message WM_SIZE;
  private
    OrigEditProc : Pointer;
    ResizeCounter : Integer;
    CurrentSelectionStart : Integer;
    CurrentSelectionEnd : Integer;
...
...
end;
Declare:

Code: Select all

{Subclassed window procedure for internal edit control - overrides new selection}
function SubclassedEditProc(Window : HWND; MessageCode : UINT; wParam : WPARAM; lParam : LPARAM) : LRESULT; stdcall;
begin
  with TMyComboBox(FindControl(GetParent(Window))) do
  begin
    if MessageCode = EM_SETSEL then
    if ResizeCounter <> 0 then
    begin
      wParam:=CurrentSelectionStart;
      lParam:=CurrentSelectionEnd;
    end;
    
    if not IsWindowUnicode(Window) then
      Result:=CallWindowProcA(OrigEditProc,Window,MessageCode,wParam,lParam)
    else
      Result:=CallWindowProcW(OrigEditProc,Window,MessageCode,wParam,lParam);
  end;
end;

{Subclassing internal edit control}
procedure TMyComboBox.CreateWnd;
begin
  inherited;
  if Win32Platform = VER_PLATFORM_WIN32_NT then
  if EditHandle <> 0 then
  begin
    OrigEditProc:=Pointer(GetWindowLong(EditHandle,GWL_WNDPROC));
    SetWindowLong(EditHandle,GWL_WNDPROC,HINST(@SubclassedEditProc));
  end;
end;

{Unsubclassing internal edit control}
procedure TMyComboBox.WMDestroy(var Message : TWMDestroy);
begin
  if Win32Platform = VER_PLATFORM_WIN32_NT then
  if EditHandle <> 0 then
    SetWindowLong(EditHandle,GWL_WNDPROC,HINST(OrigEditProc));
  inherited;
end;

{Combobox resize handler - remembers current selection}
procedure TMyComboBox.WMSize(var Message : TWMSize);
begin
  Inc(ResizeCounter);
  try
    Perform(CB_GETEDITSEL,HINST(@CurrentSelectionStart),HINST(@CurrentSelectionEnd));
    inherited;
  finally
    Dec(ResizeCounter);
  end;
end;
Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50541
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Thanks for your suggestion. So essentially you intercept the fake EM_SETSEL messages received while resizing - nice idea!
Author of Total Commander
https://www.ghisler.com
Post Reply