Click here to Skip to main content
15,897,187 members
Articles / Desktop Programming / Win32
Tip/Trick

Introduction to Embedded Icons without Resource on ReactOS

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
21 Oct 2019CPOL3 min read 5.3K   56   2   1
How to embed icons into Win32 programs without utilizing resources - useful for platforms without resource editor/resorce compiler, e.g., ReactOS. Learn the missing things about the .ico format.

Introduction

This article goes beyond the great Microsoft online article about the .ico format and introduces the missing things for handling binary .ico data.

I wrote this article to save other developers the hassle of gathering all the necessary information about the .ico data format.

The motivation for the question "embedded icon without utilization of resources" comes from the fact that:

  • I didn't have a resource compiler available,
  • but wanted to embed the icons

for my application programming tests with ReactOS. If you're interested in ReactOS programming, you can also take a look at my tips "Introduction to OpenGL with C/C++ on ReactOS" and "Introduction to C# on ReactOS". This tip is a direct continuation of the "Introduction to OpenGL with C/C++ on ReactOS" tip.

Background

On ReactOS, the most stable programming interface is the plain old Win32 C API - and it provides a lot of icon functions (see Microsoft article "Icons"), but none of them work with a stream or a BYTE[]. The nearest one is LoadImage, that supports bitmaps, icons and cursors. But LoadImage loads from the file system and I don't think it's a good style to ship many .ico files with a program - and would prefer to embed the .ico files. Unfortunately, there is no suitable function for it in the plain old Win32 C API - and so I am forced to write my own function.

A Small Side Note About Icons

I didn't like the Windows feature "icon" very much until the intensive examination of icons. However, there were reasons why I think differently about it today:

  • Under ReactOS, the STATIC window class currently does not support bitmaps, but icons.
  • Appealing icons always need a masking of the transparent pixels. To achieve this with bitmaps, at least two files are required.
  • The old limitation of 16x16 pixels or 32x32 pixels at 16 or 256 colors is removed. Nowadays icons can also be much larger and in TrueColor.

Using the Code

NOTICE: The code I'll provide here is developed for icons with:

  • one image per file
  • 16x16 pixels and
  • 16 color palette

Other formats might work, but I doubt they'll do. Nevertheless, the code contains all information you need to extend the functionality according to your needs.

An icon can easily be embedded into a program. The .ico file must just be copied from any HEX editor to a C file and be formatted as BYTE[], e.g.:

C++
WORD ICO_CLOCKWISE_16_ByteCount = 318;
BYTE ICO_CLOCKWISE_16_Bytes[318] = {
    0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00,
    0x28, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
// 00 + 22 = 22
    0x28, 0x00, 0x00, 0x00,
    0x10, 0x00, 0x00, 0x00,
    0x20, 0x00, 0x00, 0x00,
    0x01, 0x00, 0x04, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x10, 0x00, 0x00, 0x00,
    0x10, 0x00, 0x00, 0x00,
// 22 + 40 = 62 - START COLORTABLE
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x80, 0x00,
    0x00, 0x80, 0x00, 0x00,
    0x00, 0x80, 0x80, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x80, 0x00,
    0x80, 0x80, 0x00, 0x00,
    0x40, 0x40, 0x40, 0x00,
    0x60, 0x60, 0x60, 0x00,
    0x00, 0x00, 0xff, 0x00,
    0x00, 0xff, 0x00, 0x00,
    0x00, 0xff, 0xff, 0x00,
    0xff, 0x00, 0x00, 0x00,
    0xff, 0x00, 0xff, 0x00,
    0xff, 0xff, 0x00, 0x00,
    0xff, 0xff, 0xff, 0x00,
// IMAGE
    0x00, 0x00, 0x87, 0x00, 0x07, 0x80, 0x00, 0x00,
    0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x07, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x80,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x70,
    0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x08, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00,
    0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00,
    0x00, 0x00, 0x08, 0x70, 0x00, 0x78, 0x00, 0x00,
// MASK
    0x70, 0x1f, 0x00, 0x00, 0x20, 0x0f, 0x00, 0x00,
    0x01, 0xc7, 0x00, 0x00, 0x07, 0xe3, 0x00, 0x00,
    0x07, 0xf3, 0x00, 0x00, 0x03, 0xf1, 0x00, 0x00,
    0xff, 0xf1, 0x00, 0x00, 0xff, 0xf1, 0x00, 0x00,
    0x8f, 0xff, 0x00, 0x00, 0x8f, 0xff, 0x00, 0x00,
    0x8f, 0xe0, 0x00, 0x00, 0xcf, 0xf0, 0x00, 0x00,
    0xc7, 0xf0, 0x00, 0x00, 0xe1, 0xc0, 0x00, 0x00,
    0xf0, 0x04, 0x00, 0x00, 0xf8, 0x0e, 0x00, 0x00
};

This sample .ico definition contains just one image with 16x16 pixel. My application calls:

C++
HICON hIcon = Utils_CreateIconFromBytes(ICO_CLOCKWISE_16_Bytes(),
                                        ICO_CLOCKWISE_16_ByteCount(), 16, 16);

I stick very close to the great Microsoft online article about the .ico format when buffering the data:

C++
typedef struct tagICONIMAGE
{
    BITMAPINFOHEADER   iiHeader;       // DIB header
    RGBQUAD            iiColors[1];    // Color table
    BYTE*              iiXOR;          // DIB bits for XOR mask
    BYTE*              iiAND;          // DIB bits for AND mask
} ICONIMAGE, *LPICONIMAGE;

typedef struct tagICONDIRENTRY
{
    BYTE              deWidth;         // Width, in pixels, of the image
    BYTE              deHeight;        // Height, in pixels, of the image
    BYTE              deColorCount;    // Number of colors in image (0 if >=8bpp)
    BYTE              deReserved;      // Reserved ( must be 0)
    WORD              dePlanes;        // Color Planes
    WORD              deBitCount;      // Bits per pixel
    DWORD             deBytesInRes;    // How many bytes in this resource?
    DWORD             deImageOffset;   // Where in the file is this image?
} ICONDIRENTRY, *LPICONDIRENTRY;

typedef struct tagICONDIR
{
    WORD              idReserved;      // Reserved (must be 0)
    WORD              idType;          // Resource Type (1 for icons)
    WORD              idCount;         // How many images?
    LPICONDIRENTRY    idEntries;       // An entry for each image.
} ICONDIR, *LPICONDIR;

This includes the data structures (above) and the first processing stage:

C++
/// <summary>
/// Creates an icon from indicated icon bytes.
/// </summary>
/// <param name="pbIconBytes">The icon bytes.</param>
/// <param name="wByteCount">The number of icon bytes.</param>
/// <param name="lWidth">The requested icon width in pixel.</param>
/// <param name="lHeight">The requested icon height in pixel.</param>
/// <returns>The handle to the GDI icon object on success, or <c>NULL</c> otherwise.
/// The caller is responsible to free the GDI object with <c>DestroyIcon()</c>.</returns>
/// <remarks>For details see: "https://docs.microsoft.com/en-us/previous-versions/
///                            ms997538(v=msdn.10)?redirectedfrom=MSDN"</remarks>
__declspec(dllexport) HICON __cdecl Utils_CreateIconFromBytes(BYTE* pbIconBytes,
                                                              WORD wByteCount,
                                                              LONG lWidth, LONG lHeight)
{
    if (pbIconBytes == NULL)
    {
        Console::WriteText(Console::__ERROR,
                           L"Utils_CreateIconFromBits: The 'pbIconBytes' argument"
                           L" must not be NULL!\n");
        return NULL;
    }
    if (wByteCount <= 22)
    {
        Console::WriteText(Console::__ERROR,
                           L"Utils_CreateIconFromBits: The 'wByteCount' argument"
                           L" must be at least 22!\n");
        return NULL;
    }
    if (lWidth <= 0)
    {
        Console::WriteText(Console::__ERROR,
                           L"Utils_CreateIconFromBits: The 'lWidth' argument"
                           L" must be a valid width - at least 1!\n");
        return NULL;
    }
    if (lHeight <= 0)
    {
        Console::WriteText(Console::__ERROR,
                           L"Utils_CreateIconFromBits: The 'lHeight' argument"
                           L" must be a valid height - at least 1!\n");
        return NULL;
    }

    // --------------------------------------------------------------------------
    // ICON DIR
    // --------------------------------------------------------------------------

    ICONDIR aIconDir       = {0};

    aIconDir.idReserved    = (WORD)pbIconBytes[0] + (WORD)pbIconBytes[1] * (WORD)256;

    aIconDir.idType        = (WORD)pbIconBytes[2] + (WORD)pbIconBytes[3] * (WORD)256;
    if (aIconDir.idType   != (WORD)1 && aIconDir.idType    != (WORD)2)
    {
        Console::WriteText(Console::__ERROR,
                           L"Utils_CreateIconFromBits: The icon header's content"
                           L" type is not equal to '1' (for icon) or '2' (for cursor)!\n");
        return NULL;
    }

    aIconDir.idCount       = (WORD)pbIconBytes[4] + (WORD)pbIconBytes[5] * (WORD)256;
    if (aIconDir.idCount  == (WORD)0)
    {
        Console::WriteText(Console::__ERROR,
                           L"Utils_CreateIconFromBits: The icon bits contains '0' images!\n");
        return NULL;
    }

    int n = 6;

    aIconDir.idEntries = new ICONDIRENTRY[aIconDir.idCount];

    for (WORD wCountIconEntries = 0; wCountIconEntries < aIconDir.idCount; wCountIconEntries++)
    {
        // --------------------------------------------------------------------------
        // ICON DIRENTRY
        // --------------------------------------------------------------------------

        LPICONDIRENTRY pIconDirEntry  = &aIconDir.idEntries[wCountIconEntries];

        pIconDirEntry->deWidth         = (BYTE)pbIconBytes[n + 0];
        if (pIconDirEntry->deWidth    == 0)
            pIconDirEntry->deWidth     = (BYTE)256;

        pIconDirEntry->deHeight        = (BYTE)pbIconBytes[n + 1];
        if (pIconDirEntry->deHeight   == 0)
            pIconDirEntry->deHeight    = (BYTE)256;

        pIconDirEntry->deColorCount    = (BYTE)pbIconBytes[n + 2];

        pIconDirEntry->deReserved      = (BYTE)pbIconBytes[n + 3];

        pIconDirEntry->dePlanes        = (WORD)pbIconBytes[n + 4];
        pIconDirEntry->dePlanes       += (WORD)pbIconBytes[n + 5] * (WORD)256;
        if (pIconDirEntry->dePlanes   != (WORD)0 && pIconDirEntry->dePlanes   != (WORD)1)
        {
            Console::WriteText(Console::__ERROR,
                               L"Utils_CreateIconFromBits: The icon header's"
                           L" number of planes is not equal to '1'!\n");
            return NULL;
        }

        pIconDirEntry->deBitCount      = (WORD)pbIconBytes[n + 6];
        pIconDirEntry->deBitCount     += (WORD)pbIconBytes[n + 7] * (WORD)256;
        if (pIconDirEntry->deBitCount == (WORD)0)
        {
            Console::WriteText(Console::__ERROR,
                               L"Utils_CreateIconFromBits: The icon header's"
                           L" bits per pixel is '0'!\n");
            return NULL;
        }
        if (pIconDirEntry->deBitCount != (WORD)4 &&
            pIconDirEntry->deBitCount != (WORD)8 && pIconDirEntry->deBitCount != (WORD)32)
        {
            Console::WriteText(Console::__ERROR,
                               L"Utils_CreateIconFromBits: The icon header's"
                           L" bits per pixel is not equal to '4', '8' or '32'!\n");
            return NULL;
        }

        pIconDirEntry->deBytesInRes   = (DWORD)pbIconBytes[n +  8];
        pIconDirEntry->deBytesInRes  += (DWORD)pbIconBytes[n +  9] * (DWORD)256;
        pIconDirEntry->deBytesInRes  += (DWORD)pbIconBytes[n + 10] * (DWORD)65536;
        pIconDirEntry->deBytesInRes  += (DWORD)pbIconBytes[n + 11] * (DWORD)16777216;
        if (pIconDirEntry->deBytesInRes == (WORD)0)
        {
            Console::WriteText(Console::__ERROR,
                               L"Utils_CreateIconFromBits: The icon header's"
                           L" size of the bitmap is '0'!\n");
            return NULL;
        }

        pIconDirEntry->deImageOffset  = (DWORD)pbIconBytes[n + 12];
        pIconDirEntry->deImageOffset += (DWORD)pbIconBytes[n + 13] * (DWORD)256;
        pIconDirEntry->deImageOffset += (DWORD)pbIconBytes[n + 14] * (DWORD)65536;
        pIconDirEntry->deImageOffset += (DWORD)pbIconBytes[n + 15] * (DWORD)16777216;
        if (pIconDirEntry->deImageOffset == (WORD)0)
        {
            Console::WriteText(Console::__ERROR,
                               L"Utils_CreateIconFromBits: The icon header's"
                           L" offset of the bitmap is '0'!\n");
            return NULL;
        }

        n += 16;
    }

    WORD wPreferredIconEntry = -1;
    for (WORD wCountIconEntries = 0; wCountIconEntries < aIconDir.idCount; wCountIconEntries++)
    {
        LPICONDIRENTRY pIconDirEntry  = &aIconDir.idEntries[wCountIconEntries];

        if ((LONG)pIconDirEntry->deWidth == lWidth && (LONG)pIconDirEntry->deHeight == lHeight)
        {
            wPreferredIconEntry = wCountIconEntries;
            break;
        }
    }
    if (wPreferredIconEntry < 0)
    {
        Console::WriteText(Console::__ERROR,
                           L"Utils_CreateIconFromBits: The icon doesn't include"
                           L" an icon image of the requested width and height!\n");
        return NULL;
    }

    LPICONDIRENTRY pIDEntry  = &aIconDir.idEntries[wPreferredIconEntry];
    HICON          hIcon     = Utils_CreateIconFromBytesSub(pbIconBytes, n, pIDEntry);

    delete aIconDir.idEntries;

    return hIcon;
}

The processing within this function is well known. The rather unknown processing steps are carried out in CreateIconFromBytesSub().

C++
HICON Utils_CreateIconFromBitsSub(BYTE* pbIconBytes, LONG lIconBytesBaseOffset,
                                  LPICONDIRENTRY pIDEntry)
{
    // --------------------------------------------------------------------------
    // ICON IMAGE
    // --------------------------------------------------------------------------

    ICONIMAGE aIconImage = {0};
    LPBITMAPINFOHEADER bmiHeader = &aIconImage.iiHeader;
    LONG n = lIconBytesBaseOffset;

    bmiHeader->biSize           = (DWORD)pbIconBytes[n +  0];
    bmiHeader->biSize          += (DWORD)pbIconBytes[n +  1] * (DWORD)256;
    bmiHeader->biSize          += (DWORD)pbIconBytes[n +  2] * (DWORD)65536;
    bmiHeader->biSize          += (DWORD)pbIconBytes[n +  3] * (DWORD)16777216;

    bmiHeader->biWidth          =  (LONG)pbIconBytes[n +  4];
    bmiHeader->biWidth         +=  (LONG)pbIconBytes[n +  5] * (LONG)256;
    bmiHeader->biWidth         +=  (LONG)pbIconBytes[n +  6] * (LONG)65536;
    bmiHeader->biWidth         +=  (LONG)pbIconBytes[n +  7] * (LONG)16777216;

    bmiHeader->biHeight         =  (LONG)pbIconBytes[n +  8];
    bmiHeader->biHeight        +=  (LONG)pbIconBytes[n +  9] * (LONG)256;
    bmiHeader->biHeight        +=  (LONG)pbIconBytes[n + 10] * (LONG)65536;
    bmiHeader->biHeight        +=  (LONG)pbIconBytes[n + 11] * (LONG)16777216;
    bmiHeader->biHeight        /=  2; // By convention.

    bmiHeader->biPlanes         =  (WORD)pbIconBytes[n + 12];
    bmiHeader->biPlanes        +=  (WORD)pbIconBytes[n + 13] * (WORD)256;

    bmiHeader->biBitCount       =  (WORD)pbIconBytes[n + 14];
    bmiHeader->biBitCount      +=  (WORD)pbIconBytes[n + 15] * (WORD)256;

    bmiHeader->biCompression    = (DWORD)pbIconBytes[n + 16];
    bmiHeader->biCompression   += (DWORD)pbIconBytes[n + 17] * (DWORD)256;
    bmiHeader->biCompression   += (DWORD)pbIconBytes[n + 18] * (DWORD)65536;
    bmiHeader->biCompression   += (DWORD)pbIconBytes[n + 19] * (DWORD)16777216;

    bmiHeader->biSizeImage      = (DWORD)pbIconBytes[n + 20];
    bmiHeader->biSizeImage     += (DWORD)pbIconBytes[n + 21] * (DWORD)256;
    bmiHeader->biSizeImage     += (DWORD)pbIconBytes[n + 22] * (DWORD)65536;
    bmiHeader->biSizeImage     += (DWORD)pbIconBytes[n + 23] * (DWORD)16777216;

    bmiHeader->biXPelsPerMeter  =  (LONG)pbIconBytes[n + 24];
    bmiHeader->biXPelsPerMeter +=  (LONG)pbIconBytes[n + 25] * (LONG)256;
    bmiHeader->biXPelsPerMeter +=  (LONG)pbIconBytes[n + 26] * (LONG)65536;
    bmiHeader->biXPelsPerMeter +=  (LONG)pbIconBytes[n + 27] * (LONG)16777216;

    bmiHeader->biYPelsPerMeter  =  (LONG)pbIconBytes[n + 28];
    bmiHeader->biYPelsPerMeter +=  (LONG)pbIconBytes[n + 29] * (LONG)256;
    bmiHeader->biYPelsPerMeter +=  (LONG)pbIconBytes[n + 30] * (LONG)65536;
    bmiHeader->biYPelsPerMeter +=  (LONG)pbIconBytes[n + 31] * (LONG)16777216;

    bmiHeader->biClrUsed        = (DWORD)pbIconBytes[n + 32];
    bmiHeader->biClrUsed       += (DWORD)pbIconBytes[n + 33] * (DWORD)256;
    bmiHeader->biClrUsed       += (DWORD)pbIconBytes[n + 34] * (DWORD)65536;
    bmiHeader->biClrUsed       += (DWORD)pbIconBytes[n + 35] * (DWORD)16777216;

    bmiHeader->biClrImportant   = (DWORD)pbIconBytes[n + 36];
    bmiHeader->biClrImportant  += (DWORD)pbIconBytes[n + 37] * (DWORD)256;
    bmiHeader->biClrImportant  += (DWORD)pbIconBytes[n + 38] * (DWORD)65536;
    bmiHeader->biClrImportant  += (DWORD)pbIconBytes[n + 39] * (DWORD)16777216;

    if (bmiHeader->biSize != 40)
    {
        Console::WriteText(Console::__ERROR, L"Utils_CreateIconFromBits: The icon header"
                           L" size is not equal to '40'!\n");
        return NULL;
    }

    if (bmiHeader->biPlanes != 1)
    {
        Console::WriteText(Console::__ERROR, L"Utils_CreateIconFromBits: The icon header's"
                           L" number of planes is not equal to '1'!\n");
        return NULL;
    }

    if (bmiHeader->biCompression != 0)
    {
        Console::WriteText(Console::__ERROR, L"Utils_CreateIconFromBits: The icon header's"
                           L" compression is not equal to '0'!\n");
        return NULL;
    }

    if (bmiHeader->biSizeImage != (DWORD)(bmiHeader->biWidth * bmiHeader->biHeight) *
                                          bmiHeader->biPlanes * bmiHeader->biBitCount / 8)
    {
        Console::WriteText(Console::__ERROR, L"Utils_CreateIconFromBits: The image size"
                           L" of bitmap '1' is not equal to the calculated size!\n");
        return NULL;
    }

    n += 40;

    // --------------------------------------------------------------------------
    // COLOR PALETTE
    // --------------------------------------------------------------------------

    COLORREF* aColorPalette = (COLORREF*)new COLORREF[pIDEntry->deColorCount];
    for (DWORD i = 0; i < pIDEntry->deColorCount; i++)
    {
        DWORD color = 0;
        color  = (DWORD)pbIconBytes[n + i * 4 + 0];
        color += (DWORD)pbIconBytes[n + i * 4 + 1] * (DWORD)256;
        color += (DWORD)pbIconBytes[n + i * 4 + 2] * (DWORD)65536;
        color += (DWORD)pbIconBytes[n + i * 4 + 3] * (DWORD)16777216;
        aColorPalette[i] = color;
    }

    n += sizeof(COLORREF) * pIDEntry->deColorCount;

    // --------------------------------------------------------------------------
    // XOR BITMAP
    // --------------------------------------------------------------------------

    aIconImage.iiXOR = (BYTE*)new COLORREF[bmiHeader->biWidth * bmiHeader->biHeight];
    for (LONG rowXOR = 0; rowXOR < bmiHeader->biHeight; rowXOR++)
    {
        for (LONG colXOR = 0; colXOR < bmiHeader->biWidth; colXOR++)
        {
            LONG sourcePos = rowXOR * bmiHeader->biWidth + colXOR;
            LONG targetPos = (bmiHeader->biHeight - 1 - rowXOR) * bmiHeader->biWidth + colXOR;

            if (bmiHeader->biBitCount == 4)
            {
                // Every BYTE stores the color index of two pixel.
                BYTE palIndex  = pbIconBytes[n + sourcePos / 2];
                COLORREF color;
                if (colXOR % 2 == 0)
                    color = aColorPalette[(palIndex & 0xf0) / 16];
                else
                    color = aColorPalette[(palIndex & 0x0f)     ];

                ((COLORREF*)aIconImage.iiXOR)[targetPos] = color;
            }
        }
    }

    n += bmiHeader->biSizeImage;

    // --------------------------------------------------------------------------
    // AND BITMAP
    // --------------------------------------------------------------------------

    aIconImage.iiAND = (BYTE*)new BYTE[bmiHeader->biSizeImage / 2];
    for (DWORD i = 0; i < bmiHeader->biSizeImage / 2; i++)
        aIconImage.iiAND[i] = pbIconBytes[n + i];

    LONG sourceOffset = 0;
    for (LONG rowAND = 0; rowAND < bmiHeader->biHeight; rowAND++)
    {
        // The mask is BIT-wise. Every BYTE holds the mask for 8 BITs.
        for (LONG colAND = 0; colAND < bmiHeader->biWidth; colAND += 8)
        {
            BYTE mask  = pbIconBytes[n + sourceOffset];
            sourceOffset++;

            LONG targetPos = (bmiHeader->biHeight - 1 - rowAND) *
                             bmiHeader->biWidth / 8 + colAND / 8;
            aIconImage.iiAND[targetPos] = mask;
        }
        while (sourceOffset % 4 != 0)
            sourceOffset++;
    }

    // --------------------------------------------------------------------------
    // ICON
    // --------------------------------------------------------------------------

    HICON hIcon        = NULL;

    Utils_InspectBitmapBytes (&(pbIconBytes[pIDEntry->deImageOffset]), pIDEntry->deBytesInRes);

    ICONINFO ii = {0};
    ii.fIcon = TRUE;
    ii.xHotspot = 0;
    ii.yHotspot = 0;
    ii.hbmColor = ::CreateBitmap(bmiHeader->biWidth,  bmiHeader->biHeight,
                                 bmiHeader->biPlanes, 32, aIconImage.iiXOR);
    ii.hbmMask  = ::CreateBitmap(bmiHeader->biWidth, bmiHeader->biHeight,
                                 1, 1, aIconImage.iiAND);

    hIcon = ::CreateIconIndirect(&ii);

    ::DeleteObject(ii.hbmMask);
    ::DeleteObject(ii.hbmColor);
    delete aColorPalette;
    delete aIconImage.iiXOR;
    delete aIconImage.iiAND;

    return hIcon;
}

That's it!

Points of Interest

What did I learn beyond the great Microsoft online article about the .ico format?

  • The value of BITMAPINFOHEADER.biHeight must be divided by 2.
  • The color table follows immediately after the BITMAPINFOHEADER data.
  • The length of the color table is already known by ICONDIRENTRY.deColorCount.
  • The ICONIMAGE.iiXOR data follows immediately after the color table, followed by the ICONIMAGE.iiAND data.

History

  • 22nd October, 2019: Initial tip

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader Celonis SA
Germany Germany
I am currently the CEO of Symbioworld GmbH and as such responsible for personnel management, information security, data protection and certifications. Furthermore, as a senior programmer, I am responsible for the automatic layout engine, the simulation (Activity Based Costing), the automatic creation of Word/RTF reports and the data transformation in complex migration projects.

The main focus of my work as a programmer is the development of Microsoft Azure Services using C# and Visual Studio.

Privately, I am interested in C++ and Linux in addition to C#. I like the approach of open source software and like to support OSS with own contributions.

Comments and Discussions

 
SuggestionRE: Introduction to embedded icons without resource Pin
JuHuhn22-Oct-19 13:46
JuHuhn22-Oct-19 13:46 
The WinApi functions: "CreateIconFromResource" and "CreateCursor" provides to create
embedded icons or cursors from Data...

Eg.: "CreateIconFromResource"
Basic Code:

Type DRAGLIST_TAGICONDIR
idReserved As Word 'Reserved (must be 0)
idType As Word 'Resource Type (1 For icons, 2 For Cursors)
idCount As Word 'How many images?
End Type

Type DRAGLIST_TAGICONDIRENTRY
bWidth As Byte 'Width, In Pixels, of the Image
bHeight As Byte 'Height, In Pixels, of the Image
bColorCount As Byte 'Number of colors In Image (0 If >=8bpp)
bReserved As Byte 'Reserved (must be 0)
wPlanes As Word 'Color Planes
wBitCount As Word 'Bits per pixel
dwBytesInRes As Dword 'How many bytes In this resource?
dwImageOffset As Dword 'Where In the file is this image?
End Type
' Hex data:
DATA 00, 00, 02, 00, 01, 00, 20, 20, 00, 00, 00, 00, 00, 00, A8, 08
DATA 00, 00, 16, 00, 00, 00, 28, 00, 00, 00, 20, 00, 00, 00, 40, 00
DATA 00, 00, 01, 00, 08, 00, 00, 00, 00, 00, 80, 04, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 80, 00, 80, 00, 80, 00, 00, 00, 80, 80, 00, 00, 00, 80
DATA 00, 00, 00, 80, 80, 00, 00, 00, 80, 00, C0, C0, C0, 00, C0, DC
DATA C0, 00, F0, CA, A6, 00, 80, 80, 80, 00, FF, 00, FF, 00, FF, 00
DATA 00, 00, FF, FF, 00, 00, 00, FF, 00, 00, 00, FF, FF, 00, 00, 00
DATA FF, 00, FF, FF, FF, 00, F0, FB, FF, 00, A4, A0, A0, 00, D4, F0
DATA FF, 00, B1, E2, FF, 00, 8E, D4, FF, 00, 6B, C6, FF, 00, 48, B8
DATA FF, 00, 25, AA, FF, 00, 00, AA, FF, 00, 00, 92, DC, 00, 00, 7A
DATA B9, 00, 00, 62, 96, 00, 00, 4A, 73, 00, 00, 32, 50, 00, D4, E3
DATA FF, 00, B1, C7, FF, 00, 8E, AB, FF, 00, 54, A3, F1, 00, 01, 78
DATA FC, 00, 25, 57, FF, 00, 00, 55, FF, 00, 00, 49, DC, 00, 00, 3D
DATA B9, 00, 00, 31, 96, 00, 00, 25, 73, 00, 00, 19, 50, 00, D4, D4
DATA FF, 00, B1, B1, FF, 00, 8E, 8E, FF, 00, 6B, 6B, FF, 00, 48, 48
DATA FF, 00, 25, 25, FF, 00, 00, 00, FF, 00, 00, 00, DC, 00, 00, 00
DATA B9, 00, 00, 00, 96, 00, 00, 00, 73, 00, 00, 00, 50, 00, E3, D4
DATA FF, 00, C7, B1, FF, 00, AB, 8E, FF, 00, 8F, 6B, FF, 00, 73, 48
DATA FF, 00, 57, 25, FF, 00, 55, 00, FF, 00, 49, 00, DC, 00, 3D, 00
DATA B9, 00, 31, 00, 96, 00, 25, 00, 73, 00, 19, 00, 50, 00, F0, D4
DATA FF, 00, E2, B1, FF, 00, D4, 8E, FF, 00, C6, 6B, FF, 00, B8, 48
DATA FF, 00, AA, 25, FF, 00, AA, 00, FF, 00, 92, 00, DC, 00, 7A, 00
DATA B9, 00, 62, 00, 96, 00, 4A, 00, 73, 00, 32, 00, 50, 00, FF, D4
DATA FF, 00, FF, B1, FF, 00, FF, 8E, FF, 00, FF, 6B, FF, 00, FF, 48
DATA FF, 00, FF, 25, FF, 00, FF, 00, FF, 00, DC, 00, DC, 00, B9, 00
DATA B9, 00, 96, 00, 96, 00, 73, 00, 73, 00, 50, 00, 50, 00, FF, D4
DATA F0, 00, FF, B1, E2, 00, FF, 8E, D4, 00, FF, 6B, C6, 00, FF, 48
DATA B8, 00, FF, 25, AA, 00, FF, 00, AA, 00, DC, 00, 92, 00, B9, 00
DATA 7A, 00, 96, 00, 62, 00, 73, 00, 4A, 00, 50, 00, 32, 00, FF, D4
DATA E3, 00, FF, B1, C7, 00, FF, 8E, AB, 00, FF, 6B, 8F, 00, FF, 48
DATA 73, 00, FF, 25, 57, 00, FF, 00, 55, 00, DC, 00, 49, 00, B9, 00
DATA 3D, 00, 96, 00, 31, 00, 73, 00, 25, 00, 50, 00, 19, 00, FF, D4
DATA D4, 00, FF, B1, B1, 00, FF, 8E, 8E, 00, FF, 6B, 6B, 00, FF, 48
DATA 48, 00, FF, 25, 25, 00, FF, 00, 00, 00, DC, 00, 00, 00, B9, 00
DATA 00, 00, 96, 00, 00, 00, 73, 00, 00, 00, 50, 00, 00, 00, FF, E3
DATA D4, 00, FF, C7, B1, 00, FF, AB, 8E, 00, FF, 8F, 6B, 00, FF, 73
DATA 48, 00, FF, 57, 25, 00, FF, 55, 00, 00, DC, 49, 00, 00, B9, 3D
DATA 00, 00, 96, 31, 00, 00, 73, 25, 00, 00, 50, 19, 00, 00, FF, F0
DATA D4, 00, FF, E2, B1, 00, FF, D4, 8E, 00, FF, C6, 6B, 00, FF, B8
DATA 48, 00, FF, AA, 25, 00, FF, AA, 00, 00, DC, 92, 00, 00, B9, 7A
DATA 00, 00, 96, 62, 00, 00, 73, 4A, 00, 00, 50, 32, 00, 00, FF, FF
DATA D4, 00, FF, FF, B1, 00, FF, FF, 8E, 00, FF, FF, 6B, 00, FF, FF
DATA 48, 00, FF, FF, 25, 00, FF, FF, 00, 00, DC, DC, 00, 00, B9, B9
DATA 00, 00, 96, 96, 00, 00, 73, 73, 00, 00, 50, 50, 00, 00, F0, FF
DATA D4, 00, E2, FF, B1, 00, D4, FF, 8E, 00, C6, FF, 6B, 00, B8, FF
DATA 48, 00, AA, FF, 25, 00, AA, FF, 00, 00, 92, DC, 00, 00, 7A, B9
DATA 00, 00, 62, 96, 00, 00, 4A, 73, 00, 00, 32, 50, 00, 00, E3, FF
DATA D4, 00, C7, FF, B1, 00, AB, FF, 8E, 00, 8F, FF, 6B, 00, 73, FF
DATA 48, 00, 57, FF, 25, 00, 55, FF, 00, 00, 49, DC, 00, 00, 3D, B9
DATA 00, 00, 31, 96, 00, 00, 25, 73, 00, 00, 19, 50, 00, 00, D4, FF
DATA D4, 00, B1, FF, B1, 00, 8E, FF, 8E, 00, 6B, FF, 6B, 00, 48, FF
DATA 48, 00, 25, FF, 25, 00, 00, FF, 00, 00, 00, DC, 00, 00, 00, B9
DATA 00, 00, 00, 96, 00, 00, 00, 73, 00, 00, 00, 50, 00, 00, D4, FF
DATA E3, 00, B1, FF, C7, 00, 8E, FF, AB, 00, 6B, FF, 8F, 00, 48, FF
DATA 73, 00, 25, FF, 57, 00, 00, FF, 55, 00, 00, DC, 49, 00, 00, B9
DATA 3D, 00, 00, 96, 31, 00, 00, 73, 25, 00, 00, 50, 19, 00, D4, FF
DATA F0, 00, B1, FF, E2, 00, 8E, FF, D4, 00, 6B, FF, C6, 00, 48, FF
DATA B8, 00, 25, FF, AA, 00, 00, FF, AA, 00, 00, DC, 92, 00, 00, B9
DATA 7A, 00, 00, 96, 62, 00, 00, 73, 4A, 00, 00, 50, 32, 00, D4, FF
DATA FF, 00, B1, FF, FF, 00, 8E, FF, FF, 00, 6B, FF, FF, 00, 48, FF
DATA FF, 00, 25, FF, FF, 00, 00, FF, FF, 00, 00, DC, DC, 00, 00, B9
DATA B9, 00, 00, 96, 96, 00, 00, 73, 73, 00, 00, 50, 50, 00, F2, F2
DATA F2, 00, E6, E6, E6, 00, DA, DA, DA, 00, CE, CE, CE, 00, C2, C2
DATA C2, 00, B6, B6, B6, 00, AA, AA, AA, 00, 9E, 9E, 9E, 00, 92, 92
DATA 92, 00, 86, 86, 86, 00, 7A, 7A, 7A, 00, 6E, 6E, 6E, 00, 62, 62
DATA 62, 00, 56, 56, 56, 00, 4A, 4A, 4A, 00, 3E, 3E, 3E, 00, 32, 32
DATA 32, 00, 26, 26, 26, 00, 1A, 1A, 1A, 00, 0E, 0E, 0E, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 2B, 2B, 2B, 2B, 2B, 2B, 2B, 2B, 2B, 2B, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 2B, 15, 15, F2, 16, 16, 17, 17, 22, 2B, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 2B, 15, F1, 16, 16, 16, 23, 1C, 23, 2B, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 2B, 15, 22, 16, F1, 16, 16, 23, 23, 17, 23, 2B, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 2B, 15, 16, 16, 16, 22, 17, 23, 23, 23, 23, 2B, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 2B, 15, 16, 22, 16, 16, 16, 17, 23, 22, 1C, 1C, 2B, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 2B, 15, 16, 16, 22, F1, 16, 16, 16, 22, 23, 23, 23, 2B
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 2B, 14, 16, 16, 15, 15, 16, 16, 15, 16, 17, 23, 17, 23, 2B
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 2B, 14, 16, 16, 16, 15, 15, 15, 15, 17, 23, 17, 23, 23, 2B
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 2B, 14, 16, 2B, 15, F0, 16, 15, 15, 16, 22, 17, 17, 23, 23, 2B
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 2B, 14, 15, 2B, 16, 15, 16, 15, 15, 16, 16, 17, 17, 23, 23, 2B
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 2B, 14, F1, 2B, 15, 15, 16, 16, 15, 15, 16, 22, 16, 16, 23, 2B
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 2B, 14, F1, 2B, 15, 16, 2B, 16, 16, 2B, 15, 16, 2B, 15, 23, 2B
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 2B, 14, 2B, 2B, 15, 17, 2B, 17, 17, 2B, 15, 16, 2B, 2B, 2B, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 2B, 2B, 00, 2B, 14, 15, 2B, 15, 16, 2B, 2B, 2B, 2B, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 2B, 14, 15, 2B, 15, 16, 2B, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 2B, 14, F2, 2B, 15, 16, 2B, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 2B, 14, 16, 2B, 15, 15, 2B, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 2B, 14, 16, 2B, 2B, 2B, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 2B, 14, 16, 2B, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 2B, 14, 15, 2B, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 2B, 14, 14, 2B, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 2B, 2B, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
DATA 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, FF, FF
DATA FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF
DATA FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FC, 00, FF, FF, FC, 00
DATA FF, FF, FC, 00, FF, FF, F8, 00, 7F, FF, F8, 00, 7F, FF, F0, 00
DATA 7F, FF, F0, 00, 3F, FF, E0, 00, 3F, FF, E0, 00, 3F, FF, C0, 00
DATA 3F, FF, C0, 00, 3F, FF, C0, 00, 3F, FF, C0, 00, 3F, FF, C0, 00
DATA 7F, FF, C8, 01, FF, FF, F8, 0F, FF, FF, F8, 0F, FF, FF, F8, 0F
DATA FF, FF, F8, 1F, FF, FF, F8, 7F, FF, FF, F8, 7F, FF, FF, F8, 7F
DATA FF, FF, FC, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF

STATIC hCursor AS DWORD
DIM CursorArray(1 TO 2238) AS BYTE
LOCAL Counter AS LONG
LOCAL pIconDir AS DRAGLIST_TAGICONDIR Ptr
LOCAL IconDirEntry AS DRAGLIST_TAGICONDIRENTRY Ptr
FOR Counter = 1 TO UBOUND(CursorArray())
CursorArray(Counter) = VAL("&h" & READ$(Counter))
NEXT
'HotSpot (X, Y): 0, 0
pIconDir = VARPTR(CursorArray(1))
IconDirEntry = pIconDir + Len(@pIconDir)

hCursor = CreateIconFromResource(ByVal pIconDir + _
@IconDirEntry.dwImageOffset, @IconDirEntry.dwBytesInRes, @pIconDir.idType, &H30000&)
SetCursor hCursor
ShowCursor 1
CASE %WM_SETCURSOR
'The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
'to move within a window and mouse input is not captured.
SetCursor hCursor
ShowCursor 1
FUNCTION = 1 'Will prevent window to reset cursor to default arrow

CASE %WM_DESTROY
IF hCursor THEN DestroyCursor hCursor

' Or use decimal Data:

DATA 0, 0, 2, 0, 1, 0, 32, 32, 0, 0, 0, 0, 0, 0, 168, 8, 0, 0, 22, 0
DATA 0, 0, 40, 0, 0, 0, 32, 0, 0, 0, 64, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0
DATA 0, 128, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 128, 0, 128, 0, 128, 0, 0, 0, 128, 128, 0, 0, 0, 128
DATA 0, 0, 0, 128, 128, 0, 0, 0, 128, 0, 192, 192, 192, 0, 192, 220
DATA 192, 0, 240, 202, 166, 0, 128, 128, 128, 0, 255, 0, 255, 0, 255
DATA 0, 0, 0, 255, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 0, 0, 0, 255
DATA 0, 255, 255, 255, 0, 240, 251, 255, 0, 164, 160, 160, 0, 212, 240
DATA 255, 0, 177, 226, 255, 0, 142, 212, 255, 0, 107, 198, 255, 0, 72
DATA 184, 255, 0, 37, 170, 255, 0, 0, 170, 255, 0, 0, 146, 220, 0, 0
DATA 122, 185, 0, 0, 98, 150, 0, 0, 74, 115, 0, 0, 50, 80, 0, 212, 227
DATA 255, 0, 177, 199, 255, 0, 142, 171, 255, 0, 84, 163, 241, 0, 1
DATA 120, 252, 0, 37, 87, 255, 0, 0, 85, 255, 0, 0, 73, 220, 0, 0, 61
DATA 185, 0, 0, 49, 150, 0, 0, 37, 115, 0, 0, 25, 80, 0, 212, 212, 255
DATA 0, 177, 177, 255, 0, 142, 142, 255, 0, 107, 107, 255, 0, 72, 72
DATA 255, 0, 37, 37, 255, 0, 0, 0, 255, 0, 0, 0, 220, 0, 0, 0, 185, 0
DATA 0, 0, 150, 0, 0, 0, 115, 0, 0, 0, 80, 0, 227, 212, 255, 0, 199
DATA 177, 255, 0, 171, 142, 255, 0, 143, 107, 255, 0, 115, 72, 255, 0
DATA 87, 37, 255, 0, 85, 0, 255, 0, 73, 0, 220, 0, 61, 0, 185, 0, 49
DATA 0, 150, 0, 37, 0, 115, 0, 25, 0, 80, 0, 240, 212, 255, 0, 226, 177
DATA 255, 0, 212, 142, 255, 0, 198, 107, 255, 0, 184, 72, 255, 0, 170
DATA 37, 255, 0, 170, 0, 255, 0, 146, 0, 220, 0, 122, 0, 185, 0, 98
DATA 0, 150, 0, 74, 0, 115, 0, 50, 0, 80, 0, 255, 212, 255, 0, 255, 177
DATA 255, 0, 255, 142, 255, 0, 255, 107, 255, 0, 255, 72, 255, 0, 255
DATA 37, 255, 0, 255, 0, 255, 0, 220, 0, 220, 0, 185, 0, 185, 0, 150
DATA 0, 150, 0, 115, 0, 115, 0, 80, 0, 80, 0, 255, 212, 240, 0, 255
DATA 177, 226, 0, 255, 142, 212, 0, 255, 107, 198, 0, 255, 72, 184, 0
DATA 255, 37, 170, 0, 255, 0, 170, 0, 220, 0, 146, 0, 185, 0, 122, 0
DATA 150, 0, 98, 0, 115, 0, 74, 0, 80, 0, 50, 0, 255, 212, 227, 0, 255
DATA 177, 199, 0, 255, 142, 171, 0, 255, 107, 143, 0, 255, 72, 115, 0
DATA 255, 37, 87, 0, 255, 0, 85, 0, 220, 0, 73, 0, 185, 0, 61, 0, 150
DATA 0, 49, 0, 115, 0, 37, 0, 80, 0, 25, 0, 255, 212, 212, 0, 255, 177
DATA 177, 0, 255, 142, 142, 0, 255, 107, 107, 0, 255, 72, 72, 0, 255
DATA 37, 37, 0, 255, 0, 0, 0, 220, 0, 0, 0, 185, 0, 0, 0, 150, 0, 0
DATA 0, 115, 0, 0, 0, 80, 0, 0, 0, 255, 227, 212, 0, 255, 199, 177, 0
DATA 255, 171, 142, 0, 255, 143, 107, 0, 255, 115, 72, 0, 255, 87, 37
DATA 0, 255, 85, 0, 0, 220, 73, 0, 0, 185, 61, 0, 0, 150, 49, 0, 0, 115
DATA 37, 0, 0, 80, 25, 0, 0, 255, 240, 212, 0, 255, 226, 177, 0, 255
DATA 212, 142, 0, 255, 198, 107, 0, 255, 184, 72, 0, 255, 170, 37, 0
DATA 255, 170, 0, 0, 220, 146, 0, 0, 185, 122, 0, 0, 150, 98, 0, 0, 115
DATA 74, 0, 0, 80, 50, 0, 0, 255, 255, 212, 0, 255, 255, 177, 0, 255
DATA 255, 142, 0, 255, 255, 107, 0, 255, 255, 72, 0, 255, 255, 37, 0
DATA 255, 255, 0, 0, 220, 220, 0, 0, 185, 185, 0, 0, 150, 150, 0, 0
DATA 115, 115, 0, 0, 80, 80, 0, 0, 240, 255, 212, 0, 226, 255, 177, 0
DATA 212, 255, 142, 0, 198, 255, 107, 0, 184, 255, 72, 0, 170, 255, 37
DATA 0, 170, 255, 0, 0, 146, 220, 0, 0, 122, 185, 0, 0, 98, 150, 0, 0
DATA 74, 115, 0, 0, 50, 80, 0, 0, 227, 255, 212, 0, 199, 255, 177, 0
DATA 171, 255, 142, 0, 143, 255, 107, 0, 115, 255, 72, 0, 87, 255, 37
DATA 0, 85, 255, 0, 0, 73, 220, 0, 0, 61, 185, 0, 0, 49, 150, 0, 0, 37
DATA 115, 0, 0, 25, 80, 0, 0, 212, 255, 212, 0, 177, 255, 177, 0, 142
DATA 255, 142, 0, 107, 255, 107, 0, 72, 255, 72, 0, 37, 255, 37, 0, 0
DATA 255, 0, 0, 0, 220, 0, 0, 0, 185, 0, 0, 0, 150, 0, 0, 0, 115, 0
DATA 0, 0, 80, 0, 0, 212, 255, 227, 0, 177, 255, 199, 0, 142, 255, 171
DATA 0, 107, 255, 143, 0, 72, 255, 115, 0, 37, 255, 87, 0, 0, 255, 85
DATA 0, 0, 220, 73, 0, 0, 185, 61, 0, 0, 150, 49, 0, 0, 115, 37, 0, 0
DATA 80, 25, 0, 212, 255, 240, 0, 177, 255, 226, 0, 142, 255, 212, 0
DATA 107, 255, 198, 0, 72, 255, 184, 0, 37, 255, 170, 0, 0, 255, 170
DATA 0, 0, 220, 146, 0, 0, 185, 122, 0, 0, 150, 98, 0, 0, 115, 74, 0
DATA 0, 80, 50, 0, 212, 255, 255, 0, 177, 255, 255, 0, 142, 255, 255
DATA 0, 107, 255, 255, 0, 72, 255, 255, 0, 37, 255, 255, 0, 0, 255, 255
DATA 0, 0, 220, 220, 0, 0, 185, 185, 0, 0, 150, 150, 0, 0, 115, 115
DATA 0, 0, 80, 80, 0, 242, 242, 242, 0, 230, 230, 230, 0, 218, 218, 218
DATA 0, 206, 206, 206, 0, 194, 194, 194, 0, 182, 182, 182, 0, 170, 170
DATA 170, 0, 158, 158, 158, 0, 146, 146, 146, 0, 134, 134, 134, 0, 122
DATA 122, 122, 0, 110, 110, 110, 0, 98, 98, 98, 0, 86, 86, 86, 0, 74
DATA 74, 74, 0, 62, 62, 62, 0, 50, 50, 50, 0, 38, 38, 38, 0, 26, 26
DATA 26, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 43, 43
DATA 43, 43, 43, 43, 43, 43, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 21, 21, 242, 22, 22, 23, 23, 34
DATA 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 43, 21, 241, 22, 22, 22, 35, 28, 35, 43, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 21, 34, 22, 241
DATA 22, 22, 35, 35, 23, 35, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 43, 21, 22, 22, 22, 34, 23, 35, 35, 35
DATA 35, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 43, 21, 22, 34, 22, 22, 22, 23, 35, 34, 28, 28, 43, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 21, 22, 22, 34
DATA 241, 22, 22, 22, 34, 35, 35, 35, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 43, 20, 22, 22, 21, 21, 22, 22, 21, 22
DATA 23, 35, 23, 35, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 43, 20, 22, 22, 22, 21, 21, 21, 21, 23, 35, 23, 35, 35, 43
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 20, 22, 43
DATA 21, 240, 22, 21, 21, 22, 34, 23, 23, 35, 35, 43, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 20, 21, 43, 22, 21, 22, 21
DATA 21, 22, 22, 23, 23, 35, 35, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 43, 20, 241, 43, 21, 21, 22, 22, 21, 21, 22, 34
DATA 22, 22, 35, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 43, 20, 241, 43, 21, 22, 43, 22, 22, 43, 21, 22, 43, 21, 35, 43
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 20, 43, 43
DATA 21, 23, 43, 23, 23, 43, 21, 22, 43, 43, 43, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 43, 0, 43, 20, 21, 43, 21, 22
DATA 43, 43, 43, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 43, 20, 21, 43, 21, 22, 43, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 20
DATA 242, 43, 21, 22, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 20, 22, 43, 21, 21, 43, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 43, 20, 22, 43, 43, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 20, 22, 43, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 43, 20, 21, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 20, 20, 43, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 43, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DATA 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255
DATA 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
DATA 255, 255, 255, 255, 255, 255, 255, 252, 0, 255, 255, 252, 0, 255
DATA 255, 252, 0, 255, 255, 248, 0, 127, 255, 248, 0, 127, 255, 240
DATA 0, 127, 255, 240, 0, 63, 255, 224, 0, 63, 255, 224, 0, 63, 255
DATA 192, 0, 63, 255, 192, 0, 63, 255, 192, 0, 63, 255, 192, 0, 63, 255
DATA 192, 0, 127, 255, 200, 1, 255, 255, 248, 15, 255, 255, 248, 15
DATA 255, 255, 248, 15, 255, 255, 248, 31, 255, 255, 248, 127, 255, 255
DATA 248, 127, 255, 255, 248, 127, 255, 255, 252, 255, 255, 255, 255
DATA 255, 255, 255, 255, 255, 255, 255

If you write this DATA as Bytes to a File - It`s an icon (Filename.ico) or cursor (Filename.cur)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.