3

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?

Robertas
  • 1,164
  • 3
  • 11
  • 26

4 Answers4

6

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);
mity
  • 2,299
  • 17
  • 20
1

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.

dsmtoday
  • 747
  • 1
  • 6
  • 13
1

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!

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Well, sort of... I thought `GetThemeBitmap` method with specific parts and states will return me a bitmap containing the sort icon as specified in [msdn documentation](http://msdn.microsoft.com/en-us/library/windows/desktop/bb773388(v=VS.85).aspx). But all I get is a background color. – Robertas Dec 05 '11 at 14:09
  • 2
    The documentation for the theme API and especially parts and themes is simply pathetic. If you call `GetThemeBitmap` and get nothing back, most likely that's by design. But good luck finding anything official that states that. – David Heffernan Dec 05 '11 at 14:12
1

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.

Robertas
  • 1,164
  • 3
  • 11
  • 26