Virtualization-free custom cursor for dpi-awareness PerMonitorV2 win32 app - to avoid ugly auto-scaling.

We obtain HCURSOR by creating an "icon", not by creating a "cursor", so we don't have to call win11 new API SetThreadCursorCreationScaling(CURSOR_CREATION_SCALING_NONE), so this program should run also on earlier versions of win11 and win10.

#pragma once

#include <map>

/*
CCursorDpi typical usage:

With visual studio resource view, create a cursor resource containing 32, 48, 64, 96 and 128 monochrome (or color) image types

Construct a CCursorDpi object with the ID of the cursor resource above

Call Create() on WM_CREATE

Call DpiChanged() on WM_DPICHANGED

Call GetHCURSOR() on WM_MOUSEMOVE to get the cursor handle for SetCursor()

*/

class CCursorDpi
{
protected:
    bool m_bSuccessfullyConstructed;

    // cursor size to image ordinal map
    std::map<int, int> m_mapImages;

    HCURSOR m_hCursor;
    int m_nCursorSize;
    bool m_bDpiChanged;

    HWND m_hWnd;


public:
    CCursorDpi(int idCursor);
    bool IsSuccessfullyConstructed() { return m_bSuccessfullyConstructed; }
    ~CCursorDpi();
    BOOL Create(HWND hWnd);
    BOOL DpiChanged();
    HCURSOR GetHCURSOR();
protected:
    BOOL CreateCursorFromResource(int cxCursor, int nOrdinal);
    BOOL FindCursorSize(int cxCursorWanted, int& cxCursor, int& nOrdinal);
};
		

#include <Windows.h>
#include "CursorDpi.h"

#if !defined(ASSERT)
#include <cassert>
#define ASSERT assert
#endif

#pragma pack(2)
typedef struct {
    WORD Reserved;
    WORD ResType;
    WORD ResCount;
} NEWHEADER;

typedef struct {
    BYTE Width;
    BYTE Height;
    BYTE ColorCount;
    BYTE reserved;
} ICONRESDIR;

typedef struct {
    WORD Width;
    WORD Height;
} CURSORDIR;

typedef struct {
    union
    {
        ICONRESDIR   Icon;
        CURSORDIR    Cursor;
    };
    WORD       Planes;
    WORD       BitCount;
    DWORD      BytesInRes;
    WORD       IconCursorId;
} RESDIR;

typedef struct {
    WORD xHotSpot;
    WORD yHotSpot;
} LOCALHEADER;
#pragma pack()



///////////////////////////////////////////////////////////////////////////

CCursorDpi::CCursorDpi(int idCursor)
    : m_hCursor(NULL)
    , m_bDpiChanged(false)
    , m_nCursorSize(0)
    , m_hWnd(NULL)
{
    m_bSuccessfullyConstructed = false;

    {
        // load group cursor resource 
        HRSRC hrsrc = FindResource(NULL, MAKEINTRESOURCE(idCursor), RT_GROUP_CURSOR);
        if (hrsrc) {
            HGLOBAL h = LoadResource(NULL, hrsrc);
            if (h) {
                BYTE* p = (BYTE*)LockResource(h);
                if (p) {
                    NEWHEADER* pNewHeader = (NEWHEADER*)p;
                    if (pNewHeader->ResType == 2) {
                        p += sizeof(NEWHEADER);

                        RESDIR* pResDirs = (RESDIR*)p;

                        for (int i = 0; i < (int)pNewHeader->ResCount; i++) {
                            if (m_mapImages.find(pResDirs[i].Cursor.Width) == m_mapImages.end()) {
                                // set image ordinal for cursor size
                                m_mapImages[pResDirs[i].Cursor.Width] = pResDirs[i].IconCursorId;
                            }
                            else {
                                ASSERT(0);      // duplicate cursor size
                            }
                        }
                    }
                    else {
                        ASSERT(pNewHeader->ResType == 2);       // must be cursor
                        return;
                    }
                    UnlockResource(h);
                }
                FreeResource(h);
            }
        }
    }

    if (m_mapImages.empty()) {
        ASSERT(0);
        return;
    }

    m_bSuccessfullyConstructed = true;
}

CCursorDpi::~CCursorDpi()
{
    if (m_hCursor)
        DestroyIcon(m_hCursor);
}


BOOL CCursorDpi::Create(HWND hWnd)
{
    if (m_hWnd) {
        ASSERT(0);      // creating twice not assumed
        return FALSE;
    }

    m_hWnd = hWnd;

    return TRUE;
}

BOOL CCursorDpi::DpiChanged()
{
    ASSERT(m_hWnd);

    m_bDpiChanged = true;
    return TRUE;
}

HCURSOR CCursorDpi::GetHCURSOR()
{
    ASSERT(m_hWnd);

    if (!m_hCursor || m_bDpiChanged) {
        int nDpi = GetDpiForWindow(m_hWnd);
        int cxCursorWanted = GetSystemMetricsForDpi(SM_CXCURSOR, nDpi);
        int cxCursor, nOrdinal;
        FindCursorSize(cxCursorWanted, cxCursor, nOrdinal);
        if (m_nCursorSize != cxCursor) {
            CreateCursorFromResource(cxCursor, nOrdinal);
        }
        m_bDpiChanged = false;
    }

    return m_hCursor;
}

BOOL CCursorDpi::CreateCursorFromResource(int cxCursor, int nOrdinal)
{
    ASSERT(m_hWnd);

    if (m_hCursor) {
        DestroyIcon(m_hCursor);
        m_hCursor = NULL;
    }

    HRSRC hrsrc = FindResource(NULL, MAKEINTRESOURCE(nOrdinal), RT_CURSOR);
    if (hrsrc) {
        HGLOBAL h = LoadResource(NULL, hrsrc);
        if (h) {
            BYTE* p = (BYTE*)LockResource(h);
            if (p) {
                LOCALHEADER* pLocalHeader = (LOCALHEADER*)p;
                p += sizeof(LOCALHEADER);
                BITMAPINFO* pInfo = (BITMAPINFO*)p;

                HBITMAP hbmColor = NULL;
                HBITMAP hbmMask = NULL;
                bool bBitmapSuccess = false;

                // calculate color table size
                int cbColorTable = 0;
                if (pInfo->bmiHeader.biCompression == BI_RGB && pInfo->bmiHeader.biBitCount <= 8) {
                    // has color table
                    if (pInfo->bmiHeader.biClrUsed) {
                        cbColorTable = pInfo->bmiHeader.biClrUsed * (int)sizeof(RGBQUAD);
                    }
                    else {
                        cbColorTable = (1 << pInfo->bmiHeader.biBitCount) * (int)sizeof(RGBQUAD);
                    }
                }

                int cbImageDataOffset = sizeof(BITMAPINFO) - sizeof(RGBQUAD) + cbColorTable;
                BYTE* pImageData = (BYTE*)pInfo + cbImageDataOffset;
                int cx = pInfo->bmiHeader.biWidth;
                int cy = abs(pInfo->bmiHeader.biHeight);
                int stride = ((((cx * pInfo->bmiHeader.biBitCount) + 31) & ~31) >> 3);

                if (pInfo->bmiHeader.biBitCount == 1) {
                    // monochrome cursor consisits of one double height bitmap
                    void* pBits = nullptr;
                    hbmMask = CreateDIBSection(NULL, pInfo, DIB_RGB_COLORS, &pBits, NULL, 0);
                    if (pBits) {
                        memcpy(pBits, pImageData, stride * cy);
                    }
                    hbmColor = NULL;
                    if (hbmMask) {
                        bBitmapSuccess = true;
                    }
                }
                else {
                    cy /= 2;
                    BYTE* pMaskData = pImageData + stride * cy;

                    // color cursor consists of one color bitmap and one monochrome mask bitmap
                    // bits of both bitmaps are strangely packed in one color bitmap
                    {
                        // color bitmap
                        // make a copy of BITMAPINFO including Color Table to correct bitmap size
                        BITMAPINFO* pInfoCopied = (BITMAPINFO*)malloc(cbImageDataOffset);
                        if (pInfoCopied) {
                            memcpy(pInfoCopied, pInfo, cbImageDataOffset);
                            pInfoCopied->bmiHeader.biHeight /= 2;
                            pInfoCopied->bmiHeader.biSizeImage = stride * cy;

                            void* pBits = nullptr;
                            hbmColor = CreateDIBSection(NULL, pInfoCopied, cbColorTable ? DIB_RGB_COLORS : 0, &pBits, NULL, 0);
                            if (pBits) {
                                memcpy(pBits, pImageData, stride * cy);
                            }
                            free(pInfoCopied);
                        }
                    }

                    {
                        // monochrome mask bitmap
                        // calculate stride and bitmapdata size
                        int strideMask = ((((pInfo->bmiHeader.biWidth) + 31) & ~31) >> 3);

                        // make a copy of BITMAPINFO to correct bitmap size, bitcount, etc
                        size_t cbInfo = sizeof(BITMAPINFO) + sizeof(RGBQUAD) * (2 - 1);
                        BITMAPINFO* pInfoCopied = (BITMAPINFO*)malloc(cbInfo);
                        if (pInfoCopied) {
                            memcpy(pInfoCopied, pInfo, sizeof(BITMAPINFOHEADER));
                            pInfoCopied->bmiHeader.biSize = (int)cbInfo;
                            pInfoCopied->bmiHeader.biHeight /= 2;
                            pInfoCopied->bmiHeader.biBitCount = 1;
                            pInfoCopied->bmiHeader.biSizeImage = strideMask * cy;
                            pInfoCopied->bmiColors[0] = RGBQUAD{};
                            pInfoCopied->bmiColors[1] = RGBQUAD{ 255, 255, 255, 0 };

                            void* pBits = nullptr;
                            hbmMask = CreateDIBSection(NULL, pInfoCopied, DIB_RGB_COLORS, &pBits, NULL, 0);
                            if (pBits) {
                                // stride is rounded up to 32 bit boundary
                                DWORD* pDst = (DWORD*)pBits;
                                DWORD* pSrc = (DWORD*)pMaskData;
                                int c = (strideMask * cy) / 4;
                                for (int i = 0; i < c; i++) {
                                    *(pDst++) = ~*(pSrc++);
                                }
                            }
                            free(pInfoCopied);
                        }
                    }
                    if (hbmColor && hbmMask) {
                        bBitmapSuccess = true;
                    }
                }

                if (bBitmapSuccess) {
                    ICONINFO ii = {};
                    ii.xHotspot = pLocalHeader->xHotSpot;
                    ii.yHotspot = pLocalHeader->yHotSpot;
                    ii.fIcon = FALSE;
                    ii.hbmColor = hbmColor;
                    ii.hbmMask = hbmMask;
                    m_hCursor = CreateIconIndirect(&ii);
                }

                if (hbmColor)
                    DeleteObject(hbmColor);
                if (hbmMask)
                    DeleteObject(hbmMask);

                UnlockResource(h);
            }
            FreeResource(h);
        }
    }
    else {
        ASSERT(0);  // something went wrong
    }

    if (m_hCursor) {
        m_nCursorSize = cxCursor;
        return TRUE;
    }
    else {
        return FALSE;
    }
}

BOOL CCursorDpi::FindCursorSize(int cxCursorWanted, int& cxCursor, int& nOrdinal)
{
    if (m_mapImages.empty()) {
        cxCursor = 0;
        nOrdinal = 0;
        return FALSE;
    }

    // find cursor image that is smaller or equal to cursor size wanted
    auto iter = m_mapImages.begin();
    cxCursor = iter->first;
    nOrdinal = iter->second;
    iter++;

    for (; iter != m_mapImages.end(); iter++) {
        if (iter->first > cxCursorWanted) {
            break;
        }
        cxCursor = iter->first;
        nOrdinal = iter->second;
    }
    return TRUE;
}