Domanda

Lo sfondo: La mia forma ha un TWebBrowser. Voglio chiudere il modulo con ESC ma il TWebBrowser mangia le sequenze di tasti -. Così ho deciso di andare con un hook di tastiera

Il problema è che la forma può essere aperto in più istanze allo stesso tempo.

Non importa quello che faccio, in alcune situazioni, se ci sono due istanze aperte della mia forma, chiudendo uno di loro chiude l'altro pure.

Ho allegato alcuni esempi di codice. Tutte le idee su ciò che causa il problema?

var
  EmailDetailsForm: TEmailDetailsForm;
  KeyboardHook: HHook;

implementation

function KeyboardHookProc(Code: Integer; wParam, lParam: LongInt): LongInt; stdcall;
var
  hWnd: THandle;
  I: Integer;
  F: TForm;
begin
  if Code < 0 then
    Result := CallNextHookEx(KeyboardHook, Code, wParam, lParam)
  else begin
    case wParam of
      VK_ESCAPE:  
        if (lParam and $80000000) <> $00000000 then
        begin
          hWnd := GetForegroundWindow;
          for I := 0 to Screen.FormCount - 1 do
          begin
            F := Screen.Forms[I];
            if F.Handle = hWnd then
              if F is TEmailDetailsForm then
              begin
                PostMessage(hWnd, WM_CLOSE, 0, 0);
                Result := HC_SKIP;
                break;
              end;
          end; //for
        end; //if
      else
        Result := CallNextHookEx(KeyboardHook, Code, wParam, lParam);
    end;  //case
  end;  //if
end;

function TEmailDetailsForm.CheckInstance: Boolean;
var
  I, J: Integer;
  F: TForm;
begin
  Result := false;

  J := 0;

  for I := 0 to Screen.FormCount - 1 do
  begin
    F := Screen.Forms[I];
    if F is TEmailDetailsForm then
    begin
      J := J + 1;
      if J = 2 then
      begin
        Result := true;
        break;
      end;
    end;
  end;
end;

procedure TEmailDetailsForm.FormCreate(Sender: TObject);
begin
    if not CheckInstance then    
      KeyboardHook := SetWindowsHookEx(WH_KEYBOARD, @KeyboardHookProc, 0, GetCurrentThreadId());
end;

procedure TEmailDetailsForm.FormDestroy(Sender: TObject);
begin
    if not CheckInstance then
      UnHookWindowsHookEx(KeyboardHook);
end;
È stato utile?

Soluzione

Si potrebbe fare questo con TApplicationEvents.OnMessage invece. Eliminare un componente TApplicationEvents sulla forma principale dell'applicazione con questo codice:

procedure TMainForm.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  C: TControl;
  H: HWND;
begin
  if (Msg.message = WM_KEYDOWN) and (Msg.wParam = VK_ESCAPE) then begin
    H := Msg.hwnd;
    while GetParent(H) <> 0 do
      H := GetParent(H);
    C := FindControl(H);
    if C is TEmailDetailsForm then begin
      TEmailDetailsForm(C).Close;
      Handled := True;
    end;
  end;
end;

Se si desidera continuare a utilizzare un hook di tastiera, invece, si deve collegare solo una volta, piuttosto che una sola volta per ogni forma, soprattutto perché si sta sovrascrivendo una variabile globale. Prova ad aggiungere una variabile globale HookCount, e solo agganciare / sganciare se è l'unica forma.

scroll top