[Win32] ウィンドウ位置とサイズの取得方法

ウィンドウの位置とサイズの取得方法について記載します。

 

注意

Windows Vista 以降の Windows 環境でGUIを動作する場合、DWM API を使って正しく実装しないとウィンドウ位置とサイズに誤差を生じます。注意が必要です。

 

 

 

1. GetWindowRect による方法

Window95以降で使用可能な伝統的手法です。

 

RECT    rect;
BOOL    result;

result = GetWindowRect( hWnd, &rect);

 

上記処理で RECT 情報を取得することで、ウィンドウの位置およびサイズを以下のように確認できます。

LEFT:      rect.left
TOP:       rect.top
WIDTH:     rect.right  - rect.left
HEIGHT:    rect.bottom - rect.top

 

 

2. DwmGetWindowAttribute による方法

Windows Vista 以降で採用されたエアロ環境(ウィンドウマネージャ― DWM を動作している環境)では、前述の GetWindowRect で取得した情報は実際のウィンドウ位置およびサイズと差異が生じます。特に Windows10環境では誤差が大きくなるため注意が必要です。
エアロ環境で正しくウィンドウ位置およびサイズを取得するためには、 API DwmGetWindowAttribute を "DWMWA_EXTENDED_FRAME_BOUNDS" の属性を使って情報を取得する必要があります。

注意:
・DwmGetWindowAttribute は Vista 以降のみサポートのAPIです。
・Vista/7 ではエアロをON/OFFできます。エアロのON/OFFをチェックして、エアロがONのときのみ DwmGetWindowAttribute を使用する必要があります。OFFの時は従来のウィンドウサイズ取得を使用します。これをしないとまた誤差を生じます。
・Form にて使用する場合、ウィンドウの Load イベント中で DwmGetWindowAttribute を使用したら正しく値を取得できませんでした。ウィンドウの起動完了から一定の時間が経過した後に情報を取得する必要がある可能性があります。

 

RECT    rect;
HRESULT hResult;
BOOL    bResult;
BOOL    bDwmEnable;

hResult = DwmIsCompositionEnable( &bDwmEnable );
if ( S_OK == hResult ){
    if ( bDwmEnable ){
        // エアロ環境
        hResult = DwmGetWindowAttribute( hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, &rect, sizeof(rect));
    }
    else{
        // 非エアロ環境
        bResult = GetWindowRect( hWnd, &rect);        
    }
}

 

上記処理で RECT 情報を取得することで、ウィンドウの位置およびサイズを以下のように確認できます。

LEFT:         rect.left
TOP:          rect.top
WIDTH:     rect.right - rect.left
HEIGHT:    rect.bottom - rect.top

 

 

3. テストプログラム

Windows10 環境にて、GetWindowRect と DwmGetWindowAttribute で得られる情報の差異を実際に確認してみます。
シンプルに Win32 のプロジェクトとして作成してみます。

[環境]

 

[実行結果]

実行結果は下図の通りです。
"DwmGetWindowAttribute" で取得した値が期待する正しい値です。
"GetWindowRect" で取得した値と比べると、左右でそれぞれ 7画素、下に 7画素、の差異を確認することができます。

 

実行結果

 

[プログラムソース]
プロシージャコールを抜粋で記載します。
全体については、サンプルダウンロードから取得して確認してください。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_MOVE:
        InvalidateRect(hWnd, NULL, FALSE);
        break;

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            RECT    rect1;
            RECT    rect2;
            BOOL    result1;
            HRESULT result2;

            // TODO: HDC を使用する描画コードをここに追加してください...

            // ウィンドウサイズを取得
            {
                // GetWindowRect で取得
                {
                    result1 = GetWindowRect(hWnd, &rect1);
                }

                // DwmGetWindowAttribute で取得
                {
                    BOOL    bDwmEnable;

                    result2 = DwmIsCompositionEnabled(&bDwmEnable);
                    if (S_OK == result2) {
                        if (bDwmEnable) {
                            DwmGetWindowAttribute( hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, &rect2, sizeof(rect2));
                        }
                    }
                }
            }

            // 画面にウィンドウサイズを書く
            {
                TCHAR str[256];
                TCHAR* title1 = _T("[GetWindowRect]");
                TCHAR* title2 = _T("[DwmGetWindowAttribute]");

                if (TRUE == result1) {
                    _stprintf_s(str, _T("left = %d, top = %d, width = %d, height = %d"), 
                        rect1.left, rect1.top, rect1.right - rect1.left, rect1.bottom - rect1.top);
                    TextOut(hdc, 10, 10, title1, _tcslen(title1));
                    TextOut(hdc, 10, 30, str, _tcslen(str));
                }

                if (S_OK == result2) {
                    _stprintf_s(str, _T("left = %d, top = %d, width = %d, height = %d"),
                        rect2.left, rect2.top, rect2.right - rect2.left, rect2.bottom - rect2.top);
                    TextOut(hdc, 10, 60, title2, _tcslen(title2));
                    TextOut(hdc, 10, 80, str, _tcslen(str));
                }
            }
            EndPaint(hWnd, &ps);
        }
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

 

NOTE

GetWindowRect と DwmGetWindowAttribute は下記違いもありそうです。どう活用したらよいか、難しい・・・。

 

 

サンプルプログラム

サンプルプログラム ダウンロード

 

 

ライセンス

本ページの情報は、特記無い限り下記 MIT ライセンスで提供されます。

The MIT License (MIT)

Copyright © 2015-2022 Kinoshita Hidetoshi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 

 

参考

 


 

変更履歴

2022-10-13 - ページデザイン更新
  - 誤り修正
2015-08-29 - 新規作成

 

Programming Items トップページ

プライバシーポリシー