![]() |
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 |
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:
und
#32768 (Menu)
Delphi-Quellcode:
. Letzteres stellt den Schatten am rechten und unteren Rand dar.
SysShadow
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ü. ![]() 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:
Die Definitionen für die von Microsoft undokumentierten Messages befinden sich als Konstanten ganz oben in der Unit.
procedure MNSELECTITEM(var Message: TMessage); message MN_SELECTITEM;
procedure WMPRINT(var Message: TMessage); message WM_PRINT; procedure WndProc(var Message: TMessage); override; |
AW: Menu Ownerdraw
Zitat:
Werde es damit mal versuchen und melde mich dann wieder hoffentlich mit einer Erfolgsmeldung. :) gruss |
AW: Menu Ownerdraw
Was genau willst du denn wissen?
|
AW: Menu Ownerdraw
Zitat:
Ich Subclass im Moment meine Toolbar auf diesem weg.
Delphi-Quellcode:
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.
{$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} 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 |
AW: Menu Ownerdraw
Guck dir mal GetMenuFromHandle an und die Stellen wo es verwendet wird.
|
AW: Menu Ownerdraw
Zitat:
Delphi-Quellcode:
Innerhalb der ToolbarProc.
WM_PAINT, WM_PRINTCLIENT:
begin HToolBarMenu := HMENU(SendMessage(GetParent(WinHandle), MN_GETHMENU, 0, 0)); if HToolBarMenu <> 0 then ToolBarSubClass(hToolbarMenu); Handle ist immer 0. GetParent(WinHandle) und nur WinHandle immer 0. Kann ich mit den VCL Styles nicht vergleichen. Hmmm... gruss |
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 |
AW: Menu Ownerdraw
Wo kommt denn der Wert für hToolbar in procedure TSkinOpenSaveDialog.ToolBarSubClassProc(var Message: TMessage); her?
|
AW: Menu Ownerdraw
Zitat:
Delphi-Quellcode:
hMain = Handle der Class #32700 Dialog Box
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); gruss |
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:
der Hintergrund bei der Message WM_PRINT (791) gezeichnet wird.
procedure TSysPopupStyleHook.WMPRINT(var Message: TMessage);
|
AW: Menu Ownerdraw
Danke werde es mir anschauen..
gruss |
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:
Hmmm schwierig..
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; PS: Werde es wohl erst mal verwerfen komme nicht an das Handle. gruss |
AW: Menu Ownerdraw
mach doch mal ein FindWindowEx auf den Klassennamen '#32768'.
|
AW: Menu Ownerdraw
Zitat:
Danke. Werde es so lassen wie es ist. Kann man nichts machen ohne das ich jetzt fremden Quelltext verwende. gruss |
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. |
AW: Menu Ownerdraw
Zitat:
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:
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 |
AW: Menu Ownerdraw
Zitat:
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? ![]() |
AW: Menu Ownerdraw
Zitat:
Nun zeige mir bitte die Classe #32768 Warum soll ich dir irgendwas erzählen was nicht stimmt! Bringt mich in keinem Fall weiter. gruss |
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:
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
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); welches handle nun gültig ist. Dementsprechend wird jetzt auch 2 mal die Subclass
Delphi-Quellcode:
aufgerufen.
ToolBarMenuSubClass(CBTMenuHandle);
gruss |
AW: Menu Ownerdraw
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
|
AW: Menu Ownerdraw
Danke brauch ich nicht.
Hatte im vorherigen Thread schon geschrieben. Zitat:
|
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. |
AW: Menu Ownerdraw
Zitat:
Zitat:
Zitat:
gruss |
AW: Menu Ownerdraw
Zitat:
Es gibt auch eine Portable-Version ohne Installation zum Runterladen (ganz unten auf folgender Seite): ![]() 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...". |
AW: Menu Ownerdraw
Zitat:
![]() 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 |
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 13:44 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz