Robertas
Robertas

Reputation: 1222

How to get an icon associated with Windows theme?

How to get an icon of some control in Windows? More specifically I would like to get a sort arrow icon from a ListView Header. I tried to get it by using the following method:

HRESULT GetSortArrowBmp(HWND hwnd, HEADERSORTARROWSTATES arrowState, HBITMAP** arrow)
{
    HTHEME theme = OpenThemeData(hwnd,L"HEADER"); // hwnd is header itself
    HRESULT res = E_FAIL;
    if (theme){
        res = GetThemeBitmap(theme, HP_HEADERSORTARROW, arrowState, TMT_DIBDATA, GBF_COPY, *arrow);   
        CloseThemeData(theme);
    }
    return res;
} 

But it doesn't return the tiny triangle I'm expecting. Any suggestions?

Upvotes: 3

Views: 890

Answers (4)

dsmtoday
dsmtoday

Reputation: 797

I found that GetThemeBitmap() can fail for both TMT_GLYPHDIBDATA and TMT_DIBDATA. I extended mity's solution to the following.

HRESULT ret = ::GetThemeBitmap(hTheme, iPartId, iStateId, glyph ? TMT_GLYPHDIBDATA : TMT_DIBDATA, GBF_DIRECT, hBmp);
if (ret == E_INVALIDARG)
    ret = ::GetThemeBitmap(pThemeRecord->hTheme, iPartId, iStateId, 3, GBF_DIRECT, hBmp);

Magic values are scary.

Upvotes: 1

mity
mity

Reputation: 2349

According to MSDN docs, the function GetThemeBitmap() can be called for property TMT_DIBDATA (the background without the glyph) or TMT_GLYPHDIBDATA (the glyph, i.e. just the triangle here) or TMT_HBITMAP (which is not currently supported at all though).

Unfortunately I have found that with TMT_GLYPHDIBDATA the functions always fails with E_INVALIDARG. The header <vssym32.h> defines the TMT_GLYPHDIBDATA as 8. However I have found that the function gets the glyph bitmap for the constant 3.

I guess there is a bug (typo) in the header <vssym32.h> (as of Windows SDK 7.1), or implementation of GetThemeBitmap() on Windows 7.

Unless Microsoft at least documents if 3 or 8 is correct, I use this workaround in my code:

HBITMAP bmp;
HRESULT hr = GetThemeBitmap(hTheme, iPartId, iStateId, 3, GBF_DIRECT, &bmp);
if(FAILED(hr))
   hr = GetThemeBitmap(hTheme, iPartId, iStateId, TMT_GLYPHDIBDATA, GBF_DIRECT, &bmp);

Upvotes: 6

Robertas
Robertas

Reputation: 1222

As a workaround I could suggest the following function to get a bitmap image of the sort arrow.

HBITMAP GetSortArrowBmp(HWND hwnd, HEADERSORTARROWSTATES arrowState, int width, int height){
    RECT rect; // dimensions of a bitmap
    rect.left = 0;
    rect.right = width;
    rect.top = 0;
    rect.bottom = height;

    HDC hdc;
    HDC hdcMem;
    HBITMAP hBitmap;

    hdc = GetDC(hwnd);
    hdcMem = CreateCompatibleDC(hdc);
    hBitmap = CreateCompatibleBitmap(hdc, width, height);

    HTHEME theme = OpenThemeData(hwnd, L"HEADER");

    if(theme){
        DrawThemeBackground(theme, hdcMem, HP_HEADERITEM, HIS_ICONNORMAL, &rect, NULL);
        // drawing sort arrow
        DrawThemeBackground(theme, hdcMem, HP_HEADERSORTARROW, arrowState, &rect, NULL); 
    }
    CloseThemeData(theme);

    DeleteObject(hdcMem);
    ReleaseDC(hwnd, hdc);

    return hBitmap;
}

Although I didn't use this in my code. I applied the same DrawThemeBackground(theme, hdcMem, HP_HEADERSORTARROW, arrowState, &rect, NULL); function inside owner draw header which was more elegant than drawing it to the bitmap and displaying that bitmap.

Upvotes: 1

David Heffernan
David Heffernan

Reputation: 612993

I don't think the theme API will give you the icon for this. That's not the way the theme API works. Rather you simply ask it to paint the sort icon and identify it by part and state identifiers. It's listed in the Parts and States MSDN topic: HP_HEADERSORTARROW, HSAS_SORTEDDOWN, HSAS_SORTEDUP.

Edit: Having re-read your question, I see that you already know all about the parts and states!

Upvotes: 1

Related Questions