2017-01-14 1 views
-2

Beim Hinzufügen eines Taskleistensymbols von Windows gibt es zwei API-Versionen, die an Shell_NotifyIcon() über die Struktur NOTIFYICONDATA übergeben werden können. Zwischen den beiden APIs gibt es feine Unterschiede, die nirgendwo auf MSDN aufgeführt sind. Ich brauchte einige Anstrengungen, um einige der Unterschiede herauszufinden, die ich jetzt teilen werde. Verbesserungen/Ergänzungen zur Antwort sind immer willkommen.Unterschied zwischen NOTIFYICON_VERSION und NOTIFYICON_VERSION_4 in NOTIFYICONDATA-Struktur verwendet?

PS: Diese Frage ist rein zum Teilen, was ich in den letzten paar Tagen gelernt habe, experimentieren mit Windows-DPI-Skalierung.

Antwort

-2

uVersion Mitglied der NOTIFYICONDATA Struktur kann 3 mögliche Werte haben, die die Version der API darstellen, die zum Erstellen des Taskleistensymbols verwendet wird.

  • Verwenden Sie diesen Wert für Anwendungen für Windows-Versionen entwickelt, vor Windows 2000
  • NOTIFYICON_VERSION verwendet das Windows 2000-Verhalten. Verwenden Sie diesen Wert für Anwendungen, die für Windows 2000 und höher entwickelt wurden.
  • NOTIFYICON_VERSION_4 Verwenden Sie das aktuelle Verhalten. Verwenden Sie diesen Wert für Anwendungen, die für Windows Vista und höher entwickelt wurden.

Wenn es um Nachrichten-Handler für das Tray-Icon kommt, die wParam und uParam haben die Unterschiede, wie im folgenden Bild dargestellt.

NOTIFYICON_VERSION vs NOTIFYICON_VERSION_4

Beachten Sie, dass NOTIFYICON_VERSION_4 in dem WParam X gibt, und Y-Koordinaten von verschiedenen Veranstaltungen, aber es gibt keine Vorschrift, die die Koordinaten in NOTIFYICON_VERSION für immer. Dies führt zu einem interessanten Verhalten (was eine Ursache für einen BUG war, den ich zu lösen versuchte). Wenn Sie NOTIFYICON_VERSION verwenden und dann das Kontextmenü des Taskleistensymbols aufrufen, wird der Mauszeiger, egal wo Sie ihn gerade aufrufen, direkt in der Mitte des Taskleistensymbols platziert. Auch wenn Sie die Tastatur (WINDOWS + B) zum Aufrufen des Kontextmenüs des Symbols verwenden, bewegt sich der Mauszeiger immer noch auf das Symbol.

Dies ist möglicherweise nicht von besonderem Interesse für Sie, bis Sie auf diese besondere BUG schauen, die ich versuche, in Pico torrent Anwendung zu lösen.

Hier ist das Szenario.

  • OS: Windows 10
  • Anwendung ist nicht pro-Monitor DPI bewusst, aber es ist auf Systemebene DPI bewusst.
  • Es gibt einen Anfangswert der Desktop-Skalierung, sagen wir 150%, wenn sich der Benutzer anmeldet.
  • Pico torrent wird ausgeführt.
  • DPI-Skalierung Wert wird geändert, sagt 125%
  • Kontextmenü des Pico torrent aufgerufen wird Das Kontextmenü wird nicht an der richtigen Stelle angezeigt werden, und wird ein wenig verschoben werden, eine Abweichung zeigt.

Sehen Sie sich die folgenden Bilder an, um zu verstehen, was passiert.

DPI scaling level : 150 % DPI scaling level : 125 %

Das Problem ist, dass, obwohl MSDN sagt, dass GET_X_LPARAM(wParam) und GET_Y_LPARAM(wParam) richtige Werte in der Prozedur des Tray-Icon geben soll, aber es funktioniert nicht, in Gegenwart von DPI-Skalierung (dh für ein Ändern Sie die DPI-Skalierung, ohne eine Abmeldung durchzuführen und sich anzumelden). Auf der anderen Seite gibt die API GetCursorPos() den korrekten Wert der Mauszeigerkoordinaten zurück. Beachten Sie, dass NOTIFYICON_VERSION_4 zusammen mit GetCursorPos() nicht funktioniert, da das Kontextmenü über die Tastatur aufgerufen werden kann, bei der der Mauszeiger an beliebiger Stelle auf dem Bildschirm sein kann.

Also, wie kombinieren Sie alle soeben erlernten Kenntnisse, um das Kontextmenü des Tray-Icons korrekt anzuzeigen, wenn DPI-Skalierung in der oben beschriebenen Weise durchgeführt wird, ohne dass Sie pro DPI-fähige Anwendungen pro Monitor DPI-fähig machen GET_X_LPARAM(wParam) und GET_Y_LPARAM(wParam) geben immer den korrekten Wert zurück)?

Verwenden Sie NOTIFYICON_VERSION anstelle von NOTIFYICON_VERSION_4, dies wird den Mauszeiger auf das Tray-Symbol positionieren, wenn das Kontextmenü aufgerufen wird, und dann GetCursorPos() verwenden, um die Position des Mauszeigers zu erhalten. Zeigen Sie das Kontextmenü mit TrackPopupMenu() mit den Koordinaten an.

PS: Im obigen Beispiel wurde der DPI-Skalierungswert von 150% auf 125% geändert. Die Abweichung des Kontextmenüs ist stärker ausgeprägt, wenn die DPI-Skalierung von einem größeren Wert zu einem kleineren Wert erfolgt, wenn sich Ihr Taskleistensymbolbereich unten rechts auf dem Bildschirm befindet. Dies liegt daran, dass bei der DPI-Skalierung und der Vergrößerung von UI-Elementen, die nicht pro Monitor überwacht werden, mithilfe der DPI-Virtualisierung die Objekte nach rechts und nach unten verschoben werden. z.B. Wenn in einer Anwendung ein Fensterrechteck (0,0,100,100) (Bildschirmkoordinaten) ist, dann kann es nach der Vergrößerung auf 150% (0,0,150,150) werden. Wenn Sie nun für das Symbol des Taskleistensymbols Koordinaten angeben, die sich rechts unten auf dem Bildschirm befinden, wird das Betriebssystem immer noch in der unteren rechten Position angezeigt, die innerhalb des Bildschirms liegt. Dadurch wird sichergestellt, dass das Menü ordnungsgemäß angezeigt wird. z.B. Wenn ein Bildschirm 1920x1080 ist und TrackPopupMenu() (10000,10000) für Menü angegeben ist, wird das Menü immer noch im Bildschirmrechteck von 1920x1080 angezeigt. Eine Erhöhung der DPI-Skalierung verschiebt das Kontextmenü daher nicht weiter, wenn es bereits die rechte untere Position erreicht hat.

+3

Die richtige Lösung für das Problem ist, das Programm DPI-bewusst zu machen. Laden Sie 'SetProcessDpiAwareness()' zur Laufzeit bei Bedarf dynamisch. – andlabs

+1

Beachten Sie auch, wenn das Popupfenster über die Tastatur aufgerufen wird, können Sie ['Shell_NotifyIconGetRect()'] (https://msdn.microsoft.com/en-us/library/windows/desktop/dd378426 (v = vs.85) .aspx), um die aktuelle Bildschirmposition des Symbols selbst zu erhalten, anstatt 'GetCursorPos()' zu verwenden, um die aktuelle Bildschirmposition der Maus zu erhalten. –

+0

@andlabs Nein, ist es nicht.Denn wenn Sie den Prozess pro Monitor DPI bewusst machen, dann müssen Sie die Skalierung jedes UI-Elements selbst vornehmen. Viele Entwickler wollen die DPI-Virtualisierung dennoch teilweise nutzen. Wenn Ihre Anwendung außerdem eine Binärdatei von einem Drittanbieter verwendet, der UI-Elemente erstellt, können Sie die DPI-Skalierung nicht verarbeiten, da Sie den Code nicht haben. Dies war der Hauptgrund, der Microsoft veranlasste, eine neue API in Windows 10 Aniversary Update, SetThreadDpiAwarenessContext() einzuführen. –

1

@ sahil-singh Sie haben Recht damit, und ich stimme allen anderen zu, dass Ihre Anwendung sollte DPI bewusst sein, aber wenn das hier keinen Punkt ist.

Ich hatte ein ähnliches Problem, bei dem meine Anwendung (noch) nicht DPI bewusst ist und GET_X_LPARAM (wParam) nicht-virtuelle Koordinaten zurückgibt. Nach dem Übergeben dieses Wertes an das TrackPopupMenu() bekomme ich eine falsche Position auf dem Bildschirm.

Der beste Weg ist GetMessagePos() anstelle von wParam zu verwenden. In diesem Fall gibt Windows Ihnen ein neues DWORD mit virtuellen Koordinaten und anschließend GET_X_LPARAM/GET_Y_LPARAM, um Werte zu erhalten, die Sie an TrackPopupMenu() übergeben können.

+0

wird GetMessagePos() funktionieren, wenn Ihr Taskleistensymbol über die Tastatur und nicht die Maus aufgerufen wird? –

Verwandte Themen