ドラッグ&ドロップでファイルパスを取得する(C++)

このチュートリアルでは、デスクトップアプリケーションのウィンドウにドラッグ&ドロップでファイルパスを取得する方法について説明します。 作成するアプリケーションの例では、Direct2D コンテンツをイメージファイルに保存する(C++)で開発したコードをパターンとして使用して、ドラッグ&ドロップでファイルパスを取得してイメージを表示します。 ‎

ix 重要

簡潔にするために、一部のコードステートメントはこのテキストでは省略されています。 このドキュメントの最後の コードの‎‎ビルド セクションに、完全なコードが示されています。

Visual Studio で Windows デスクトップ プロジェクトを開くには

  1. Visual Stadio 2022 を起動して、[プロジェクトやソリューションを開く] を選択します。あるいは、メインメニューから、[ファイル] > [開く] > [プロジェクト/ソリューション] の順に選択して、[プロジェクト/ソリューションを開く] ダイアログボックスを開きます。

  2. ファイル選択で、[Project1.sln] を 選択して、 [開く] を選択してプロジェクトを開きます。

これで、プロジェクトが開かれ、ソースファイルがエディタで開かれます。 続行するには、コードを作成する‎ に進んでください。

‎コードを作成する‎‎

次に、Visual Studio で Windows デスクトップ アプリケーションでドラッグ&ドロップでファイルパスを取得する方法について説明します。

ドラッグ&ドロップでファイルパスを取得するには

  1. WM_CREATE を受信したときに、DragAcceptFiles にウィンドウのハンドル指定してウィンドウがドロップされたファイルを受け入れるかどうかを登録します。

  2. C++

    case WM_CREATE:
        ...
    
        // ドロップ登録
        DragAcceptFiles(hWnd, TRUE);
        break;
  3. WM_DROPFILES を受信したときに、ドロップされたファイル名を取得するには、 DragQueryFile にドロップされたファイルのファイル名を受け取るバッファのアドレスを指定します。

  4. ReadToImageFile は、DragQueryFile で取得したファイルパスのコンテナ形式およびファイルサイズを取得します。

    InvalidateRect 関数は、ウィンドウの WM_PAINT メッセージを間接的に生成できます。

  5. DragFinish は、アプリケーションへのファイル名の転送に使用するためにシステムが割り当てたメモリを解放します。

    C++

    case WM_DROPFILES:
        // ドロップされたファイル名を取得
        DragQueryFile((HDROP)wParam, 0, chMsg, MAX_PATH);
        hr = ReadToImageFile(hWnd, chMsg);
        if (SUCCEEDED(hr))
        {
            InvalidateRect(hWnd, &rc, FALSE);
        }
        // メモリを解放
        DragFinish((HDROP)wParam);
        break;

コードのビルド

約束どおり、動作するアプリケーションの完全なコードを次に示します。

この例をビルドするには

  1. エディターで Source.cpp に入力したすべてのコードを削除します。 このコード例をコピーし、Source.cpp に貼り付けます。

    C++

    #include <windows.h>
    #include <windowsx.h>
    #include <d2d1.h>
    #include <commctrl.h>
    #include <strsafe.h>
    #include <wincodec.h>
    #include <shobjidl.h>
    #include <shlwapi.h>
    #include "resource.h"
    
    #pragma comment(lib, "d2d1.lib" )
    #pragma comment(lib, "comctl32.lib")
    #pragma comment(lib, "Windowscodecs.lib")
    #pragma comment(lib, "Shlwapi.lib")
    
    // グローバル変数:
    HINSTANCE hInst;                        // 現在のインターフェイス
    WINDOWPLACEMENT wndpl;                  // WINDOWPLACEMENT 構造体へのポインタ
    DWORD wndplSize = sizeof(wndpl);        // WINDOWPLACEMENT 構造体のサイズ
    MENUITEMINFO mii;                       // MENUITEMINFO型変数の宣言
    HMENU hMenu;                            // メニューのハンドル
    HICON hIcon;                            // アイコンのハンドル
    HWND hToolbar;                          // ツールバーのハンドル
    HIMAGELIST himl, himl_Disable;          // イメージリストのハンドル
    INT rebar_height;                       // レバーコントロールの高さ
    HWND hToolTip;                          // ツールチップのハンドル
    TTTOOLINFO toolInfo;                    // TTTOOLINFO 構造体へのポインタ
    HWND hStatus;                           // ステータスバーのハンドル
    INT status_height;                      // ステータスバーの高さ
    WCHAR chMsg[MAX_PATH];                  // 一時文字列
    WCHAR szSize[MAX_PATH] = L"0 バイト";   // ファイルサイズ変換文字列
    BOOL readImage = FALSE;                 // イメージファイル読み込み
    WCHAR szFilePath[MAX_PATH];             // ファイルパス記憶
    UINT iFileType;                         // ファイルの種類
    GUID containerFormat;                   // コンテナ形式
    
    RECT rc;                                // RECT 構造体へのポインタ
    BOOL first = TRUE;                      // 初回起動
    FLOAT fAngle = 0.0f;                    // 回転角度 
    FLOAT fZoom = 1.0f;                     // ズーム倍率
    BOOL actual = FALSE;                    // ウィンドウに合わせてズーム
    BOOL movement;                          // 移動開始記憶
    POINT pt;                               // マウスポイント位置
    POINT pt1;                              // マウスポイント開始位置
    D2D1_SIZE_F scaleSize;                  // スケール変換サイズ
    D2D1_SIZE_F marginSize;                 // ウインドウ余白サイズ
    D2D1_SIZE_F translationSize;            // 移動サイズ
    D2D1_SIZE_F translationSize1;           // 移動サイズ記憶
    
    ID2D1Factory* pD2d1Factory = nullptr;
    ID2D1DCRenderTarget* pDCRenderTarget = nullptr;
    IWICImagingFactory* pIWICFactory = nullptr;
    
    // ズーム配列
    FLOAT zoom[] = {
        0.25f, 0.33f, 0.5f, 0.67f, 0.75f, 0.8f, 0.9f, 1.0f,
        1.1f, 1.25f, 1.5f, 1.75f, 2.0f, 2.5f, 3.0f, 4.0f, 5.0f };
    
    // ファイルの種類の配列
    COMDLG_FILTERSPEC rgSpec[] = {
        { L"ビットマップ ファイル", L"*.bmp;*.dib" },
        { L"JPEG", L"*.jpg;*.jpeg;*.jpe" },
        { L"TIFF", L"*.tif;*.tiff" },
        { L"GIF", L"*.gif" },
        { L"PNG", L"*.png" },
        { L"すべてのピクチャ ファイル", L"*.bmp;*.dib;*.jpg;*.jpeg;*.jpe;*.tif;*.tiff;*.gif;*.png" }
    };
    
    // コンテナ形式の配列
    GUID guid[] = {
        GUID_ContainerFormatBmp,
        GUID_ContainerFormatJpeg,
        GUID_ContainerFormatTiff,
        GUID_ContainerFormatGif,
        GUID_ContainerFormatPng
    };
    
    // このコード モジュールに含まれる関数の宣言を転送します:
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    HRESULT CreateDeviceResources();
    HRESULT OnRender(HWND, const PAINTSTRUCT& ps);
    void ChangeImgSizeItem(BOOL);
    void EnableZoomItem(FLOAT);
    void AddIconToMenuItem(HMENU, int, HICON);
    HRESULT Create32BitHBITMAP(HDC, const SIZE*, void**, HBITMAP*);
    HWND CreateToolbarToRebar(HWND);
    HWND CreateStatusbar(HWND);
    HRESULT CommonItemDialog(HWND, const IID& rclsid);
    HRESULT ReadToImageFile(HWND, LPCWSTR);
    HRESULT SaveToImageFile(LPCWSTR, LPCWSTR, UINT, UINT, GUID);
    
    int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
        _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
    {
        WNDCLASSEX wcex = { };
    
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
        wcex.lpfnWndProc = WndProc;
        wcex.cbClsExtra = 0;
        wcex.cbWndExtra = 0;
        wcex.hInstance = hInstance;
        wcex.hIcon = (HICON)LoadImage(wcex.hInstance, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON,
            GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0);
        wcex.hCursor = (HCURSOR)LoadImage(nullptr, IDC_HAND, IMAGE_CURSOR,
            GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_SHARED);
        wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
        wcex.lpszClassName = L"Project1";
        wcex.hIconSm = (HICON)LoadImage(wcex.hInstance, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON,
            GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
    
        RegisterClassEx(&wcex);
    
        hInst = hInstance;  // グローバル変数にインスタンス ハンドルを格納する
    
        // メイン ウィンドウを作成します。
        HWND hwnd = CreateWindowEx(0, L"Project1", L"Project1", WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, 0, 560, 372, nullptr, nullptr, hInstance, nullptr);
    
        if (!hwnd)
        {
            return 0;
        }
    
        // WINDOWPLACEMENT 構造体の初期化
        wndpl.length = sizeof(WINDOWPLACEMENT);
    
        // レジストリからウィンドウの表示状態と位置情報を取得
        LONG retCode = RegGetValue(HKEY_CURRENT_USER, L"SOFTWARE\\Project1", L"wndpl",
            RRF_RT_REG_BINARY, nullptr, &wndpl, &wndplSize);
        if (retCode != ERROR_SUCCESS)
        {
            // ウインドウの表示状態と位置情報を取得
            GetWindowPlacement(hwnd, &wndpl);
        }
    
        // ウィンドウ表示
        SetWindowPlacement(hwnd, &wndpl);
    
        // アクセラレータテーブルをロードします。
        HACCEL haccel = LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_ACCELERATOR1));
    
        MSG msg;
    
        // メイン メッセージ ループ:
        while (GetMessage(&msg, nullptr, 0, 0))
        {
            if (!TranslateAccelerator(hwnd, haccel, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        return (int)msg.wParam;
    }
    
    // メインウィンドウプロシージャ
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        PAINTSTRUCT ps;
        HDC hdc;
    
        HRESULT hr = S_OK;		    // 戻り値
        static HWND hRebar;         // レバーコントロールのハンドル
    
        int part_pos[6] = { };
    
        switch (message)
        {
        case WM_CREATE:
            // COM初期化
            hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    
            if (SUCCEEDED(hr))
            {
                // WIC ファクトリを作成します。
                hr = CoCreateInstance(
                    CLSID_WICImagingFactory,
                    NULL,
                    CLSCTX_INPROC_SERVER,
                    IID_PPV_ARGS(&pIWICFactory)
                );
    
                if (SUCCEEDED(hr))
                {
                    // Direct2D ファクトリを作成します。
                    hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2d1Factory);
                }
            }
            if (FAILED(hr))
            {
                return -1;      // CreateWindowEx に失敗します。
            }
    
            hMenu = GetMenu(hWnd);	// メニューのハンドルを取得
            // MENUITEMINFO の初期化
            mii.cbSize = sizeof(MENUITEMINFO);
            mii.fMask = MIIM_TYPE | MIIM_ID;
            // メニュー項目を無効
            EnableMenuItem(hMenu, IDM_SAVE, MF_GRAYED);
            EnableMenuItem(hMenu, IDM_SAVEAS, MF_GRAYED);
            // メニューにアイコン表示
            hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON2), IMAGE_ICON,
                GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
            AddIconToMenuItem(hMenu, IDM_OPEN, hIcon);
            hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON3), IMAGE_ICON,
                GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
            AddIconToMenuItem(hMenu, IDM_SAVE, hIcon);
            hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON4), IMAGE_ICON,
                GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
            AddIconToMenuItem(hMenu, IDM_SAVEAS, hIcon);
            hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON5), IMAGE_ICON,
                GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
            AddIconToMenuItem(hMenu, IDM_ROTE, hIcon);
            hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON6), IMAGE_ICON,
                GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
            AddIconToMenuItem(hMenu, IDM_ZOOM, hIcon);
            hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON8), IMAGE_ICON,
                GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
            AddIconToMenuItem(hMenu, IDM_PLUS, hIcon);
            hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON9), IMAGE_ICON,
                GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
            AddIconToMenuItem(hMenu, IDM_MINAS, hIcon);
    
            // レバーコントロールにツールバーを作成します。
            hRebar = CreateToolbarToRebar(hWnd);
            // レバーコントロールのサイズを取得
            GetClientRect(hRebar, (LPRECT)&rc);
            // レバーコントロールの高さ取得
            rebar_height = rc.bottom - rc.top;
    
            // ステータスバーを作成します。
            hStatus = CreateStatusbar(hWnd);
            // ステータスバーのサイズを取得
            GetClientRect(hStatus, (LPRECT)&rc);
            // ステータスバーの高さ取得
            status_height = rc.bottom;
    
            // ドロップ登録
            DragAcceptFiles(hWnd, TRUE);
            break;
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
            case IDM_OPEN:
                // ファイルを開くダイアログオブジェクトを作成
                hr = CommonItemDialog(hWnd, CLSID_FileOpenDialog);
                if (SUCCEEDED(hr))
                {
                    InvalidateRect(hWnd, NULL, FALSE);
                }
                break;
            case IDM_SAVE:
                hr = SaveToImageFile(szFilePath, szFilePath, (UINT)scaleSize.width, (UINT)scaleSize.height, containerFormat);
                if (SUCCEEDED(hr))
                {
                    hr = ReadToImageFile(hWnd, szFilePath);
                    if (SUCCEEDED(hr))
                    {
                        InvalidateRect(hWnd, NULL, FALSE);
                    }
                }
                break;
            case IDM_SAVEAS:
                // ファイルを保存ダイアログオブジェクトを作成
                hr = CommonItemDialog(hWnd, CLSID_FileSaveDialog);
                if (SUCCEEDED(hr))
                {
                    InvalidateRect(hWnd, NULL, FALSE);
                }
                break;
            case IDM_EXIT:
                //「閉じる」にメッセージを送る
                SendMessage(hWnd, WM_CLOSE, 0, 0);
                break;
            case IDM_ROTE:
                fAngle = fAngle + 90.0f;
                if (fAngle == 360.0f)
                {
                    fAngle = 0.0f;
                }
                translationSize = { 0.0f, 0.0f };
                InvalidateRect(hWnd, NULL, FALSE);
                break;
            case IDM_ZOOM:
                actual = TRUE;
                ChangeImgSizeItem(TRUE);
                InvalidateRect(hWnd, NULL, FALSE);
                break;
            case IDM_ACTUAL:
                actual = FALSE;
                fZoom = 1.0f;
                ChangeImgSizeItem(FALSE);
                InvalidateRect(hWnd, NULL, FALSE);
                break;
            case IDM_MINAS:
                for (int j = 16; j > 0; j--)
                {
                    if (fZoom <= zoom[j] && fZoom > zoom[j - 1])
                    {
                        fZoom = zoom[j - 1];
                        break;
                    }
                    if (fZoom > zoom[j])
                    {
                        fZoom = zoom[j];
                        break;
                    }
                }
    
                translationSize = { 0.0f, 0.0f };
                actual = FALSE;
                ChangeImgSizeItem(FALSE);
                EnableZoomItem(fZoom);
                InvalidateRect(hWnd, NULL, FALSE);
                break;
            case IDM_PLUS:
                for (int j = 0; j < 16; j++)
                {
                    if (fZoom >= zoom[j] && fZoom < zoom[j + 1])
                    {
                        fZoom = zoom[j + 1];
                        break;
                    }
                }
                translationSize = { 0.0f, 0.0f };
                actual = FALSE;
                ChangeImgSizeItem(FALSE);
                EnableZoomItem(fZoom);
                InvalidateRect(hWnd, NULL, FALSE);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
            break;
        case WM_LBUTTONDBLCLK:
            if (actual == TRUE)
            {
                actual = FALSE;
                fZoom = 1.0f;
                ChangeImgSizeItem(FALSE);
            }
            else
            {
                actual = TRUE;
                ChangeImgSizeItem(TRUE);
            }
            EnableZoomItem(fZoom);
            InvalidateRect(hWnd, NULL, FALSE);
            break;
        case WM_MOUSEMOVE:
            // マウス左ボタンが押されてるとき
            if (wParam == MK_LBUTTON)
            {
                // 移動開始
                if (movement == FALSE)
                {
                    // 水平垂直移動を一時記憶
                    translationSize1 = translationSize;
    
                    // 水平方向と垂直方向の位置を取得
                    pt1.x = GET_X_LPARAM(lParam);
                    pt1.y = GET_Y_LPARAM(lParam);
                    movement = TRUE;    // 移動開始記憶
                }
                else
                {
                    // 水平方向と垂直方向の位置を取得
                    pt.x = GET_X_LPARAM(lParam);
                    pt.y = GET_Y_LPARAM(lParam);
    
                    // 水平余白が 0 より小さい場合
                    if (marginSize.width < 0.0f)
                    {
                        // 水平移動サイズを取得
                        translationSize.width = translationSize1.width + pt.x - pt1.x;
                    }
    
                    // 垂直余白が 0 より小さい場合
                    if (marginSize.height < 0.0f)
                    {
                        // 垂直移動サイズを取得
                        translationSize.height = translationSize1.height + pt.y - pt1.y;
                    }
                    InvalidateRect(hWnd, &rc, FALSE);
                }
            }
    
            // マウスの左ボタンが押されてない場合
            if (wParam != MK_LBUTTON && movement == TRUE)
            {
                movement = FALSE;   // 移動開始記憶
            }
            break;
        case WM_GETMINMAXINFO:
            MINMAXINFO* pmmi;               // MINMAXINFO 構造体へのポインタ
            pmmi = (MINMAXINFO*)lParam;
            pmmi->ptMinTrackSize.x = 560;   // 最小トラッキング幅(560px)
            pmmi->ptMinTrackSize.y = 372;   // 最小トラッキング高さ(372px)
            break;
        case WM_DROPFILES:
            // ドロップされたファイル名を取得
            DragQueryFile((HDROP)wParam, 0, chMsg, MAX_PATH);
            hr = ReadToImageFile(hWnd, chMsg);
            if (SUCCEEDED(hr))
            {
                InvalidateRect(hWnd, &rc, FALSE);
            }
            // メモリを解放
            DragFinish((HDROP)wParam);
            break;
        case WM_SIZE:
            SendMessage(hRebar, WM_SIZE, wParam, lParam);
            SendMessage(hStatus, WM_SIZE, wParam, lParam);
    
            // 各パーツの右端の座標を設定します。 
            part_pos[0] = LOWORD(lParam) - 543;
            part_pos[1] = LOWORD(lParam) - 413;
            part_pos[2] = LOWORD(lParam) - 283;
            part_pos[3] = LOWORD(lParam) - 153;
            part_pos[4] = LOWORD(lParam) - 73;
            part_pos[5] = -1;
    
            // ステータスウィンドウ内のパーツの数と、各パーツの右端の座標を設定します。
            SendMessage(hStatus, SB_SETPARTS, (WPARAM)6, (LPARAM)part_pos);
            break;
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            OnRender(hWnd, ps);
            EndPaint(hWnd, &ps);
            break;
        case WM_CLOSE:
            if (pDCRenderTarget != nullptr)
            {
                // ID2D1DCRenderTarget の破棄
                pDCRenderTarget->Release();
            }
    
            if (pD2d1Factory != nullptr)
            {
                // ID2D1Factory の破棄
                pD2d1Factory->Release();
            }
            DestroyWindow(hWnd);
            break;
        case WM_DESTROY:
            // WINDOWPLACEMENT 構造体の初期化
            wndpl.length = sizeof(WINDOWPLACEMENT);
            // ウインドウの表示状態と位置情報を取得
            GetWindowPlacement(hWnd, &wndpl);
            // ウインドウの表示状態と位置情報をレジストリへ保存
            RegSetKeyValue(HKEY_CURRENT_USER, L"SOFTWARE\\Project1", L"wndpl",
                REG_BINARY, (LPBYTE)&wndpl, sizeof(WINDOWPLACEMENT));
            ImageList_Destroy(himl);
            ImageList_Destroy(himl_Disable);
            // COMの破棄
            CoUninitialize();
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    
    // デバイスリソースを作成します。
    HRESULT CreateDeviceResources()
    {
        HRESULT hr = S_OK;    // 戻り値
    
        if (!pDCRenderTarget)
        {
            // ピクセル形式を作成し、その形式と alphaMode フィールドを初期化します。
            D2D1_PIXEL_FORMAT format = D2D1::PixelFormat(
                DXGI_FORMAT_B8G8R8A8_UNORM,
                D2D1_ALPHA_MODE_PREMULTIPLIED
            );
    
            // Direct2D レンダーターゲットプロパティを作成します。
            D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
                D2D1_RENDER_TARGET_TYPE_DEFAULT,
                format
            );
    
            // DC レンダーターゲットを作成します。
            hr = pD2d1Factory->CreateDCRenderTarget(
                &props,
                &pDCRenderTarget
            );
        }
        return hr;
    }
    
    // クライアントウィンドウを表示する必要がある場合に呼び出されます。
    HRESULT OnRender(HWND hwnd, const PAINTSTRUCT& ps)
    {
        HRESULT hr;
    
        // クライアント描画領域のサイズを取得します。
        GetClientRect(hwnd, &rc);
        rc.top = rc.top + rebar_height;
        rc.bottom = rc.bottom - status_height;
    
        // DC レンダーターゲットを作成します。
        hr = CreateDeviceResources();
    
        if (SUCCEEDED(hr))
        {
            // DC を DC レンダーターゲットにバインドします。
            hr = pDCRenderTarget->BindDC(ps.hdc, &rc);
        }
    
        if (SUCCEEDED(hr))
        {
            // 描画開始(DC)
            pDCRenderTarget->BeginDraw();
            // 指定した変換をレンダーターゲットに適用し、既存の変換を置き換えます。
            pDCRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
            // 指定した色の描画領域をクリアします。
            pDCRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::LightBlue));
    
            // イメージ ファイルを読み込み、D2DBitmap を作成します。
            ID2D1Bitmap* ppBitmap = nullptr;
    
            if (readImage)
            {
                // デコーダを作成します。
                IWICBitmapDecoder* pDecoder = nullptr;
    
                hr = pIWICFactory->CreateDecoderFromFilename(
                    szFilePath,                     // デコードする画像
                    NULL,                           // 特定のベンダーを優先しない
                    GENERIC_READ,                   // ファイルへの必要な読み取りアクセス
                    WICDecodeMetadataCacheOnDemand, // 必要に応じてメタデータをキャッシュする
                    &pDecoder                       // デコーダーへのポインタ
                );
    
                // デコーダからイメージの最初のフレームを取得します。
                IWICBitmapFrameDecode* pSource = nullptr;
    
                if (SUCCEEDED(hr))
                {
                    hr = pDecoder->GetFrame(0, &pSource);
                }
    
                // フレームを 32bppPBGRA にフォーマット変換します。
                IWICFormatConverter* pConverter = nullptr;
    
                if (SUCCEEDED(hr))
                {
                    hr = pIWICFactory->CreateFormatConverter(&pConverter);
                }
    
                if (SUCCEEDED(hr))
                {
                    // フォーマットコンバーターを初期化します。
                    hr = pConverter->Initialize(
                        pSource,                          // 変換する入力イメージ
                        GUID_WICPixelFormat32bppPBGRA,    // 出力先のピクセルフォーマット
                        WICBitmapDitherTypeNone,          // 指定されたディザパターン
                        NULL,                             // 特定のパレットを指定
                        0.0f,                             // アルファしきい値
                        WICBitmapPaletteTypeCustom        // パレット変換タイプ
                    );
                }
    
                if (SUCCEEDED(hr))
                {
                    // WIC ビットマップから Direct2D ビットマップを作成します。
                    hr = pDCRenderTarget->CreateBitmapFromWicBitmap(
                        pConverter,
                        NULL,
                        &ppBitmap
                    );
                }
    
                if (pConverter != nullptr)
                {
                    // IWICFormatConverter の破棄
                    pConverter->Release();
                }
    
                if (pSource != nullptr)
                {
                    // IWICBitmapFrameDecode の破棄
                    pSource->Release();
                }
    
                if (pDecoder != nullptr)
                {
                    // IWICBitmapDecoder の破棄
                    pDecoder->Release();
                }
            }
    
            if (SUCCEEDED(hr))
            {
                // レンダーターターゲットのサイズを取得します。
                D2D1_SIZE_F renderTargetSize = pDCRenderTarget->GetSize();
    
                //  ビットマップのサイズを設定します。
                D2D1_SIZE_F size = { 560.0f, 314.0f };
    
                if (readImage)
                {
                    size = ppBitmap->GetSize();
                }
    
                // ビットマップの左上隅を取得します。
                D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(
                    (renderTargetSize.width - size.width) / 2.0f,
                    (renderTargetSize.height - size.height) / 2.0f
                );
    
                // レンダーターターゲットの中心点を取得します。
                D2D1_POINT_2F imageCenter = D2D1::Point2F(
                    renderTargetSize.width / 2.0f,
                    (renderTargetSize.height) / 2.0f
                );
    
                D2D1_SIZE_F rotationSize;   // 回転後の画像サイズ
    
                // 回転角度によるサイズ変更
                if (fAngle == 0.0f || fAngle == 180.0f)
                {
                    rotationSize = { size.width, size.height };
                }
                else
                {
                    rotationSize = { size.height, size.width };
                }
    
                // 初回起動の場合
                if (first == TRUE)
                {
                    // 初期表示ウィンドウより画像サイズが大きい場合(初期表示)
                    if (size.width > renderTargetSize.width || size.height > renderTargetSize.height)
                    {
                        actual = TRUE;
                        ChangeImgSizeItem(TRUE);
                    }
                    first = FALSE;
                }
    
                // ウィンドウに合わせてズームの場合
                if (actual == TRUE)
                {
                    translationSize = { 0.0f, 0.0f };
    
                    // ウィンドウに合わせてズーム
                    fZoom = min(renderTargetSize.width / rotationSize.width, renderTargetSize.height / rotationSize.height);
                    EnableZoomItem(fZoom);
                }
    
                //スケール変換サイズを取得します。
                scaleSize = D2D1::SizeF(
                    rotationSize.width * fZoom,
                    rotationSize.height * fZoom
                );
    
                // ウインドウ中央にビットマップを表示した時の余白を取得します。
                marginSize = D2D1::SizeF(
                    (renderTargetSize.width - scaleSize.width) / 2.0f,
                    (renderTargetSize.height - scaleSize.height) / 2.0f
                );
    
                // 水平余白が 0 より小さい場合
                if (marginSize.width < 0.0f)
                {
                    // 水平移動が水平左余白より大きい場合
                    if (translationSize.width > -marginSize.width)
                    {
                        // 水平移動を水平左余白に設定
                        translationSize.width = -marginSize.width;
                    }
                    // 水平移動が水平右余白より小さい場合
                    if (translationSize.width < marginSize.width)
                    {
                        // 水平移動を水平右余白に設定
                        translationSize.width = marginSize.width;
                    }
                }
                else
                {
                    // 水平移動を 0 に設定
                    translationSize.width = 0.0f;
                }
                //  垂直余白が 0 より小さい場合
                if (marginSize.height < 0.0f)
                {
                    // 垂直移動が垂直上余白より大きい場合
                    if (translationSize.height > -marginSize.height)
                    {
                        // 垂直移動を垂直上余白に設定
                        translationSize.height = -marginSize.height;
                    }
                    // 垂直移動が垂直下余白より小さい場合
                    if (translationSize.height < marginSize.height)
                    {
                        // 垂直移動を垂直下余白に設定
                        translationSize.height = marginSize.height;
                    }
                }
                else
                {
                    // 垂直移動を 0 に設定
                    translationSize.height = 0.0f;
                }
    
                // 指定した角度と中心点を持つ回転変換を作成します。
                D2D1_MATRIX_3X2_F rotation = D2D1::Matrix3x2F::Rotation(
                    fAngle,
                    imageCenter
                );
    
                // 指定したスケール係数と中心点を持つスケール変換を作成します。
                D2D1_MATRIX_3X2_F scale = D2D1::Matrix3x2F::Scale(
                    D2D1::Size(fZoom, fZoom),
                    imageCenter
                );
                // 指定した x と y 変位を持つ平行移動変換を作成します。
                D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(
                    D2D1::Size(translationSize.width, translationSize.height)
                );
    
                // 回転、スケール、平行移動変換をレンダーターゲットに適用します。
                pDCRenderTarget->SetTransform(rotation * scale * translation);
    
                // ビットマップの四角形を作成します。
                D2D1_RECT_F rectangle = D2D1::RectF(
                    upperLeftCorner.x,
                    upperLeftCorner.y,
                    upperLeftCorner.x + size.width,
                    upperLeftCorner.y + size.height
                );
    
                // 移動中でない場合
                if (movement == FALSE)
                {
                    StringCchPrintf(chMsg, MAX_PATH, L"%d × %d px", (UINT32)size.width, (UINT32)size.height);
                    SendMessage(hStatus, SB_SETTEXT, 1 | 0, (WPARAM)chMsg);
                    StringCchPrintf(chMsg, MAX_PATH, L"サイズ: %s", szSize);
                    SendMessage(hStatus, SB_SETTEXT, 2 | 0, (WPARAM)chMsg);
                    StringCchPrintf(chMsg, MAX_PATH, L"%d × %d px", (UINT32)scaleSize.width, (UINT32)scaleSize.height);
                    SendMessage(hStatus, SB_SETTEXT, 3 | 0, (WPARAM)chMsg);
                    StringCchPrintf(chMsg, MAX_PATH, L"%d %%", (INT)(fZoom * 100));
                    SendMessage(hStatus, SB_SETTEXT, 4 | 0, (WPARAM)chMsg);
                    StringCchPrintf(chMsg, MAX_PATH, L"%d °", (int)fAngle);
                    SendMessage(hStatus, SB_SETTEXT, 5 | 0, (WPARAM)chMsg);
                }
    
                // ブラシの生成
                ID2D1SolidColorBrush* pBlackBrush = nullptr;
                ID2D1SolidColorBrush* pWhiteBrush = nullptr;
    
                // 黒色のブラシを作成します。
                hr = pDCRenderTarget->CreateSolidColorBrush(
                    D2D1::ColorF(D2D1::ColorF(D2D1::ColorF::Black, 0.1f)),
                    &pBlackBrush
                );
    
                if (SUCCEEDED(hr))
                {
                    // 白色のブラシを作成します。
                    hr = pDCRenderTarget->CreateSolidColorBrush(
                        D2D1::ColorF(D2D1::ColorF(D2D1::ColorF::White, 0.1f)),
                        &pWhiteBrush
                    );
                }
    
                if (SUCCEEDED(hr))
                {
                    for (float x = 0.0f; rectangle.left + x < rectangle.right; x += 10.0f)
                    {
                        float i = size.width - x;
    
                        if (i > 10.0f)
                        {
                            i = 10.0f;
                        }
    
                        for (float y = 0.0f; rectangle.top + y < rectangle.bottom; y += 10.0f)
                        {
                            float j = size.height - y;
    
                            if (j > 10.0f)
                            {
                                j = 10.0f;
                            }
    
                            // ビットマップの四角形を作成します。
                            D2D1_RECT_F rectangle1 = D2D1::RectF(
                                rectangle.left + x,
                                rectangle.top + y,
                                rectangle.left + x + i,
                                rectangle.top + y + j
                            );
    
                            if (~int(x + y) / 10 % 2)
                            {
                                // 塗りつぶされた四角形を描画します。
                                pDCRenderTarget->FillRectangle(&rectangle1, pBlackBrush);
                            }
                            else
                            {
                                // 塗りつぶされた四角形を描画します。
                                pDCRenderTarget->FillRectangle(&rectangle1, pWhiteBrush);
                            }
                        }
                    }
                }
    
                // ブラシの破棄
                if (pBlackBrush != nullptr)
                {
                    pBlackBrush->Release();
                }
    
                if (pWhiteBrush != nullptr)
                {
                    pWhiteBrush->Release();
                }
    
                // イメージを描画し、現在のウィンドウサイズに拡大縮小します。
                if (ppBitmap != nullptr)
                {
                    // ビットマップを描画
                    pDCRenderTarget->DrawBitmap(
                        ppBitmap,
                        rectangle
                    );
    
                    // ID2D1Bitmap の破棄
                    ppBitmap->Release();
                }
            }
    
            // 描画終了(DC)
            hr = pDCRenderTarget->EndDraw();
    
            if (hr == D2DERR_RECREATE_TARGET)
            {
                hr = S_OK;
    
                if (pDCRenderTarget != nullptr)
                {
                    // ID2D1DCRenderTargetの破棄
                    pDCRenderTarget->Release();
                }
            }
        }
        return hr;
    }
    
    // 画像サイズ項目識別子を変更します。
    void ChangeImgSizeItem(BOOL cmdID)
    {
        if (cmdID)
        {
            mii.wID = IDM_ACTUAL;
            mii.dwTypeData = (LPWSTR)L"実際のサイズに拡大(&R)\tCtr+1";
            SetMenuItemInfo(hMenu, IDM_ZOOM, FALSE, &mii);
            // メニューのアイコン表示変更
            hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON7), IMAGE_ICON,
                GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
            AddIconToMenuItem(hMenu, IDM_ACTUAL, hIcon);
            // ツールバーボタンのビットマップイメージ変更
            SendMessage(hToolbar, TB_SETCMDID, 5, IDM_ACTUAL);
            SendMessage(hToolbar, TB_CHANGEBITMAP, IDM_ACTUAL, (LPARAM)12);
            // ツールバーボタンのツールチップテキスト変更
            toolInfo.uId = IDM_ACTUAL;
            toolInfo.lpszText = MAKEINTRESOURCE(IDM_ACTUAL);
            SendMessage(hToolTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&toolInfo);
        }
        else
        {
            mii.wID = IDM_ZOOM;
            mii.dwTypeData = (LPWSTR)L"ウィンドウに合わせてズーム(&Z)\tCtr+0";
            SetMenuItemInfo(hMenu, IDM_ACTUAL, FALSE, &mii);
            // メニューのアイコン表示変更
            hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON6), IMAGE_ICON,
                GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
            AddIconToMenuItem(hMenu, IDM_ZOOM, hIcon);
            // ツールバーボタンのビットマップイメージ変更
            SendMessage(hToolbar, TB_SETCMDID, 5, IDM_ZOOM);
            SendMessage(hToolbar, TB_CHANGEBITMAP, IDM_ZOOM, (LPARAM)11);
            // ツールバーボタンのツールチップテキスト変更
            toolInfo.uId = IDM_ZOOM;
            toolInfo.lpszText = MAKEINTRESOURCE(IDM_ZOOM);
            SendMessage(hToolTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&toolInfo);
        }
    }
    
    // ズーム項目識別子の有効または無効表示を変更します。
    void EnableZoomItem(FLOAT fZoom)
    {
        if (fZoom <= 0.25f)
        {
            EnableMenuItem(hMenu, IDM_MINAS, MF_DISABLED);
            SendMessage(hToolbar, TB_ENABLEBUTTON, IDM_MINAS, FALSE);
        }
        else
        {
            EnableMenuItem(hMenu, IDM_MINAS, MF_ENABLED);
            SendMessage(hToolbar, TB_ENABLEBUTTON, IDM_MINAS, TRUE);
        }
    
        if (fZoom >= 5.0f)
        {
            EnableMenuItem(hMenu, IDM_PLUS, MF_DISABLED);
            SendMessage(hToolbar, TB_ENABLEBUTTON, IDM_PLUS, FALSE);
        }
        else
        {
            EnableMenuItem(hMenu, IDM_PLUS, MF_ENABLED);
            SendMessage(hToolbar, TB_ENABLEBUTTON, IDM_PLUS, TRUE);
        }
    }
    
    // メニュー項目にアイコンを追加
    void AddIconToMenuItem(HMENU hmenu, int iItem, HICON hicon)
    {
        HRESULT hr = E_OUTOFMEMORY;
        HBITMAP hbmp = NULL;
    
        MENUITEMINFO mii = { }; // MENUITEMINFO型変数の宣言
        SIZE sizIcon = { };     // SIZE型変数の宣言
    
        sizIcon.cx = GetSystemMetrics(SM_CXSMICON);
        sizIcon.cy = GetSystemMetrics(SM_CYSMICON);
    
        HDC hdcDest = CreateCompatibleDC(NULL);
        if (hdcDest)
        {
            hr = Create32BitHBITMAP(hdcDest, &sizIcon, NULL, &hbmp);
            if (SUCCEEDED(hr))
            {
                hr = E_FAIL;
                HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcDest, hbmp);
                if (hbmpOld)
                {
                    if (DrawIconEx(hdcDest, 0, 0, hicon,
                        sizIcon.cx, sizIcon.cy, 0, NULL, DI_NORMAL))
                    {
                        hr = S_OK;
                    }
                    SelectObject(hdcDest, hbmpOld);
                }
            }
            DeleteDC(hdcDest);
    
            if (SUCCEEDED(hr))
            {
                mii.cbSize = sizeof(MENUITEMINFO);
                mii.fMask = MIIM_BITMAP;
                mii.hbmpItem = hbmp;
                SetMenuItemInfo(hmenu, iItem, FALSE, &mii);
            }
    
            if (FAILED(hr))
            {
                DeleteObject(hbmp);
                hbmp = NULL;
            }
        }
    }
    
    // 32 ビットのビットマップを作成
    HRESULT Create32BitHBITMAP(HDC hdc, const SIZE* psize, void** ppvBits, HBITMAP* phBmp)
    {
        *phBmp = NULL;
    
        BITMAPINFO bmi;
    
        RtlZeroMemory(&bmi, sizeof(BITMAPINFO));
        bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmi.bmiHeader.biWidth = psize->cx;
        bmi.bmiHeader.biHeight = psize->cy;
        bmi.bmiHeader.biPlanes = 1;
        bmi.bmiHeader.biBitCount = 32;
        bmi.bmiHeader.biCompression = BI_RGB;
    
        *phBmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, ppvBits, NULL, 0);
    
        return (NULL == *phBmp) ? E_OUTOFMEMORY : S_OK;
    }
    
    // レバーコントロールにツールバーを作成
    HWND CreateToolbarToRebar(HWND hwnd)
    {
        // コモンコントロールを初期化します。
        INITCOMMONCONTROLSEX icex = { };
        icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
        icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES;
        InitCommonControlsEx(&icex);
    
        // レバーコントロールを作成します。
        HWND hRebar = CreateWindowEx(
            0,                      // 拡張スタイルなし
            REBARCLASSNAME,         // クラスネーム
            NULL,                   // ウィンドウタイトル
            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
            CCS_NODIVIDER,          //ウィンドウスタイル
            0, 0,                   // ウィンドウ位置
            0, 0,                   // ウィンドウ幅、高さ
            hwnd,                   // 親ウィンドウ
            (HMENU)NULL,            // コントロール識別子
            (HINSTANCE)hInst,       // インスタンスハンドル
            NULL);
    
        // ツールバーを作成します。
        hToolbar = CreateWindowEx(
            0,                      // 拡張スタイルなし
            TOOLBARCLASSNAME,       // クラスネーム
            NULL,                   // ウィンドウタイトル
            WS_CHILD | WS_VISIBLE | CCS_NODIVIDER | CCS_NORESIZE |
            TBSTYLE_FLAT,           // ウィンドウスタイル
            0, 0,                   // ウィンドウ位置
            0, 0,                   // ウィンドウ幅、高さ
            hRebar,                 // 親ウィンドウ
            (HMENU)NULL,            // コントロール識別子
            (HINSTANCE)hInst,       // インスタンスハンドル
            NULL);
    
        // ツールバーボタンの現在の幅と高さを取得します。
        DWORD dwBtnSize = (DWORD)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0);
    
        REBARBANDINFO rbBand;       // REBARBANDINFO 構造体へのポインタ
    
        // ツールバーのバンドで使用されるバンド情報を初期化します。
        RtlZeroMemory(&rbBand, sizeof(REBARBANDINFO));
        rbBand.cbSize = sizeof(REBARBANDINFO);
        rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE;
        rbBand.fStyle = RBBS_CHILDEDGE | RBBS_NOGRIPPER;
    
        // ツールバーでバンドに固有の値を設定します。
        rbBand.hwndChild = hToolbar;
        rbBand.cyChild = LOWORD(dwBtnSize);
        rbBand.cxMinChild = 8 * HIWORD(dwBtnSize);
        rbBand.cyMinChild = LOWORD(dwBtnSize);
    
        // ツールバーを持つバンドを追加します。
        SendMessage(hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
    
        // ボタンを定義します。
        TBBUTTON tbButton[8] = {
            { 1, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0 },
            { 2, IDM_SAVE, 0, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0 },
            { 3, IDM_SAVEAS, 0, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0 },
            { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0 , 0 },
            { 10, IDM_ROTE, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0 },
            { 11, IDM_ZOOM, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0 },
            { 13, IDM_MINAS, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0 },
            { 14, IDM_PLUS, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0 } };
    
        // ボタンを追加します。
        SendMessage(hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
        SendMessage(hToolbar, TB_ADDBUTTONS, 8, (LPARAM)&tbButton);
    
        // ツールバーボタンにビットマップイメージを追加します。
        himl = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 15, 0);
        himl_Disable = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 15, 0);
        HBITMAP hbmImage = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP1),
            IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
        HBITMAP hbmDisable = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP2),
            IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
        ImageList_AddMasked(himl, hbmImage, CLR_DEFAULT);
        ImageList_AddMasked(himl_Disable, hbmDisable, CLR_DEFAULT);
        SendMessage(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl);
        SendMessage(hToolbar, TB_SETDISABLEDIMAGELIST, 0, (LPARAM)himl_Disable);
        DeleteObject(hbmImage);
        DeleteObject(hbmDisable);
    
        // ツールチップを作成します。
        hToolTip = CreateWindowEx(
            0,                      // 拡張スタイルなし
            TOOLTIPS_CLASS,         // クラスネーム
            NULL,                   // ウィンドウタイトル
            TTS_ALWAYSTIP,          // ウィンドウスタイル
            CW_USEDEFAULT,          // ウィンドウ水平位置
            CW_USEDEFAULT,          // ウィンドウ垂直位置
            CW_USEDEFAULT,          // ウィンドウ幅
            CW_USEDEFAULT,          // ウィンドウ高さ
            hwnd,                   // 親ウィンドウ
            (HMENU)NULL,            // コントロール識別子
            (HINSTANCE)hInst,       // インスタンスハンドル
            NULL);
    
        // ツールチップコントロールをツールバーに関連付けます。
        RtlZeroMemory(&toolInfo, sizeof(TTTOOLINFO));
        toolInfo.cbSize = sizeof(TTTOOLINFO);
        toolInfo.hwnd = hToolbar;
        toolInfo.uFlags = TTF_SUBCLASS;
        toolInfo.hinst = hInst;
        for (int i = 0; i < 8; i++)
        {
            toolInfo.uId = tbButton[i].idCommand;
            toolInfo.lpszText = MAKEINTRESOURCE(tbButton[i].idCommand);
            SendMessage(hToolTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
        }
        SendMessage(hToolbar, TB_SETTOOLTIPS, (WPARAM)hToolTip, 0);
    
        return hRebar;
    }
    
    // ステータスバーを作成します。
    HWND CreateStatusbar(HWND hwnd)
    {
        // コモンコントロールを初期化します。
    /*  INITCOMMONCONTROLSEX icex = {};
        icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
        icex.dwICC = ICC_BAR_CLASSES;
        InitCommonControlsEx(&icex); */
    
        // ステータスバーの作成
        HWND hStatus = CreateWindowEx(
            0,                      // 拡張スタイルなし
            STATUSCLASSNAME,        // クラスネーム
            NULL,                   // ウィンドウタイトル
            WS_CHILD | WS_VISIBLE | CCS_NODIVIDER |
            SBARS_SIZEGRIP,         // ウィンドウスタイル
            0, 0,                   // ウィンドウ位置
            0, 0,                   // ウィンドウ幅、高さ
            hwnd,                   // 親ウィンドウ
            (HMENU)NULL,            // コントロール識別子
            (HINSTANCE)hInst,       //インスタンスハンドル
            NULL);
    
        int part_pos[6] = { };
    
        // ステータス ウィンドウ内のパーツの数と、各パーツの右端の座標を設定します。
        SendMessage(hStatus, SB_SETPARTS, (WPARAM)6, (LPARAM)part_pos);
    
        // ステータスバーのパーツのアイコンを設定します。
        hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON12), IMAGE_ICON,
            GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
        SendMessage(hStatus, SB_SETICON, 1, (WPARAM)hIcon);
        hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON3), IMAGE_ICON,
            GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
        SendMessage(hStatus, SB_SETICON, 2, (WPARAM)hIcon);
        hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON11), IMAGE_ICON,
            GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
        SendMessage(hStatus, SB_SETICON, 3, (WPARAM)hIcon);
        hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON10), IMAGE_ICON,
            GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
        SendMessage(hStatus, SB_SETICON, 4, (WPARAM)hIcon);
        hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON5), IMAGE_ICON,
            GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
        SendMessage(hStatus, SB_SETICON, 5, (WPARAM)hIcon);
    
        return hStatus;
    }
    
    // 共通項目ダイアログ
    HRESULT CommonItemDialog(HWND hwnd, const IID& rclsid)
    {
        // COM初期化
        HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED |
            COINIT_DISABLE_OLE1DDE);
    
        if (SUCCEEDED(hr))
        {
            // ファイルを開くまたは保存ダイアログオブジェクトを作成
            IFileDialog* pfd = nullptr;
            hr = CoCreateInstance(rclsid,
                nullptr,
                CLSCTX_INPROC_SERVER,
                IID_PPV_ARGS(&pfd));
    
            if (SUCCEEDED(hr))
            {
                // 開くダイアログオブジェクトの場合
                if (rclsid == CLSID_FileOpenDialog)
                {
                    // ファイルの種類を開くダイアログに設定します。
                    hr = pfd->SetFileTypes(6, rgSpec);
    
                    if (SUCCEEDED(hr))
                    {
                        // 選択したファイルの種類のインデックスを「すべての画像ファイル」に設定します。
                        hr = pfd->SetFileTypeIndex(6);
                    }
                }
    
                // 保存ダイアログオブジェクトの場合
                if (rclsid == CLSID_FileSaveDialog)
                {
                    // ファイルの種類を保存ダイアログに設定します。
                    hr = pfd->SetFileTypes(5, rgSpec);
                    if (SUCCEEDED(hr))
                    {
                        // 選択したファイルの種類のインデックスを読み込まれたファイルに設定します。
                        hr = pfd->SetFileTypeIndex(iFileType);
                        if (SUCCEEDED(hr))
                        {
                            // 既定の拡張子を「.png」ファイルに設定します。 
                            hr = pfd->SetDefaultExtension(L"png");
                            if (SUCCEEDED(hr))
                            {
                                // ファイル名表示設定
                                hr = pfd->SetFileName(PathFindFileName(szFilePath));
                            }
                        }
                    }
                }
    
                if (SUCCEEDED(hr))
                {
                    // 「開く」または「保存」ダイアログを表示する
                    hr = pfd->Show(hwnd);
    
                    if (SUCCEEDED(hr))
                    {
                        // ユーザーが「開く」または「保存」ボタンをクリックすると、結果が取得されます。
                        IShellItem* psi;
                        hr = pfd->GetResult(&psi);
                        if (SUCCEEDED(hr))
                        {
                            // ファイルパスを取得
                            PWSTR pszFilePath = NULL;
    
                            hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
                            if (SUCCEEDED(hr))
                            {
                                // 開くダイアログオブジェクトの場合
                                if (rclsid == CLSID_FileOpenDialog)
                                {
                                    hr = ReadToImageFile(hwnd, pszFilePath);
                                }
    
                                // 保存ダイアログオブジェクトの場合
                                if (rclsid == CLSID_FileSaveDialog)
                                {
                                    // コンテナ形式を取得
                                    UINT piFileType;
    
                                    hr = pfd->GetFileTypeIndex(&piFileType);
                                    if (SUCCEEDED(hr))
                                    {
                                        containerFormat = guid[piFileType - 1];
    
                                        hr = SaveToImageFile(szFilePath, pszFilePath, (UINT)scaleSize.width, (UINT)scaleSize.height, containerFormat);
                                        if (SUCCEEDED(hr))
                                        {
                                            hr = ReadToImageFile(hwnd, pszFilePath);
                                        }
                                    }
                                }
                                CoTaskMemFree(pszFilePath);
                            }
                            psi->Release();
                        }
                    }
                }
                pfd->Release();
            }
            // COMの破棄
            CoUninitialize();
        }
        return hr;
    }
    
    // イメージファイルへの読み込り
    HRESULT ReadToImageFile(HWND hwnd, LPCWSTR lpszFile)
    {
        HRESULT hr = S_OK;		    // 戻り値
    
        IWICBitmapDecoder* pDecoder = nullptr;
    
        // デコーダを作成します。
        hr = pIWICFactory->CreateDecoderFromFilename(
            lpszFile,                       // デコードするイメージ
            NULL,                           // 特定のベンダーを優先しない
            GENERIC_READ,                   // ファイルに対する必要な読み取りアクセス
            WICDecodeMetadataCacheOnDemand, // 必要に応じてメタデータをキャッシュする
            &pDecoder                       // デコーダへのポインタ
        );
    
        if (SUCCEEDED(hr))
        {
            // イメージのコンテナー形式を取得します。
            hr = pDecoder->GetContainerFormat(&containerFormat);
        }
    
        if (SUCCEEDED(hr))
        {
            hr = E_FAIL;
    
            for (int i = 0; i < 5; i++)
            {
                if (containerFormat == guid[i])
                {
                    iFileType = i + 1;
                    hr = S_OK;
                    break;
                }
            }
        }
    
        if (pDecoder != nullptr)
        {
            // IWICBitmapDecoder の破棄
            pDecoder->Release();
        }
    
        if (SUCCEEDED(hr))
        {
            DWORD nFileSize;
    
            HANDLE hFile = CreateFile(lpszFile, GENERIC_READ,
                0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
            if (hFile != INVALID_HANDLE_VALUE)
            {
                nFileSize = GetFileSize(hFile, NULL);	// ファイルサイズ取得
    
                CloseHandle(hFile);
            }
    
            if (nFileSize != NULL)
            {
                // 異なるサイズの値として表される値を表す文字列に数値を変換
                StrFormatByteSize(nFileSize, szSize, MAX_PATH);
            }
    
            // 保存識別子を有効にします。
            EnableMenuItem(hMenu, IDM_SAVE, MF_ENABLED);
            EnableMenuItem(hMenu, IDM_SAVEAS, MF_ENABLED);
            SendMessage(hToolbar, TB_ENABLEBUTTON, IDM_SAVE, TRUE);
            SendMessage(hToolbar, TB_ENABLEBUTTON, IDM_SAVEAS, TRUE);
    
            // イメージ表示状態を初期化します。
            fAngle = 0.0f;
            fZoom = 1.0f;
            translationSize = { 0.0f, 0.0f };
            first = TRUE;
            actual = FALSE;
            readImage = TRUE;
            ChangeImgSizeItem(FALSE);
            EnableZoomItem(fZoom);
    
            // ファイルパス記憶       
            StringCchCopy(szFilePath, MAX_PATH, lpszFile);
            // ウィンドウタイトルの表示
            StringCchPrintf(chMsg, MAX_PATH, L"%s - Project1", PathFindFileName(lpszFile));
            SetWindowText(hwnd, chMsg);
        }
    
        if (FAILED(hr))
        {
            StringCchPrintf(chMsg, MAX_PATH, L"%s\nこのファイルは読み取れません。\nこのビットマップファイルは無効であるか、または現在サポートされていない書式です。", lpszFile);
            MessageBox(hwnd, chMsg, TEXT("Project1"), MB_OK | MB_ICONEXCLAMATION);
        }
    
        return hr;
    }
    
    // イメージファイルに保存
    HRESULT SaveToImageFile(LPCWSTR lpszDecoder, LPCWSTR lpszEncoder, UINT uiWidth, UINT uiHeight, GUID containerFormat)
    {
        HRESULT hr = S_OK;
    
        // IWICBitmap オブジェクトを作成します。
        IWICBitmap* pWICBitmap = nullptr;
    
        hr = pIWICFactory->CreateBitmap(
            uiWidth,
            uiHeight,
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapCacheOnLoad,
            &pWICBitmap
        );
    
        // WicBitmap レンダーターゲットを作成します。
        ID2D1RenderTarget* pRenderTarget = nullptr;
    
        if (SUCCEEDED(hr))
        {
            hr = pD2d1Factory->CreateWicBitmapRenderTarget(
                pWICBitmap,
                D2D1::RenderTargetProperties(),
                &pRenderTarget
            );
        }
    
        if (SUCCEEDED(hr))
        {
            // このレンダーターゲットで描画を開始します。
            pRenderTarget->BeginDraw();
    
            FLOAT alfa = 1.0f;
    
            // GIF または PNG の場合
            if (containerFormat == GUID_ContainerFormatGif || containerFormat == GUID_ContainerFormatPng)
            {
                alfa = 0.0f;
            }
    
            // 作図領域を指定した色にクリアします。
            pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White, alfa));
    
            IWICBitmapDecoder* pDecoder = nullptr;
    
            hr = pIWICFactory->CreateDecoderFromFilename(
                lpszDecoder,                    // デコードするイメージ
                NULL,                           // 特定のベンダーを優先しない
                GENERIC_READ,                   // ファイルに対する必要な読み取りアクセス
                WICDecodeMetadataCacheOnDemand, // 必要に応じてメタデータをキャッシュする
                &pDecoder                       // デコーダへのポインタ
            );
    
            // 最初のビットマップフレームを取得します。
            IWICBitmapFrameDecode* pSource = nullptr;
    
            if (SUCCEEDED(hr))
            {
                hr = pDecoder->GetFrame(0, &pSource);
            }
    
            // フォーマットコンバーターを作成します。
            IWICFormatConverter* pConverter = nullptr;
    
            if (SUCCEEDED(hr))
            {
                hr = pIWICFactory->CreateFormatConverter(&pConverter);
            }
    
            if (SUCCEEDED(hr))
            {
                // フォーマットコンバーターを初期化します。
                hr = pConverter->Initialize(
                    pSource,                          // 変換する入力ソース
                    GUID_WICPixelFormat32bppPBGRA,    // 出力先のピクセルフォーマット
                    WICBitmapDitherTypeNone,          // 指定されたディザパターン
                    NULL,                             // 特定のパレットを指定
                    0.0f,                             // アルファしきい値
                    WICBitmapPaletteTypeCustom        // パレット変換タイプ
                );
            }
    
            ID2D1Bitmap* ppBitmap = nullptr;
    
            if (SUCCEEDED(hr))
            {
                // WIC ビットマップから Direct2D ビットマップを作成します。
                hr = pRenderTarget->CreateBitmapFromWicBitmap(
                    pConverter,
                    NULL,
                    &ppBitmap
                );
            }
    
            if (pConverter != nullptr)
            {
                // IWICFormatConverter の破棄
                pConverter->Release();
            }
    
            if (pSource != nullptr)
            {
                // IWICBitmapFrameDecoder の破棄
                pSource->Release();
            }
    
            if (pDecoder != nullptr)
            {
                // IWICBitmapDecoder の破棄
                pDecoder->Release();
            }
    
            if (SUCCEEDED(hr))
            {
                // レンダーターターゲットのサイズを取得します。
                D2D1_SIZE_F renderTargetSize = pRenderTarget->GetSize();
    
                // ビットマップのサイズを取得します。
                D2D1_SIZE_F Size = ppBitmap->GetSize();
    
                // ビットマップの左上隅を取得します。
                D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(
                    (renderTargetSize.width - Size.width) / 2.0f,
                    (renderTargetSize.height - Size.height) / 2.0f
                );
    
                // レンダーターターゲットの中心点を取得します。
                D2D_POINT_2F imageCenter = D2D1::Point2F(
                    renderTargetSize.width / 2.0f,
                    renderTargetSize.height / 2.0f
                );
    
                // 指定した角度と中心点を持つ回転変換を作成します。
                D2D1_MATRIX_3X2_F rotation = D2D1::Matrix3x2F::Rotation(
                    fAngle,
                    imageCenter
                );
                // 指定したスケール係数と中心点を持つスケール変換を作成します。
                D2D1_MATRIX_3X2_F scale = D2D1::Matrix3x2F::Scale(
                    D2D1::Size(fZoom, fZoom),
                    imageCenter
                );
    
                // 回転、スケールをレンダーターゲットに適用します。
                pRenderTarget->SetTransform(rotation * scale);
    
                // ビットマップの四角形を作成します。
                D2D1_RECT_F rectangle = D2D1::RectF(
                    upperLeftCorner.x,
                    upperLeftCorner.y,
                    upperLeftCorner.x + Size.width,
                    upperLeftCorner.y + Size.height
                );
    
                if (ppBitmap != nullptr)
                {
                    // ビットマップを描画
                    pRenderTarget->DrawBitmap(
                        ppBitmap,
                        rectangle
                    );
                    // ID2D1Bitmap の破棄
                    ppBitmap->Release();
                }
            }
    
            // レンダーターゲットでの描画操作を終了します。
            hr = pRenderTarget->EndDraw();
        }
    
        // IWICStream クラスの新しいインスタンスを作成します。
        IWICStream* pStream = nullptr;
    
        if (SUCCEEDED(hr))
        {
            hr = pIWICFactory->CreateStream(&pStream);
        }
    
        if (SUCCEEDED(hr))
        {
            // 特定のファイルからストリームを初期化します。
            hr = pStream->InitializeFromFilename(lpszEncoder, GENERIC_WRITE);
        }
    
        // IWICBitmapEncoder クラスの新しいインスタンスを作成します。
        IWICBitmapEncoder* pEncoder = nullptr;
    
        if (SUCCEEDED(hr))
        {
            hr = pIWICFactory->CreateEncoder(containerFormat, NULL, &pEncoder);
        }
    
        if (SUCCEEDED(hr))
        {
            // エンコーダーを IWICStream で初期化し、エンコーダーにビットをエンコードする場所を指示します。 
            hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
        }
    
        // 新しい IWICBitmapFrameEncode インスタンスを作成します。
        IWICBitmapFrameEncode* pFrameEncode = nullptr;
    
        if (SUCCEEDED(hr))
        {
            hr = pEncoder->CreateNewFrame(&pFrameEncode, NULL);
        }
    
        if (SUCCEEDED(hr))
        {
            // 指定されたプロパティを使用してフレームエンコーダーを初期化します。
            hr = pFrameEncode->Initialize(NULL);
        }
    
        if (SUCCEEDED(hr))
        {
            // フレームの出力イメージのサイズを設定します。
            hr = pFrameEncode->SetSize(uiWidth, uiHeight);
        }
    
        if (SUCCEEDED(hr))
        {
            WICPixelFormatGUID format = GUID_WICPixelFormatDontCare;
    
            // エンコーダーが指定されたピクセル形式を使用するように要求します。
            hr = pFrameEncode->SetPixelFormat(&format);
        }
    
        if (SUCCEEDED(hr))
        {
            // ビットマップソースをエンコードします。
            hr = pFrameEncode->WriteSource(pWICBitmap, NULL);
        }
    
        if (SUCCEEDED(hr))
        {
            // フレームをイメージにコミットします。
            hr = pFrameEncode->Commit();
        }
    
        if (SUCCEEDED(hr))
        {
            // イメージのすべての変更をコミットし、ストリームを閉じます。
            hr = pEncoder->Commit();
        }
    
        if (pWICBitmap != nullptr)
        {
            // IWICBitmap の破棄
            pWICBitmap->Release();
        }
    
        if (pRenderTarget != nullptr)
        {
            // ID2D1RenderTarget の破棄
            pRenderTarget->Release();
        }
    
        if (pEncoder != nullptr)
        {
            // IWICBitmapEncoder の破棄
            pEncoder->Release();
        }
    
        if (pFrameEncode != nullptr)
        {
            // IWICBitmapFrameEncode の破棄
            pFrameEncode->Release();
        }
    
        if (pStream != nullptr)
        {
            // IWICStream の破棄
            pStream->Release();
        }
    
        return hr;
    }
  2. [ビルド] メニューの [ソリューションのビルド] をクリックします。 コンパイルの結果は、Visual Studio の [出力] ウィンドウに表示されます。

  3. アプリケーションを実行するには、F5 を押します。イメージファイルをドラッグ&ドロップしてイメージビューアーを起動します。 イメージファイルのコンテナ形式が認識できない場合、警告のメッセージが表示されます。