C++ Builder XE4 > Windows 7, 8.1, 10 のウィンドウサイズ情報を見る


実装環境
C++ Builder XE4

関連

ウィンドウサイズを知る

Windows 10特有の「invisible border」。

Windows 7, 8.1, 10で同じようにウィンドウ配置するためには、invisible borderを含まないvisibleなウィンドウサイズ情報を知る必要がある。

WPF and WIndows 10. Invisible border around windows?

answered May 18 '16 at 23:59
mikew

You can get the offests by using a combination of the normal GetWindowRect function and the use of the DwmGetWindowAttribute function, together with the DWMWA_EXTENDED_FRAME_BOUNDS parameter.

上記の関数を使ってウィンドウ情報を調べてみる。

code

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    TRect arect_inv;
    RECT arect_nrm;

    HWND hwnd1 = this->Handle;
    HWND hwnd2 = this->Handle;

    GetWindowRect(hwnd1, &arect_nrm);
    DwmGetWindowAttribute(hwnd2, DWMWA_EXTENDED_FRAME_BOUNDS, &arect_inv, sizeof(TRect));

    String msg;
    msg = String().sprintf(L"GetWindowRect: top:%d, bottom:%d, left:%d, right:%d",
        arect_nrm.top, arect_nrm.bottom, arect_nrm.left, arect_nrm.right);
    msg += L"\r\n";
    msg += String().sprintf(L"DwmGetWindowAttribute: top:%d, bottom:%d, left:%d, right:%d",
        arect_inv.top, arect_inv.bottom, arect_inv.left, arect_inv.right);

    ShowMessage(msg);
}
//---------------------------------------------------------------------------

実行結果

Windows 7

Windows 8.1

Windows 10

知見

  • Windows 7ではDwmGetWindowAttribute()が0を返す
  • Windows 8.1と10ではDwmGetWindowAttribute()からvisibleのウィンドウサイズが得られそう

code > OSによらずvisible ウィンドウサイズを得る

Unit1.c
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    TRect arect;

    GetVisibleWindowSize(this, &arect);

    int width = arect.bottom - arect.top;
    int height = arect.right - arect.left;
    String msg = String().sprintf(L"left:%d top:%d W:%d H:%d",
        arect.left, arect.top, width, height);

    ShowMessage(msg);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::GetVisibleWindowSize(TForm *formPtr, TRect *rectPtr)
{
    TRect arect_inv;
    RECT arect_nrm;

    if (formPtr == NULL || rectPtr == NULL) {
        return; // error
    }

    GetWindowRect(formPtr->Handle, &arect_nrm); // (1)
    DwmGetWindowAttribute(formPtr->Handle, DWMWA_EXTENDED_FRAME_BOUNDS, &arect_inv, sizeof(TRect)); // (2)

    // for Windows 7
    if (arect_inv.left == 0 && arect_inv.top == 0 && arect_inv.Bottom == 0 && arect_inv.right == 0) {
        // DwmGetWindowAttribute()が0を返すためGetWindowRect()の結果を使う
        rectPtr->left = arect_nrm.left;
        rectPtr->top = arect_nrm.top;
        rectPtr->right = arect_nrm.right;
        rectPtr->bottom = arect_nrm.bottom;
        return;
    }

    // for Windows 8.1, Windows 10
    //   Windows 8.1では(1)と(2)は同じ定義
    //   Windows 10ではinvisible borderにより(1)と(2)の結果が異なる
    //   invisible borderのサイズを含まない(2)の方を返す
    rectPtr->left = arect_inv.left;
    rectPtr->top = arect_inv.top;
    rectPtr->right = arect_inv.right;
    rectPtr->bottom = arect_inv.bottom;
}