Theme Api - Как же рисовать Explorer Bar, точнее GroupPanel?
От: Rius Россия  
Дата: 20.05.05 17:51
Оценка:
В Проводнике Windows есть панели групп, например "System Tasks", "Other Places", "Details", висят они обычно слева.
Пытаюсь сам нарисовать такую панель, теперь уже средствами ThemeAPI (MS Visual Styles). В частности прорисовка любой части панели через DrawThemeBackground.

В чем проблема: когда Windows XP использует стандартную голубую тему оформления Luna, все выглядит хорошо, как в Проводнике.
Когда меняю стиль на любой другой (назависимо от того, пропатчена винда для работы с не Microsoft'овскими стилями, или нет), изображения на панели групп не соответствуют используемым в Проводнике.
При копании в системных ресурсах (програмой Restorator) выяснилось, что Theme API берет их из файла темы *.msstyles (например "Longhorn Aero.msstyles"), как вроде и предполагается. Но сам Проводник вытаскивает эти изображения (а именно фон панели групп, заголовок и кнопки сворачивания/разворачивания, в комплектации для обычных (Normal) и специальных (Special) вариантов панели) из файла shellstyle.dll, относящегося к текущей теме. Причем эти изображения в shellstyle.dll и *.msstyles отличаются.
С элементами оформления кнопки никаких проблем нет, соответствующие изображения присутсвуют в *.msstyles, а в shellstyle.dll альтернатива отсутствует.
В MSDN нарыл функцию SHGetShellStyleHInstance(), которая возвращет хэндл этой shellstyle.dll, можно обращаться к картинкам как к ресурсам в DLL, но по идее это должно выполняться через ThemeAPI стандартно.

В MSDN есть пара статей, но про эти подводные камни — ни слова, как и в статье Поддержка Windows Visual Styles (Themes) API в Ваших органах управления
Автор(ы): Акжан Абдулин
Дата: 04.12.2001
(с нее и начинал разбираться). А информации по ThemeApi в сети, судя по тому что наскреб при поиске, — кот наплакал. Немногие примеры относятся к прорисовке стандартной кнопки, а про панели в Explorer Bar — ни слуху, ни духу.

Вот код в C++ Builder 6. Рисует заголовок Group Panel на форме в левом верхнем углу. Используется статическая линковка с uxtheme.lib (при динамическом подключении к uxtheme.dll проблема остается).

typedef  HINSTANCE (__stdcall *tdefSHGetShellStyleHInstance) ();
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    HTHEME hTheme;
    WideString themepartname;
    bool FSpecialHeader;
    bool FIsThemeActived;
    bool FIsAppThemed;
    int FHeightMin = 30;

//    if(hTheme) CloseThemeData(hTheme);
    hTheme = NULL;
    themepartname = "ExplorerBar";
    FIsThemeActived = IsThemeActive();
    FIsAppThemed = IsAppThemed();

//    HANDLE hwnd = Panel2->Handle;
    HANDLE hwnd = this->Handle;
    HDC hDC = GetDC(hwnd);

    if(FIsAppThemed)
    {
            hTheme = OpenThemeData(hwnd, themepartname);
    }
    RECT rc, rcContent;
    TCHAR szText[255];
    HRESULT hr;
    size_t cch;
    int iState = 0;

    GetWindowText(hwnd, szText,
                  (sizeof(szText)/sizeof(szText[0])+1));
    WideString WideText = WideString(szText);
    wchar_t *w_szstr = WideText.c_bstr();
    hr = strlen(szText);
    cch = hr;

    HINSTANCE hShellStyle;//указатель на библиотеку стилей
    HINSTANCE hShell32 = LoadLibrary("shell32.dll");

    tdefSHGetShellStyleHInstance SHGetShellStyleHInstance = NULL;
    SHGetShellStyleHInstance = (tdefSHGetShellStyleHInstance) GetProcAddress(hShell32, "SHGetShellStyleHInstance");//получение указателя на функцию
    if(SHGetShellStyleHInstance != NULL) hShellStyle = SHGetShellStyleHInstance();//функция возвращает хэндл библиотеки стилей
    FreeLibrary(hShell32);

    if (hTheme)
    {
        //Прорисовка заголовка
            //Вывод фона заголовка
            Graphics::TBitmap *bmp;

            rc.left = 0;
            rc.top = 0;
            rc.right = 150;
            rc.bottom = 40;

            int ebp = 0;
            ebp = (FSpecialHeader ? EBP_SPECIALGROUPHEAD : EBP_NORMALGROUPHEAD);
            // Always check your result codes.


            //Вычисление и установка региона для панели
//            HRGN HeadRgn;
//            GetThemeBackgroundRegion(hTheme, hDC, ebp, iState, &rc, &HeadRgn);
//            SetWindowRgn(hwnd, HeadRgn, true);

            //Прорисовка фона родителя
            hr = DrawThemeParentBackground(hwnd, hDC, &rc);

            //Вычисление координат контента
            hr = GetThemeBackgroundContentRect(hTheme,
                    hDC,
                    ebp,
                    iState,
                    &rc,
                    &rcContent);

//            {
//                bmp = new Graphics::TBitmap();
//
//                bmp->LoadFromResourceID((unsigned int)hShellStyle, (FSpecialHeader ? 110 : 112));//вытаскивание картинки из ресурсов DLL
//                Canvas->StretchDraw(rcContent, bmp);
//                delete bmp;
//            }
            hr = DrawThemeBackground(hTheme, hDC, ebp,
                    iState, &rcContent, 0);

//            hr = DrawThemeIcon(hTheme, hDC, ebp, iState, &rcContent, (HIMAGELIST)ImageList1->Handle, 2);
            wchar_t *wstr = L"12345678901234567890123456789012345678901234567890";
            hr = GetThemeFilename(hTheme, ebp, iState, UpDown1->Position, wstr, 50);
            if(hr == S_OK) Caption = WideString(wstr);
            else Caption = "Form1";
    }
    ReleaseDC(hwnd, hDC);
    CloseThemeData(hTheme);
}


используемые идентификаторы из файла tmschema.h:
...
//---------------------------------------------------------------------------------------
//   "ExplorerBar" Parts & States
//---------------------------------------------------------------------------------------
BEGIN_TM_CLASS_PARTS(EXPLORERBAR)
    TM_PART(1, EBP, HEADERBACKGROUND)
    TM_PART(2, EBP, HEADERCLOSE)
    TM_PART(3, EBP, HEADERPIN)
    TM_PART(4, EBP, IEBARMENU)
    TM_PART(5, EBP, NORMALGROUPBACKGROUND)
    TM_PART(6, EBP, NORMALGROUPCOLLAPSE)
    TM_PART(7, EBP, NORMALGROUPEXPAND)
    TM_PART(8, EBP, NORMALGROUPHEAD)
    TM_PART(9, EBP, SPECIALGROUPBACKGROUND)
    TM_PART(10, EBP, SPECIALGROUPCOLLAPSE)
    TM_PART(11, EBP, SPECIALGROUPEXPAND)
    TM_PART(12, EBP, SPECIALGROUPHEAD)
END_TM_CLASS_PARTS()
...


Please, наставьте на путь истинный, что я не так делаю?
Примеры того, что получилось в нестандартной и в стандартной темах:


Спасибо за внимание.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.