注
このドキュメントは、System.Windows.Automation 名前空間で定義されているマネージド UI オートメーション クラスを使用する .NET Framework 開発者を対象としています。 UI オートメーションの最新情報については、「Windows Automation API: UI オートメーション 」を参照してください。
Windows Vista 以降では、ユーザーは画面のほとんどのユーザー インターフェイス (UI) 要素が大きく表示されるように、1 インチあたりのドット数 (dpi) 設定を変更できます。 この機能は長い間 Windows で使用できますが、以前のバージョンでは、スケーリングをアプリケーションで実装する必要がありました。 Windows Vista 以降、デスクトップ ウィンドウ マネージャーは、独自のスケーリングを処理しないすべてのアプリケーションに対して既定のスケーリングを実行します。 UI オートメーション クライアント アプリケーションでは、この機能を考慮する必要があります。
Windows Vista でのスケーリング
既定の dpi 設定は 96 です。これは、96 ピクセルが 1 つの概念インチの幅または高さを占めることを意味します。 "インチ" の正確な測定値は、モニターのサイズと物理的な解像度によって異なります。 たとえば、12 インチ幅のモニターでは、水平解像度が 1280 ピクセルの場合、96 ピクセルの水平線は約 9/10 インチに拡張されます。
dpi 設定の変更は、画面の解像度を変更するのと同じではありません。 dpi スケーリングでは、画面上の物理ピクセルの数は変わりません。 ただし、スケーリングは UI 要素のサイズと場所に適用されます。 このスケーリングは、デスクトップ ウィンドウ マネージャー (DWM) によって、デスクトップと、スケーリングしないことを明示的に要求しないアプリケーションに対して自動的に実行できます。
実際には、ユーザーがスケール ファクターを 120 dpi に設定すると、画面上の垂直方向または水平方向のインチが 25% 大きくなります。 すべてのディメンションは、それに応じてスケーリングされます。 画面の上端と左端からのアプリケーション ウィンドウのオフセットが 25% 増加します。 アプリケーションのスケーリングが有効になっていて、アプリケーションが dpi 対応でない場合、ウィンドウのサイズは、含まれるすべての UI 要素のオフセットとサイズと共に、同じ割合で増加します。
注
既定では、ユーザーが dpi を 120 に設定した場合、DWM は dpi 対応でないアプリケーションのスケーリングを実行しませんが、dpi が 144 以上のカスタム値に設定されている場合は実行されます。 ただし、ユーザーは既定の動作をオーバーライドできます。
画面のスケーリングは、画面座標に関係するアプリケーションに新しい課題を生み出します。 画面に物理座標系と論理座標系の 2 つの座標系が含まれるようになりました。 ポイントの物理的な座標は、原点の左上からの実際のオフセット (ピクセル単位) です。 論理座標は、ピクセル自体がスケーリングされた場合と同様のオフセットです。
たとえば、座標 (100、48) にボタンがあるダイアログ ボックスをデザインするとします。 このダイアログ ボックスが既定の 96 dpi で表示されている場合、ボタンは物理座標 (100、48) にあります。 120 dpi では、物理座標 (125、60) に配置されます。 ただし、論理座標は任意の dpi 設定 (100、48) で同じです。
論理座標は、dpi 設定に関係なく、オペレーティング システムとアプリケーションの動作を一貫性のあるものにするため、重要です。 たとえば、 Cursor.Position は通常、論理座標を返します。 ダイアログ ボックス内の要素の上にカーソルを移動すると、dpi の設定に関係なく、同じ座標が返されます。 コントロールを (100, 100) で描画すると、そのコントロールはそれらの論理座標に描画され、任意の dpi 設定で同じ相対位置を占めます。
UI オートメーション クライアントでのスケーリング
UI オートメーション API は論理座標を使用しません。 次のメソッドとプロパティは、物理座標を返すか、パラメーターとして受け取ります。
既定では、96 dpi 以外の環境で実行されている UI オートメーション クライアント アプリケーションは、これらのメソッドとプロパティから正しい結果を取得できません。 たとえば、カーソル位置が論理座標であるため、クライアントはこれらの座標を単に渡して、カーソルの下にある要素を取得 FromPoint することはできません。 さらに、アプリケーションは、クライアント領域の外部にウィンドウを正しく配置できません。
ソリューションは 2 つの部分に分かれています。
まず、クライアント アプリケーションを dpi 対応にします。 これを行うには、起動時に Win32 関数
SetProcessDPIAware
を呼び出します。 マネージド コードでは、次の宣言により、この関数を使用できるようになります。[System.Runtime.InteropServices.DllImport("user32.dll")] internal static extern bool SetProcessDPIAware();
<System.Runtime.InteropServices.DllImport("user32.dll")> _ Friend Shared Function SetProcessDPIAware() As Boolean End Function
この関数は、プロセス全体を dpi に対応させます。つまり、プロセスに属するすべてのウィンドウはスケーリングされません。 たとえば、 蛍光ペンのサンプルでは、強調表示の四角形を構成する 4 つのウィンドウは、論理座標ではなく UI オートメーションから取得された物理座標に配置されます。 サンプルが dpi 対応でない場合は、デスクトップ上の論理座標で強調表示が描画され、96 dpi 以外の環境での配置が正しくなくなります。
カーソル座標を取得するには、Win32 関数
GetPhysicalCursorPos
を呼び出します。 次の例は、この関数を宣言して使用する方法を示しています。public struct CursorPoint { public int X; public int Y; } [System.Runtime.InteropServices.DllImport("user32.dll")] internal static extern bool GetPhysicalCursorPos(ref CursorPoint lpPoint); private bool ShowUsage() { CursorPoint cursorPos = new CursorPoint(); try { return GetPhysicalCursorPos(ref cursorPos); } catch (EntryPointNotFoundException) // Not Windows Vista { return false; } }
Structure CursorPoint Public X As Integer Public Y As Integer End Structure <System.Runtime.InteropServices.DllImport("user32.dll")> _ Friend Shared Function GetPhysicalCursorPos(ByRef lpPoint As CursorPoint) As Boolean End Function Private Function ShowUsage() As Boolean Dim cursorPos As New CursorPoint() Try Return GetPhysicalCursorPos(cursorPos) Catch e As EntryPointNotFoundException ' Not Windows Vista Return False End Try End Function
注意事項
Cursor.Positionは使用しないでください。 スケーリングされた環境でのクライアント ウィンドウの外部でのこのプロパティの動作は未定義です。
アプリケーションが非 dpi 対応アプリケーションとの直接のクロスプロセス通信を実行する場合は、win32 関数の PhysicalToLogicalPoint
と LogicalToPhysicalPoint
を使用して、論理座標と物理座標の間で変換が行われる可能性があります。