I tried several systems with strange results:
- on my windows XP 64 pc the dialog closes when the list drops out
- in Windows XP Pro on the VMware virtual machine the dialog closes too
but
- the dialog does not close on my laptop with Windows 7
- in Windows 2000 Pro, the dialog does not close in the VMware virtual machine
Since this is so unstable, I decided to write a small component that forces the correct behavior, even if the OS does not provide it.
The component can be used as follows:
procedure TForm2.FormCreate(Sender: TObject); const SHACF_FILESYS_DIRS = $00000020; begin SHAutoComplete(Edit1.Handle, SHACF_FILESYS_DIRS or SHACF_USETAB); fAutoSuggestDropdownChecker := TAutoSuggestDropdownChecker.Create(Self); end; procedure TForm2.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_ESCAPE then begin if not fAutoSuggestDropdownChecker.DroppedDown then ModalResult := mrCancel; end; end;
but it is important that the Cancel button does not have the Cancel property property.
The component itself works by connecting to the processing of application messages and using the window enumeration for the current thread to check the visible window with the name of the class "Automatic deployment proposal". If it exists and is displayed, then the automatic completion list will be omitted.
unit uAutoSuggestDropdownCheck; interface uses Windows, Classes, Messages, Forms; type TAutoSuggestDropdownChecker = class(TComponent) private fDroppedDown: boolean; fSaveMessageEvent: TMessageEvent; procedure AppOnMessage(var AMsg: TMsg; var AHandled: Boolean); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property DroppedDown: boolean read fDroppedDown; end; implementation //////////////////////////////////////////////////////////////////////////////// function EnumThreadWindowsProc(AWnd: HWND; AParam: LPARAM): BOOL; stdcall; var WndClassName: string; FoundAndVisiblePtr: PInteger; begin SetLength(WndClassName, 1024); GetClassName(AWnd, PChar(WndClassName), Length(WndClassName)); WndClassName := PChar(WndClassName); if WndClassName = 'Auto-Suggest Dropdown' then begin FoundAndVisiblePtr := PInteger(AParam); FoundAndVisiblePtr^ := Ord(IsWindowVisible(AWnd)); Result := False; end else Result := True; end; function IsAutoSuggestDropdownVisible: boolean; var FoundAndVisible: integer; begin FoundAndVisible := 0; EnumThreadWindows(GetCurrentThreadId, @EnumThreadWindowsProc, LParam(@FoundAndVisible)); Result := FoundAndVisible > 0; end; //////////////////////////////////////////////////////////////////////////////// // TAutoSuggestDropdownChecker //////////////////////////////////////////////////////////////////////////////// constructor TAutoSuggestDropdownChecker.Create(AOwner: TComponent); begin inherited Create(AOwner); fSaveMessageEvent := Application.OnMessage; Application.OnMessage := AppOnMessage; end; destructor TAutoSuggestDropdownChecker.Destroy; begin if (TMethod(fSaveMessageEvent).Code = TMethod(Application.OnMessage).Code) and (TMethod(fSaveMessageEvent).Data = TMethod(Application.OnMessage).Data) then begin Application.OnMessage := fSaveMessageEvent; end; fSaveMessageEvent := nil; inherited; end; procedure TAutoSuggestDropdownChecker.AppOnMessage(var AMsg: TMsg; var AHandled: Boolean); begin if ((AMsg.message >= WM_KEYFIRST) and (AMsg.message <= WM_KEYLAST)) or ((AMsg.message >= WM_MOUSEFIRST) and (AMsg.message <= WM_MOUSELAST)) or (AMsg.message = WM_CANCELMODE) then fDroppedDown := IsAutoSuggestDropdownVisible end; end.
The code posted here is just a proof of concept, but can serve as a starting point for those struggling with the same problem.
source share