Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi WH_CALLWNDPROC-Hook // SystemMenu-Items (https://www.delphipraxis.net/111962-wh_callwndproc-hook-systemmenu-items.html)

bepe 12. Apr 2008 10:29


WH_CALLWNDPROC-Hook // SystemMenu-Items
 
Hallo,

ich habe mir mittels Hooks eine kleine Hilfskomponente gebastelt, welche mir zur Laufzeit ein par Eigenschaften zu meinen Controls anzeigt und ggf. ändert. Einige Funktionen habe ich in das Systemmenü meines Programms eingebunden. Nun wüsste ich gerne wann diese ausgewählt/angeklickt werden.

So:

Delphi-Quellcode:
const
  MeinMenuItem = 4711;

procedure WMSysCommand(var Msg: TMessage); message WM_SYSCOMMAND;
...
procedure TForm1.WMSysCommand(var Msg: TMessage);
begin
  inherited;
  if (Msg.wParam shr 16) = 0 then
  begin
    case Word(Msg.wParam) of
      MeinMenuItem: MessageBox(0, 'MeinItem', '', 0);
      SC_MINIMIZE: MessageBox(0, 'Minimize', '', 0);
    end;
  end;
end;
...funktioniert alles, immer wunderbar. Auch mit meinen eigenen MenuItems. Ich möchte aber meine Programme nicht anpassen müssen und habe deshalb in meiner Komponente ein WH_CALLWNDPROC-Hook eingebaut:

Delphi-Quellcode:
...
wndHook := SetWindowsHookEx(WH_CALLWNDPROC, @WndProc, 0, GetCurrentThreadId);
...
function WndProc(nCode : Integer; wParam: longint; lParam : longint): LRESULT; stdcall;
var
  cwps: TCWPStruct;
begin
  if (nCode = HC_ACTION) then
  begin
    CopyMemory(@cwps, Pointer(lParam), SizeOf(CWPSTRUCT));
    case cwps.message of
      WM_SYSCOMMAND:
      begin
        if (cwps.wParam shr 16) = 0 then
        begin
          case Word(cwps.wParam) of
            MeinMenuItem: MessageBox(0, 'MeinItem', '', 0);
            SC_MINIMIZE: MessageBox(0, 'Minimize', '', 0);
          end;
        end;
      end;
    end;
  end;
  Result := CallNextHookEx(wndHook, nCode, wParam, lParam);
end;
Das funktioniert nur mit "Minimieren" aber bei meinen eigenen Items erhalte ich keine Botschaft (zumindest kein WM_SYSCOMMAND).

Das funktioniert nicht immer. Wähle ich jetzt im Menü "Minimieren" wird das Programm minimiert aber ich erhalte keine Botschaft (zumindest kein WM_SYSCOMMAND). Klicke ich im Titel auf den entsprechenden Button, greift mein Hook.

Hat jemand eine Idee woran das liegen könnte oder ob es Alternativen für mich gibt? Bisher nur auf einem Vista32 ausprobiert... Im Netz findet man ja einige unterschiedliche Ansätze um den Hook zu implementieren. Bei allen hatte ich das gleiche Verhalten.

EDIT:
Hatte Unsinn im Quelltext, daher habe ich die Problemschilderung korrigiert..

Macci 12. Apr 2008 13:51

Re: WH_CALLWNDPROC-Hook // SystemMenu-Items
 
Wie ist im 2. Beispiel von dir denn MeinMenuItem definiert? Versuch doch mal einen expliziten Aufruf über CallWindowProc mit MeinMenuItem als entsprechendem Parameter. Wenns dann klappt, weisst du jedenfalls, dass der Fehler nicht an dem gerade eben von dir gepostetem Code liegt. :-)

bepe 12. Apr 2008 15:14

Re: WH_CALLWNDPROC-Hook // SystemMenu-Items
 
Zitat:

Wie ist im 2. Beispiel von dir denn MeinMenuItem definiert?
Meinst du die Konstante? Wie im Ersten:

Delphi-Quellcode:
const
  MeinMenuItem = 4711;
Und so füge ich ins Menü ein:

Delphi-Quellcode:
var
  hMenu: THandle;
begin
  hMenu := GetSystemMenu(Application.MainFormHandle, False);
  if hMenu <> 0 then
  begin
    InsertMenu(hMenu, 0, MF_BYPOSITION, MeinMenuItem, 'MeinItem');
    DrawMenuBar(hMenu);
  end;

Zitat:

Versuch doch mal einen expliziten Aufruf über CallWindowProc mit MeinMenuItem
Das habe ich jetzt ausprobiert und funktioniert wunderbar. (Naja, beim CallNextHookEx kommt eine AV. Aber Ereignis kommt an und wird korrekt verarbeitet.)

Delphi-Quellcode:
var
  cwps: TCWPStruct;
begin
  cwps.message := WM_SYSCOMMAND;
  cwps.wParam := MeinMenuItem;
  WndProc(HC_ACTION, 0, Integer(@cwps));

Zitat:

Wenns dann klappt, weisst du jedenfalls, dass der Fehler nicht an dem gerade eben von dir gepostetem Code liegt.
Da bin ich mir nicht ganz sicher. Wenn in meiner WndProc etwas falsch ist werde ich die Parameter wohl nicht verstanden haben. Somit wäre dann auch mein Aufruf fehlerhaft..

Aber danke..

EDIT:
OK, wer beim Lesen die Augen öffnet ist klar im Vorteil. Du hast CallWindowProc gesagt und nicht direkter Aufruf, also:

Delphi-Quellcode:
var
  cwps: TCWPStruct;
begin
  cwps.message := WM_SYSCOMMAND;
  cwps.wParam := MeinMenuItem;
  CallWindowProc(@WndProc, Application.MainFormHandle, WM_SYSCOMMAND, 0, Integer(@cwps));
Er geht wieder in meine WndProc, ich bekomme wieder eine AV beim CallNextHookEx. Aber er ich habe keine Ahnung wie ich HC_ACTION übergeben könnte. Daher greift meine Behandlung nicht...

Macci 12. Apr 2008 15:45

Re: WH_CALLWNDPROC-Hook // SystemMenu-Items
 
Hi,

bist du dir schon sicher, dass dein WndProc richtig definiert ist? Hooks habe ich ehrlichgesagt erst einmal gebraucht (um TerminateProcess zu hooken), ist aber schon lange her, deswegen weiss ich da nicht mehr so gut bescheid.

In Delphi habe ich das WndProc auch noch nie wirklich gebraucht, in C++ geht es aber soo:

Code:
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Bei dir sind die Parameter ja etwas anders:
Delphi-Quellcode:
WndProc(nCode : Integer; wParam: longint; lParam : longint): LRESULT
Und so würde auf das Systemmenü zugreifen:

Code:
     hMenu = GetSystemMenu (hwnd, FALSE) ;
     
     AppendMenu (hMenu, MF_SEPARATOR, 0,          NULL) ;
     AppendMenu (hMenu, MF_STRING, IDM_SYS_ABOUT, TEXT ("Info über...")) ;
     AppendMenu (hMenu, MF_STRING, IDM_SYS_HELP,  TEXT ("Hilfe...")) ;
     AppendMenu (hMenu, MF_STRING, IDM_SYS_REMOVE, TEXT ("Erweiterungen recyceln")) ;

....

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     switch (message)
     {
     case WM_SYSCOMMAND:
          switch (LOWORD (wParam))
          {
          case IDM_SYS_ABOUT:
               MessageBox (hwnd, TEXT ("Ein Menü für arme Leute\n")
                                 TEXT ("(c) Charles Petzold, 1998"),
                           szAppName, MB_OK | MB_ICONINFORMATION) ;
               return 0 ;
               
          case IDM_SYS_HELP:
               MessageBox (hwnd, TEXT ("Hilfestellung noch nicht implementiert!"),
                           szAppName, MB_OK | MB_ICONEXCLAMATION) ;
               return 0 ;
               
          case IDM_SYS_REMOVE:
               GetSystemMenu (hwnd, TRUE) ; // zurück zum Original
               return 0 ;
          }
          break ;
         
     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}
(aus dem Buch "Windows Programmierung - 5. Auflage")

sx2008 12. Apr 2008 15:55

Re: WH_CALLWNDPROC-Hook // SystemMenu-Items
 
Mach dir das Leben doch nicht so schwer !
Es gibt eine Komponente, der gibt man einfach ein PopupMenu mit, und sie zeigt alle Items als System-Menu an. Natürlich braucht man sich selbst nicht um Windows Messages kümmern, sondern bekommt einen Klick im Menu als Event geliefert.
Leider ist Torry's gerade down, aber dort gibt es die Komponente.

jbg 12. Apr 2008 15:55

Re: WH_CALLWNDPROC-Hook // SystemMenu-Items
 
Zitat:

Zitat von bepe
Bisher nur auf einem Vista32 ausprobiert...

Na dann viel Spaß unter einem 64 Bit System.
Warum man kein WH_CALLWNDPROC hook installieren sollte (Engl.)

bepe 12. Apr 2008 16:13

Re: WH_CALLWNDPROC-Hook // SystemMenu-Items
 
Danke euch dreien aber leider noch keine Lösung in sicht :-D

@jbg:
Von dem Problem habe ich bei meiner Suche auch schon gelesen. Aber das ist für mich irrelevant. Die Komponente wird ja nur während der Entwicklung benötigt, danach wird sie wieder entfernt. Daher ja auch der Umweg über ein Hook.

@sx2008:
Cool, das wäre natürlich auch eine Alternative. Sobald Torry wieder da ist :( Aber mich würde dennoch intressieren was mein Problem ist.

@Macci:
Danke für deine Mühen. Die Unterschiede sind Hook bedingt. Der nCode gibt an ob ich auf die Nachricht reagieren darf/sollte. Dein Source scheint eine Hook freie Variante zu sein. Also doch das mein MainForm bearbeiten.

bepe 12. Apr 2008 16:29

Re: WH_CALLWNDPROC-Hook // SystemMenu-Items
 
Zitat:

Mach dir das Leben doch nicht so schwer !
Gute Idee, habe den Hook entfernt und mache es jetzt doch, mehr oder weniger, wie von Macci gezeigt. Ich überschreibe/tausche einfach die Proc vom MainForm.

Delphi-Quellcode:
...
  FWndBackup := Pointer(GetWindowLong(Application.MainFormHandle, GWL_WNDPROC));
  SetWindowLong(Application.MainFormHandle, GWL_WNDPROC, Integer(@WndProc2));
...

function WndProc2(WND: hwnd; Msg: LongInt; wParam: longint; lParam : longint): LRESULT; stdcall;
begin
  Result := CallWindowProc(FWndBackup, Wnd, Msg, wParam, lParam);
    case Msg of
      WM_SYSCOMMAND:
      begin
          case Word(wParam) of
            MeinMenutItem: MessageBox(0, 'Es klappt endlich!', '', 0);
          end;
      end;
    end;
end;
So funktioniert es endlich :party: Aber sollte jemand noch eine Idee zu dem Hook haben, ich bin immer noch neugierig.

Und nochmal danke...


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:38 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz