2017-01-14 12 views
-2

Windowsのシステムトレイアイコンを追加するときに、Shell_NotifyIcon()NOTIFYICONDATA構造を介して渡すことができるAPIの2つのバージョンがあります。 2つのAPIには微妙な違いがあり、MSDNのどこにも記載されていません。相違のいくつかを理解するために私はある程度の努力を払いましたが、私は今これを共有します。答えに対する改善/追加はいつでも歓迎します。NOTIFYICONDATA構造体で使用されるNOTIFYICON_VERSIONとNOTIFYICON_VERSION_4の違いは?

PS:この質問は、私がここ数日間Windows DPIスケーリングを試して学んだことを純粋に共有するためのものです。

答えて

-2

uVersionNOTIFYICONDATA構造体のメンバには、タスクバーアイコンの作成に使用されているAPIのバージョンを表す3つの値を指定できます。

  • のバージョンのWindows用に設計されたアプリケーションのための使用は、この値を以前のWindows 2000へ
  • NOTIFYICON_VERSION Windows 2000の動作を使用してください。この値は、Windows 2000以降用に設計されたアプリケーションに使用します。
  • NOTIFYICON_VERSION_4現在の動作を使用します。 Windows Vista以降用に設計されたアプリケーションには、この値を使用します。

トレイアイコンのメッセージハンドラについては、wParamuParamの違いは次のとおりです。

NOTIFYICON_VERSION vs NOTIFYICON_VERSION_4

NOTIFYICON_VERSION_4にwParamには、Xを与え、様々なイベントのY座標が、NOTIFYICON_VERSIONの座標を取得するための規定がないことに注意してください。これは面白い振る舞いを引き起こします(私が解決しようとしていたバグの原因でした)NOTIFYICON_VERSIONを使用してトレイアイコンのコンテキストメニューを呼び出すと、マウスカーソルは、メニューを呼び出している間はどこでもトレイアイコンの中央に置かれます。アイコンのコンテキストメニューを呼び出すためにキーボード(WINDOWS + B)を使用しても、マウスカーソルはアイコンに移動します。

私がPico torrentアプリケーションで解決しようとしているこの特定のバグを見るまで、これは特に興味深いことではありません。

ここにシナリオがあります。

  • OS:Windowsの10
  • アプリケーションごとのモニターDPIは認識していないが、システムレベルDPIは認識しています。
  • ユーザがログインしたときにデスクトップスケーリングの初期値が設定されています(たとえば150%)。
  • ピコトレントが実行されています。
  • DPIスケーリング値は125%
  • ピコの急流のコンテキストメニューは、コンテキストメニューは、その適切な場所に表示されません 呼び出され、逸脱を示す、少しずれることになると言う、に変更されます。

何が起きているのかを理解するには、次のイメージを参照してください。

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

問題はあるがMSDNGET_X_LPARAM(wParam)、およびGET_Y_LPARAM(wParam)は、トレイアイコンのハンドラで正しい値を与えるべきであると述べているが、それは、DPIの存在にするために、すなわち(スケーリングしないということですサインアウトやサインインをせずにDPIスケーリングを変更する)。一方、API GetCursorPos()はマウスカーソル座標の正しい値を返します。画面上のどこにでもマウスカーソルを置くことができるキーボードを使用してコンテキストメニューを呼び出すことができるので、NOTIFYICON_VERSION_4GetCursorPos()は機能しません。

DPIスケーリングが上記のように行われたときにトレイアイコンのコンテキストメニューを正しく表示するために学んだ知識を、どのように組み合わせて、アプリケーションごとにDPI対応アプリケーションを作成する必要はありませんGET_X_LPARAM(wParam)GET_Y_LPARAM(wParam)は常に正しい値を返します)。

NOTIFYICON_VERSION_4の代わりにNOTIFYICON_VERSIONを使用すると、コンテキストメニューが呼び出されたときにトレイアイコンにマウスカーソルが移動し、GetCursorPos()を使用してマウスカーソルの位置を取得します。座標を使用してTrackPopupMenu()を使用してコンテキストメニューを表示します。

PS:上記の例では、DPIスケーリング値が150%から125%に変更されています。トレイアイコン領域が画面の右下にある場合、DPIスケーリングが大きい値から小さい値に設定されると、コンテキストメニューの偏差がより顕著になります。これは、DPIスケーリングが実行され、DPI仮想化を使用してモニタごとに認識されないUI要素を拡大すると、物事が右肩上がり、下り坂に移動するためです。例えば。アプリケーションでウィンドウの矩形が(0,0,100,100)(画面座標)の場合、倍率150%の後に(0,0,150,150)になることがあります。今トレイアイコンのメニューの場合、画面の右下を越える座標を指定すると、OSは画面内の右下の位置に表示され、メニューが正しく表示されます。例えば。画面が1920x1080で、メニューがTrackPopupMenu()(10000,10000)の場合、メニューは1920x1080画面の四角形内に表示されます。したがって、DPIスケーリングが増加するとコンテキストメニューがさらに右に移動することはありません。

+3

問題の正しい解決方法は、プログラムをDPIに対応させることです。実行時に必要に応じて 'SetProcessDpiAwareness()'を動的にロードしてください。 – andlabs

+1

また、トレイアイコンのポップアップがキーボードから呼び出されているときは、['Shell_NotifyIconGetRect()'](https://msdn.microsoft.com/en-us/library/windows/desktop/dd378426 vs.85).aspx)を使用して、GetCursorPos()を使用してマウスの現在の画面位置を取得する代わりに、アイコン自体の現在のスクリーン位置を取得します。 –

+0

@andlabsいいえ、そうではありません。モニタごとにDPIを認識させると、すべてのUI要素のスケーリングを自分で処理する必要があるためです。多くの開発者は、DPI仮想化をある程度使いたいと思っています。さらに、アプリケーションがUI要素を作成するサードパーティ製のバイナリを使用する場合、コードを持たないため、DPIスケーリングを処理することはできません。これは、MicrosoftがWIndows 10 Aniversary Update、SetThreadDpiAwarenessContext()で新しいAPIを導入する主な理由でした。 –

1

@ sahil-singhあなたはそれについて正しいですし、私はあなたのアプリケーションがDPIに認識されるべきだと他の誰も同意しますが、これはここでのポイントではありません。

私のアプリケーションは(まだ)DPI対応ではなく、GET_X_LPARAM(wParam)は非仮想座標を返すという同様の問題がありました。この値をTrackPopupMenu()に渡した後、画面上の位置が正しくありません。

最も良い方法は、wParamの代わりにGetMessagePos()を使用することです。この場合、Windowsは仮想座標で新しいDWORDを与え、GET_X_LPARAM/GET_Y_LPARAMを使用してTrackPopupMenu()に渡すことができる値を取得します。

+0

トレイアイコンがマウスではなくキーボードを使用して呼び出された場合、GetMessagePos()が機能しますか? –

関連する問題