C++ Builder XE4, 10.2 Tokyo > Forms > Windows 10 Invisible borderを含まないHeight, Width取得クラス > CUtilFormSize_noInvisibleBorder (Windows 7, 8.1, 10対応)

```txt:動作環境
RAD Studio 10.2 Tokyo Update 3
C++ Builder XE4
秀丸エディタ Version 8.79
Windows 7 Pro (32bit)
Windows 8.1 Pro (64bit)
Windows 10 v1709 (64bit)
```

### 関連

- [C++ Builder 10.2 Tokyo > Forms > フォームを並べたときに空白がないように配置する (Windows 7, 8.1, 10) > FormShow後の実行](https://qiita.com/7of9/items/cc7abbdd0f11b16d9ed9)

### Windows 7, 8.1, 10でのフォームHeight, Width取得

Windows 10から[invisible borderが導入された](https://qiita.com/7of9/items/cca6839d914ce52897d9)ため、Windows 7, 8.1, 10上でのソフト動作（位置調整）が変わってしまう。

それを避けるためgetVisibleWindowSize()を実装したが、様々なフォームから使用するにはソース分離する方がいいだろう。

下記においてソース分離した。

### code

```UtilFormSize_noInvisibleBorder.h
//---------------------------------------------------------------------------

#ifndef UtilFormSize_noInvisibleBorderH
#define UtilFormSize_noInvisibleBorderH
//---------------------------------------------------------------------------

/*
Windows 10から導入された「Invisible border」。
Windows 7, 8.1, 10で同じ位置調整処理を使えるようにするため、Invisible borderを含まない
サイズを返す関数を用意した。
*/

class CUtilFormSize_noInvisibleBorder
{
private:
    static void __fastcall getVisibleWindowSize(TForm *formPtr, TRect *rectPtr);
public:
    static int __fastcall GetHeight(TForm *formPtr);
    static int __fastcall GetWidth(TForm *formPtr);
    // テスト関数
    static void __fastcall Test_showHeightAndWidth(TForm *formPtr);
};

#endif
```

```UtilFormSize_noInvisibleBorder.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "UtilFormSize_noInvisibleBorder.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)

/*
v0.1 2018/05/07
    - Test_showHeightAndWidth()追加
    - GetWidth()追加
    - GetHeight()追加
    - getVisibleWindowSize()追加
*/

//---------------------------------------------------------------------------
// private関数
//
/*static*/void __fastcall CUtilFormSize_noInvisibleBorder::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)の方を返す
    //
    // !!!ただしWindows 10の場合、FormShow時には正しい値を返さない!!!
    // FormShow後に実行すること

    rectPtr->left = arect_inv.left;
    rectPtr->top = arect_inv.top;
    rectPtr->right = arect_inv.right;
    rectPtr->bottom = arect_inv.bottom;
}

//---------------------------------------------------------------------------
// public関数
//
/*static*/ int __fastcall CUtilFormSize_noInvisibleBorder::GetHeight(TForm *formPtr)
{
    // !!!Windows 10の場合、FormShow時には正しい値を返さない!!!
    // FormShow後に実行すること

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

    TRect arect;

    getVisibleWindowSize(formPtr, &arect);
    return arect.bottom - arect.top;
}

/*static*/ int __fastcall CUtilFormSize_noInvisibleBorder::GetWidth(TForm *formPtr)
{
    // !!!Windows 10の場合、FormShow時には正しい値を返さない!!!
    // FormShow後に実行すること

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

    TRect arect;

    getVisibleWindowSize(formPtr, &arect);
    return arect.right - arect.left;
}

//---------------------------------------------------------------------------
// テスト関数
//
/*static*/ void __fastcall CUtilFormSize_noInvisibleBorder::Test_showHeightAndWidth(TForm *formPtr)
{
    if (formPtr == NULL) {
        return; // error
    }

    int hei = CUtilFormSize_noInvisibleBorder::GetHeight(formPtr);
    int wid = CUtilFormSize_noInvisibleBorder::GetWidth(formPtr);

    String msg = String().sprintf(L"%d x %d", hei, wid);
    ShowMessage(msg);
}
```

### 使用例

Test_showHeightAndWidth()の実装を参考にする。

### 注意事項

Windows 10においてはFormShow時にフォームのHeight, Widthが正しく取得できない。

- [C++ Builder 10.2 Tokyo > Forms > Height > Windows 10: 実行タイミングによって異なる | Windows 7, 8.1: 実行タイミングによらず同じ > FormShow時とFormShow後](https://qiita.com/7of9/items/fcd4e85d87857e513393)


FormShow後にHeightとWidthを取得すると良い (下記参照)。

- [C++ Builder 10.2 Tokyo > FormShow後に一回だけ実行する > Window Message処理](https://qiita.com/7of9/items/47e8fb9eda9cc1139d24)
- [C++ Builder 10.2 Tokyo > FormShow後に一回だけ実行する > FormActivate()処理](https://qiita.com/7of9/items/bc7cd3917a444a6f7338)