Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Menu Ownerdraw (https://www.delphipraxis.net/199974-menu-ownerdraw.html)

EWeiss 7. Mär 2019 08:23

Menu Ownerdraw
 
Kann mir jemand sagen wie ich das Menu ändern kann? bzw. wie ich da dran komme.
Die einzige Message die ich ermitteln kann ist WM_PRINTCLIENT.

Nur was hat diese mit dem Menu zu tun.
Habe leider keine Mail um Rodrigo Ruz mal zu kontaktieren

gruss

TiGü 7. Mär 2019 09:49

AW: Menu Ownerdraw
 
Wenn man sich den Dialog mithilfe des Tools Window Detective anschaut, dann erkennt man beim Aufklappen des Ansichtsbuttons, dass dynamisch zwei Sachen erzeugt werden (unter Windows 10 1809):
Einmal
Delphi-Quellcode:
#32768 (Menu)
und
Delphi-Quellcode:
SysShadow
. Letzteres stellt den Schatten am rechten und unteren Rand dar.
Ersteres ist wiederum interessant, weil es das Menü ist, wonach du suchst.

Wenn wir in den Quelltexten der VCL.Styles.Utils suchen, finden wir in Vcl.Styles.Utils.Menus.pas die Anmeldung des StyleHooks für dieses Menü.
https://github.com/RRUZ/vcl-styles-u...tils.Menus.pas

Am Ende der Unit unter initialization befindet sich:
Delphi-Quellcode:
TSysStyleManager.RegisterSysStyleHook('#32768', TSysPopupStyleHook);


In den folgenden Methoden der Hook-Klasse befinden sich wahrscheinlich die Dinge, die du wissen möchtest:
Delphi-Quellcode:
procedure MNSELECTITEM(var Message: TMessage); message MN_SELECTITEM;
procedure WMPRINT(var Message: TMessage); message WM_PRINT;
procedure WndProc(var Message: TMessage); override;
Die Definitionen für die von Microsoft undokumentierten Messages befinden sich als Konstanten ganz oben in der Unit.

EWeiss 7. Mär 2019 09:57

AW: Menu Ownerdraw
 
Zitat:

In den folgenden Methoden der Hook-Klasse befinden sich wahrscheinlich die Dinge, die du wissen möchtest:
Danke für das heraussuchen.. Habe selber leider den richtigen Punkt nicht gefunden. :duck:
Werde es damit mal versuchen und melde mich dann wieder hoffentlich mit einer Erfolgsmeldung. :)

gruss

TiGü 7. Mär 2019 10:23

AW: Menu Ownerdraw
 
Was genau willst du denn wissen?

EWeiss 7. Mär 2019 10:37

AW: Menu Ownerdraw
 
Zitat:

Zitat von TiGü (Beitrag 1427181)
Was genau willst du denn wissen?

Ich möchte das Menu Ownerdrawn damit es so aussieht wie mein Window also der Hintergrund..
Ich Subclass im Moment meine Toolbar auf diesem weg.

Delphi-Quellcode:
{$REGION 'procedure ToolBarSubClass'}

procedure ToolBarSubClass(WinHandle: HWND);
begin

  FToolBarInstance := MakeObjectInstance(OpenDialog.ToolBarSubClassProc);

  FPrevToolBarProc := Pointer(GetWindowLongPtr(WinHandle, GWL_WNDPROC));
  SetWindowLongPtr(WinHandle, GWL_WNDPROC, LPARAM(FToolBarInstance));
end;
{$ENDREGION}
{$REGION 'procedure ToolBarUnSubClass'}

procedure ToolBarUnSubClass(WinHandle: HWND);
begin

  SetWindowLongPtr(WinHandle, GWL_WNDPROC, LPARAM(FPrevToolBarProc));
  FreeObjectInstance(FToolBarInstance);
end;
{$ENDREGION}
{$REGION 'procedure ToolBarSubClassProc'}

procedure TSkinOpenSaveDialog.ToolBarSubClassProc(var Message: TMessage);
begin

  with Message do
  begin
    case Msg of
      WM_DESTROY:
        Result := ToolBarProc(hToolbar, LRESULT(Msg), Message.WPARAM, Message.LPARAM);
      WM_PAINT:
        Result := ToolBarProc(hToolbar, LRESULT(Msg), Message.WPARAM, Message.LPARAM);
      WM_PRINTCLIENT:
        Result := ToolBarProc(hToolbar, LRESULT(Msg), Message.WPARAM, Message.LPARAM);      
      WM_ERASEBKGND:
        Result := ToolBarProc(hToolbar, LRESULT(Msg), Message.WPARAM, Message.LPARAM);
    end;
    if (Result = 0) then
      Result := CallWindowProc(FPrevToolBarProc, hToolbar, Msg, WPARAM, LPARAM)

  end;
end;
{$ENDREGION}
{$REGION 'function ToolBarProc'}

function ToolBarProc(WinHandle: HWND; Msg: UINT; wp: WPARAM; lp: LPARAM): LRESULT; stdcall;
var
  hDCTemp: HDC;
  rc, rw: TRect;
  ps: TPaintStruct;
  lpt: TPoint;
  DC: HDC;
  hDCBack: HDC;

begin
  Result := 0;

  case Msg of

    WM_ERASEBKGND:
      begin
        RedrawWindow(WinHandle, nil, 0, RDW_INVALIDATE or RDW_ALLCHILDREN);
        Result := 1;
        Exit;
      end;

    WM_PAINT, WM_PRINTCLIENT:
      begin
        GetClientRect(WinHandle, rc);

        if (wp = 0) then
        begin
          BeginPaint(WinHandle, ps);
          DC := ps.HDC;
        end
        else
          DC := wp;

        // Double Buffer erstellen
        hDCTemp := SkinEngine.DoubleBuffer(DC, rc.Right, rc.Bottom, CreateBuffer);

        // Dimensionen der ToolBar auslesen
        GetWindowRect(WinHandle, rw);
        lpt.x := rw.Left;
        lpt.y := rw.Top;
        ScreenToClient(SKDialogHandle, lpt);

        // Hintergrund Kopieren
        hDCBack := CreateCompatibleDC(hDCTemp);
        SelectObject(hDCBack, SkinEngine.GetBackBitmap(SKDialogHandle));
        // Toolbar Hintergrund mit dem Parent Hintergrund füllen
        BitBlt(hDCTemp, 0, 0, rc.Right, rc.Bottom, hDCBack, lpt.x, lpt.y, SRCCOPY);
        // Resourcen freigeben
        DeleteDC(hDCBack);
        // Double Buffer freigeben
        SkinEngine.DoubleBuffer(0, 0, 0, DestroyBuffer);
        DeleteDC(hDCTemp);

        if (wp = 0) then
          EndPaint(WinHandle, ps);

        Result := 0;
        Exit;
      end;

    WM_DESTROY:
      begin
        ToolBarUnSubClass(WinHandle);
        Result := 1;
        Exit;
      end;

  end;
  if (Result = 0) then
    Result := CallWindowProc(FPrevToolBarProc, WinHandle, Msg, wp, lp);
end;
{$ENDREGION}
Was ich jetzt wissen muss wann bekomme ich das Window Handle um das Menu zu subclassen das ist ja erst bei WM_LBUTTONDOWN bzw. UP sichtbar.
Vorher kann ich das Handle nicht erreichen.

Etwas kompliziert. (Umständlich)
Das zeichnen selbst ist das kleinste Problem sobald ich das Handle habe.

PS:
Überlege noch ob ich diese Subclass verwenden kann oder für das Menu eine neue erstellen muss.
Muss es testen. ;)

gruss

TiGü 7. Mär 2019 11:14

AW: Menu Ownerdraw
 
Guck dir mal GetMenuFromHandle an und die Stellen wo es verwendet wird.

EWeiss 7. Mär 2019 11:36

AW: Menu Ownerdraw
 
Zitat:

Zitat von TiGü (Beitrag 1427192)
Guck dir mal GetMenuFromHandle an und die Stellen wo es verwendet wird.

Danke.. Ist etwas komplizierter muss mich da durchbeißen.

Delphi-Quellcode:
    WM_PAINT, WM_PRINTCLIENT:
      begin
        HToolBarMenu := HMENU(SendMessage(GetParent(WinHandle), MN_GETHMENU, 0, 0));
        if HToolBarMenu <> 0 then
            ToolBarSubClass(hToolbarMenu);
Innerhalb der ToolbarProc.
Handle ist immer 0.

GetParent(WinHandle) und nur WinHandle immer 0.
Kann ich mit den VCL Styles nicht vergleichen. Hmmm...

gruss

EWeiss 7. Mär 2019 12:27

AW: Menu Ownerdraw
 
Messagen die ich bekomme und das Menu siehe im Anhang.. hat bei den VCL Styles nichts mit einem Popupmenu zu tun.
Deshalb scheint MN_GETHMENU nicht das richtige zu sein.

gruss

TiGü 7. Mär 2019 12:28

AW: Menu Ownerdraw
 
Wo kommt denn der Wert für hToolbar in procedure TSkinOpenSaveDialog.ToolBarSubClassProc(var Message: TMessage); her?

EWeiss 7. Mär 2019 12:32

AW: Menu Ownerdraw
 
Zitat:

Zitat von TiGü (Beitrag 1427201)
Wo kommt denn der Wert für hToolbar in procedure TSkinOpenSaveDialog.ToolBarSubClassProc(var Message: TMessage); her?

Delphi-Quellcode:
  hToolbar := FindWindowEx(hMain, 0, 'ToolBarWindow32', nil);
  GetWindowRect(hToolbar, rc);
  lpt.x := rc.Left;
  lpt.y := rc.Top;
  ScreenToClient(hMain, lpt);

  MoveWindow(hToolbar, lpt.x, lpt.y, (rc.Right - rc.Left) + 3, rc.Bottom - rc.Top, false);

  ExStyle := GetWindowLongPtr(hToolbar, GWL_EXSTYLE);
  ExStyle := ExStyle or WS_EX_TRANSPARENT;
  SetWindowLongPtr(hToolbar, GWL_EXSTYLE, ExStyle);
  ToolBarSubClass(hToolbar);
hMain = Handle der Class #32700 Dialog Box

gruss

TiGü 7. Mär 2019 12:54

AW: Menu Ownerdraw
 
Liste der Anhänge anzeigen (Anzahl: 1)
Anbei mal ein Minimalbeispiel (ja, das geht in der Tat recht schnell) zum nachdebuggen in einer höheren Delphiversion, die schon VCL Styles unterstützt (z.B. die Delphi Community Editon).

Du kannst ja einfach mal nachvollziehen, wie in
Delphi-Quellcode:
procedure TSysPopupStyleHook.WMPRINT(var Message: TMessage);
der Hintergrund bei der Message WM_PRINT (791) gezeichnet wird.

EWeiss 7. Mär 2019 13:31

AW: Menu Ownerdraw
 
Danke werde es mir anschauen..

gruss

EWeiss 7. Mär 2019 14:06

AW: Menu Ownerdraw
 
Report:
Ist einfach mit seiner Engine aber nicht auf meiner weise..
Ich kann nicht erkennen wo das Event ausgelöst wird.. bei mir sollte es eigentlich WM_LBUTTONDOWN sein.

Aber ich bekomme kein gültiges Handle.
Ich klicke ja auf den Tollbarbutton nur welches Handle ist das bekomme ja nur das von der Toolbar selbst zurück geliefert.
Nicht das des Button den ich klicke noch das vom Menu.

Wenn ich das auf seine weise mache schlägt es fehl.
Delphi-Quellcode:
    WM_LBUTTONDOWN:
      begin
        Style := GetWindowLongPtr(WinHandle, GWL_STYLE);
        if (Style and WS_POPUP = WS_POPUP) then
        begin
          if HToolBarMenu <> 0 then
            ToolBarSubClass(hToolbarMenu);
        end;
      end;
Hmmm schwierig..
PS:
Werde es wohl erst mal verwerfen komme nicht an das Handle.

gruss

TiGü 7. Mär 2019 15:22

AW: Menu Ownerdraw
 
mach doch mal ein FindWindowEx auf den Klassennamen '#32768'.

EWeiss 7. Mär 2019 15:43

AW: Menu Ownerdraw
 
Zitat:

Zitat von TiGü (Beitrag 1427229)
mach doch mal ein FindWindowEx auf den Klassennamen '#32768'.

Habe ich schon versucht.. schlägt fehlt in der ToolBarProc.. WM_LBUTTONDOWN und WM_PRINT

Danke.
Werde es so lassen wie es ist. Kann man nichts machen ohne das ich jetzt fremden Quelltext verwende.

gruss

TiGü 7. Mär 2019 18:44

AW: Menu Ownerdraw
 
Wahrscheinlich ist das Popupfenster nicht sofort da. Warte doch ein paar Millisekunden und suche dann.
Du könntest aber auch den Callstack im Beispiel hoch debuggen und Schritt für Schritt verstehen lernen, wie es da in Verbindung mit der Styleengine von Embarcadero gelöst wird.

EWeiss 7. Mär 2019 19:09

AW: Menu Ownerdraw
 
Zitat:

Zitat von TiGü (Beitrag 1427273)
Du könntest aber auch den Callstack im Beispiel hoch debuggen und Schritt für Schritt verstehen lernen, wie es da in Verbindung mit der Styleengine von Embarcadero gelöst wird.

Danke habe das schon gemacht und verstehe was er macht aber es lässt sich so einfach nicht in mein Projekt integrieren.
Er verwendet dafür den "CBT Hook in Verbindung mit SetWindowsHookEx" habe mich aber damit noch nie beschäftigt müsste mich also da erstmal einlesen.

Nur ob sich der Aufwand lohnt ist fraglich.
Zitat:

Wahrscheinlich ist das Popupfenster nicht sofort da. Warte doch ein paar Millisekunden und suche dann.
Ein warten bringt nichts selbst über EnumClientWindows komme ich nicht ans ziel.
Auch ein "Windows Detective" listet mir das Menu nicht auf wenn es angezeigt wird.
Er erkennt es nicht von daher kann ich auch nicht sagen wodurch es aufgerufen wird auch wenn ich es theoretisch weis (Beim Klick auf den Button halt)

gruss

TiGü 7. Mär 2019 22:25

AW: Menu Ownerdraw
 
Zitat:

Zitat von EWeiss (Beitrag 1427277)
Auch ein "Windows Detective" listet mir das Menu nicht auf wenn es angezeigt wird.
Er erkennt es nicht von daher kann ich auch nicht sagen wodurch es aufgerufen wird auch wenn ich es theoretisch weis

Das ist doch jetzt Quatsch.

Die Informationen aus den ersten Absatz in meiner ersten Antwort habe ich mir ja nicht ausgedacht, sondern direkt aus dem Windows Detective abgelesen.
Kennst du das Tool?

https://www.thewindowsclub.com/window-detective

EWeiss 7. Mär 2019 22:35

AW: Menu Ownerdraw
 
Zitat:

Zitat von TiGü (Beitrag 1427286)
Zitat:

Zitat von EWeiss (Beitrag 1427277)
Auch ein "Windows Detective" listet mir das Menu nicht auf wenn es angezeigt wird.
Er erkennt es nicht von daher kann ich auch nicht sagen wodurch es aufgerufen wird auch wenn ich es theoretisch weis

Das ist doch jetzt Quatsch.

Die Informationen aus den ersten Absatz in meiner ersten Antwort habe ich mir ja nicht ausgedacht, sondern direkt aus dem Windows Detective abgelesen.
Kennst du das Tool?

https://www.thewindowsclub.com/window-detective

Quatsch? Ok anbei ein Screenshot!
Nun zeige mir bitte die Classe #32768

Warum soll ich dir irgendwas erzählen was nicht stimmt! Bringt mich in keinem Fall weiter.

gruss

EWeiss 8. Mär 2019 00:17

AW: Menu Ownerdraw
 
Destotrotz das ich mit "Windows Detective" die Class nicht finde versuche ich es jetzt auf diesen weg.
OK ist im Log zu finden seltsames Konzept..

Delphi-Quellcode:
function CBTHookProc(nCode: Integer; wP: WPARAM; lP: LPARAM): LRESULT; stdcall;
var
  buf: array[0..128] of Char;
  Style: DWORD;
begin
  if nCode < 0 then
  begin
    result := CallNextHookEx(FHook, nCode, wP, lP);
    exit;
  end;

  case nCode of
    HCBT_CREATEWND:
      begin
        CBTSturct := PCBTCreateWnd(lP)^;
        GetClassName(wP, buf, SizeOf(buf));
        if (Integer(CBTSturct.lpcs.lpszClass) = 32768) then
        begin
          CBTMenuHandle := wP;
          Style := GetWindowLongPtr(CBTMenuHandle, GWL_STYLE);
          if (Style and WS_POPUP = WS_POPUP) then
            ToolBarMenuSubClass(CBTMenuHandle);
        end;
        result := 0;
        exit;
      end;

    HCBT_DESTROYWND:
      if FHook <> 0 then
      begin
        UnhookWindowsHookEx(FHook);
        ToolBarMenuUnSubClass(CBTMenuHandle);
      end;
  end;
  result := CallNextHookEx(FHook, nCode, wP, lP);
end;
Delphi-Quellcode:
function ToolBarProc(WinHandle: HWND; Msg: UINT; wp: WPARAM; lp: LPARAM): LRESULT; stdcall;
var
  hDCTemp: HDC;
  rc, rw: TRect;
  ps: TPaintStruct;
  lpt: TPoint;
  DC: HDC;
  hDCBack: HDC;
begin
  Result := 0;

  case Msg of

    WM_LBUTTONDOWN:
      FHook := SetWindowsHookEx(WH_CBT, @CBTHookProc, 0, GetCurrentThreadId);
Das Problem das ich nun aber habe ist das 2 mal die Class "#32768" gefunden wird das verursacht nun richtige Probleme da ich nicht weis
welches handle nun gültig ist.

Dementsprechend wird jetzt auch 2 mal die Subclass
Delphi-Quellcode:
ToolBarMenuSubClass(CBTMenuHandle);
aufgerufen.

gruss

TiGü 11. Mär 2019 08:40

AW: Menu Ownerdraw
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von EWeiss (Beitrag 1427287)
Zitat:

Zitat von TiGü (Beitrag 1427286)
Zitat:

Zitat von EWeiss (Beitrag 1427277)
Auch ein "Windows Detective" listet mir das Menu nicht auf wenn es angezeigt wird.
Er erkennt es nicht von daher kann ich auch nicht sagen wodurch es aufgerufen wird auch wenn ich es theoretisch weis

Das ist doch jetzt Quatsch.

Die Informationen aus den ersten Absatz in meiner ersten Antwort habe ich mir ja nicht ausgedacht, sondern direkt aus dem Windows Detective abgelesen.
Kennst du das Tool?

https://www.thewindowsclub.com/window-detective

Quatsch? Ok anbei ein Screenshot!
Nun zeige mir bitte die Classe #32768

Warum soll ich dir irgendwas erzählen was nicht stimmt! Bringt mich in keinem Fall weiter.

Anbei eine TeamViewer-Aufzeichnung, wo man das genau sieht.

EWeiss 11. Mär 2019 22:38

AW: Menu Ownerdraw
 
Danke brauch ich nicht.
Hatte im vorherigen Thread schon geschrieben.
Zitat:

Destotrotz das ich mit "Windows Detective" die Class nicht finde versuche ich es jetzt auf diesen weg.
OK ist im Log zu finden seltsames Konzept..
gruss

TiGü 12. Mär 2019 08:10

AW: Menu Ownerdraw
 
Ich freue mich, dass du dein Problem anscheinend lösen konntest.
Du hattest gebeten, dir die Klasse zu zeigen, was ich damit tat.

Übrigens:
Beitrag, man nennt es Beitrag oder Post (englischer Plural: Postings).
Eine Ansammlung von Beiträgen oder Posts sind ein Thread (deutsch: Strang, Faden).

Das liest übrigens keiner, wenn du deine Beiträge im Nachhinein immer so vollständig und grundsätzlich editierst.
Die Edit-Funktion ist dafür da, um irgendwelche Fehler (Formatierungs-, Tipp-, Inhaltliche) zu korrigieren.
Du solltest dir wirklich angewöhnen, neue Erkenntnisse u.ä. in einem neuen Beitrag zu schreiben.

EWeiss 12. Mär 2019 08:17

AW: Menu Ownerdraw
 
Zitat:

Beitrag, man nennt es Beitrag oder Post (englischer Plural: Postings).
Du hast recht.. sorry.
Zitat:

Du hattest gebeten, dir die Klasse zu zeigen, was ich damit tat.
Ich freue mich auch über deine Hilfe nur ich verwende keinen TeamViewer und könnte die Datei also nicht ansehen.
Zitat:

Du solltest dir wirklich angewöhnen, neue Erkenntnisse u.ä. in einem neuen Beitrag zu schreiben.
Ja werde mich bessern.

gruss

TiGü 12. Mär 2019 09:17

AW: Menu Ownerdraw
 
Zitat:

Zitat von EWeiss (Beitrag 1427529)
Zitat:

Du hattest gebeten, dir die Klasse zu zeigen, was ich damit tat.
Ich freue mich auch über deine Hilfe nur ich verwende keinen TeamViewer und könnte die Datei also nicht ansehen.

Ja, nun...einatmen, ausatmen...du könntest dir natürlich TeamViewer (TV) auch runterladen. :spin2:
Es gibt auch eine Portable-Version ohne Installation zum Runterladen (ganz unten auf folgender Seite):
https://www.teamviewer.com/de/download/windows/

Ich vermute, dass diese portable Version auch Bildschirmaufzeichnungen öffnen kann. Bitte prüfen!
Im normalen TV im Menüpunkt "Extras -> Aufgezeichnete Sitzung abspielen oder konvertieren...".

EWeiss 12. Mär 2019 09:28

AW: Menu Ownerdraw
 
Zitat:

Ja, nun...einatmen, ausatmen...du könntest dir natürlich TeamViewer (TV) auch runterladen.
Es ist doch nun mal so das ich im vorherigen Beitrag dir einen Shot gezeigt habe wo du den Eintrag für das Menu nicht sehen kannst..

Der einzige Punkt wo ich die Class #32768 sehe ist im Log File Fenster..
Das andere Fenster "Desktop window hierachy" zeigt mir die class nicht an und aktualisiert auch nicht warum auch immer.

Mag sein das es bei dir angezeigt wird mit meiner Anwendung zumindest nicht.
Denke damit sollte das geklärt sein dafür muss ich keinen TeamViewer herunterladen. ;)

gruss

TiGü 13. Mär 2019 10:55

AW: Menu Ownerdraw
 
Und ich mache mir extra die Mühe, dir ein Daumenkino an "Shots" (du bist der einzige Mensch im gesamten Internet, der Screenshots so abkürzt) zu erstellen und du trittst das mit Füßen, nur weil du nicht damit umgehen kannst, wenn etwas nicht so ist, wie du gerne möchtest oder glaubst.

Schaue dir doch einfach an, ist nicht weiter kompliziert.
Vielleicht lernst du auch was dabei.
Du schaffst das schon mit der Portable Version (ja, umsonst und kostenlos und weißderkuckkuck).

Du musst dich nicht wundern, wenn die Leute hier im Forum schnippisch zu dir sind.
Es ist immer eine "Wie es in den Wald hineinruft, so schallt es heraus!"-Angelegenheit.
Die Leute wollen dir helfen, meist aus Mitleid, und von dir kommt in der Regel:
"Aber in meinen Code ist es so und so (ja haha, hättet ihr doch vorher wissen sollen das es NonVCL ist), ich gucke mir gar nicht erst an, was ihr schreibt...LOL!!!1111!1!elf"


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:59 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