Ustawianie focusa na moją aplikację

0

Witam:)

Muszę zrobić programik, który ma wykrywać zmianę zawartości schowka w następujący sposób:

jak przełączę się na dowolny inny program (aktywuję jego okno) i skopiuję w nim coś do schowka,
to mój program powinien to wyłapać i pokazać jakiś tam komunikat, który ma mieć focusa.
Po zatwierdzeniu komunikatu focus ma być z powrotem przywrócony na okno aplikacji, w której
skopiowałem coś do schowka.

Zrobiłem to w taki sposób, że aby przy aktywnym innym oknie i po wykryciu zmiany zawartości schowka
MessageBox miał focusa, to najpierw nadaję focusa mojej aplikacji, a potem wyświetlam komunikat.
Działa to pięknie jeśli mój program jest uruchomiony spod Delphi, a nie działa jak odpalam go bezpośrednio
spod powłoki systemowej (explorera), tzn. moja aplikacja nie ustawia ani sobie focusa, ani MessageBox-owi,
tylko po zmianie zawartości schowka miga jej belka na pasku zadań. Oto mój (typowy) kod do tego zadania:

 private
      FClipboardOwner: HWnd;
      procedure WMChangeCBChain(var Msg: TWMChangeCBChain); message WM_CHANGECBCHAIN;
      procedure WMDrawClipboard(var Msg: TWMDrawClipboard); message WM_DRAWCLIPBOARD;

//--------

 procedure TForm1.FormCreate(Sender: TObject); 
 begin
   FClipboardOwner:=SetClipboardViewer(Handle);
 end;

 procedure TForm1.FormDestroy(Sender: TObject);
 begin
   ChangeClipboardChain(Handle, FClipboardOwner);
 end;

procedure TForm1.WMChangeCBChain(var Msg: TWMChangeCBChain);
begin
  if Msg.Remove = FClipboardOwner then FClipboardOwner := Msg.Next
  else SendMessage(FClipboardOwner, WM_CHANGECBCHAIN, Msg.Remove, Msg.Next);
  Msg.Result := 0;
end;

procedure TForm1.WMDrawClipboard(var Msg: TWMDrawClipboard);
 Var
  OstatnioAktywneOkno: HWnd;
begin
  SendMessage(FClipboardOwner, WM_DRAWCLIPBOARD, 0, 0);
  Msg.Result := 0;
  OstatnioAktywneOkno:=GetForegroundWindow;  // zapamiętanie uchwytu ostatnio aktywnego okna
  SetForegroundWindow(Handle);  // ustawienie focusa na moją aplikację
  Application.MessageBox(PChar('Cos tam nowego trafiło do schowka.'), ' Info',mb_OK+mb_IconInformation+MB_TOPMOST);
  SetForegroundWindow(OstatnioAktywneOkno);  // ustawienie focusa z powrotem na okno, które było przedtem aktywne
end;

Skoro działa spod środowiska, a nie działa gdy uruchomione bezpośrednio, to znaczy, że środowisko wpływa jakoś
"pozytywnie" na działanie programu. Coś mi się kiedyś obiło o uszy, że trzeba coś z tymi uchwytami pokombinować.

Proszę o poradę.

Pzdr.
Marogo

0

Znalazłem już rozwiązanie [!!!] Problem ten jest powszechny od czasów Win98, tzn. M$ zablokował
możliwość wyrzucania własnego okna aplikacji na wierzch gdy jest aktywne okno innej aplikacji,
jedynie widać miganie belki na pasku zadań.

Tak dla potomnych: oto kodzik, który wymusza ustawienie focusa na belkę naszego programu
(bez migania) i ustawia jego okno na wierzchu, co także pozwala wyświetlić MessageBox-a
mającego focusa. Wywołanie tej funkcji wstawiamy w miejsce funkcji SetForegroundWindow(Handle).

Function ForceForegroundWindow(Const hWnd: THandle): Boolean;
 Var
  hCurWnd: THandle;
Begin
 Result:=False;
 If Not IsWindow(hWnd) then Exit;
 hCurWnd:=GetForegroundWindow;
 If hCurWnd=hWnd then
   Begin
     Result:=True;
     Exit;
   End;
 If (GetWindowLong( hWnd, GWL_STYLE ) and WS_MINIMIZE)<>0 then ShowWindow(hWnd, SW_SHOWNOACTIVATE);
 AttachThreadInput(GetWindowThreadProcessId(hCurWnd,nil), GetCurrentThreadId, True);
 SetForegroundWindow(hWnd);
 AttachThreadInput(GetWindowThreadProcessId(hCurWnd,nil), GetCurrentThreadId, False);
 Result:=GetForegroundWindow=hWnd;
end;

Pzdr. :d
Marogo

1 użytkowników online, w tym zalogowanych: 0, gości: 1