Windows 10 Закрыть, свернуть и развернуть кнопки

Чтобы нарисовать тематическую кнопку я использую этот код:

var
  h: HTHEME;
begin
  if UseThemes then begin
    SetWindowTheme(Handle, 'explorer', nil);
    h := OpenThemeData(Handle, 'WINDOW');
    if h <> 0 then
    try
      DrawThemeBackground(h, Canvas.Handle, WP_CLOSEBUTTON, GetAeroState, ClientRect, nil);
    finally
      CloseThemeData(h);
    end;
  end
  else
    DrawFrameControl(Canvas.Handle, ClientRect, DFC_CAPTION, DFCS_CAPTIONCLOSE or GetClassicState)
end;

Этот код работает нормально, но нарисованная кнопка выглядит как из темы Windows 7, даже в Windows 8 или 10. Это можно нарисовать кнопку Закрыть, используя тему Windows 10 или 8?

2 ответа

Решение

Работоспособное решение для получения растровых изображений из темы:

var
  h: HTHEME;
  Rect: TRect;
  BufSize: Cardinal;    

h := OpenThemeData(Handle, 'DWMWINDOW');
if h <> 0 then
try
  GetThemeRect(h, WP_MINCAPTION, MNCS_ACTIVE, TMT_ATLASRECT, Rect);
  ...
  GetThemeStream(...);
finally
  CloseThemeData(h);
end;

А как использовать GetThemeStream описано здесь: Использование GetThemeStream, большое спасибо Андреасу Верховену, автору программы Vista Style Builder

Один из способов решения этого вопроса: ручной анализ активного файла *.msstyles. Обычно это aero.msstyles. Растровое изображение для различных оконных элементов управления, хранящихся в разделе STREAM. Для Windows 7 ResId = 971, Windows 8: Id = 1060, Windows 10: Id = 1194. Но это ручная работа, и эти растровые изображения отличаются.

Обновить:

Я обнаружил, что даже для одной версии Windows (проверено на 8) у нас могут быть разные значения идентификатора ресурса для этого растрового изображения (изображение PNG), и теперь я могу предоставить код для получения идентификатора ресурса в любой Windows (проверено на 7,8,10):

function EnumStreamProc(hModule: HMODULE; AType, AName: PChar; Params: LPARAM): BOOL; stdcall;
var
  Id: NativeInt;
begin
  PNativeInt(Params)^ := Integer(AName);
  Result := False;
end;

function GetStyleResourceId(AModule: HMODULE): Integer;
begin
  Result := 0;
  EnumResourceNames(AMODULE, 'STREAM', @EnumStreamProc, LPARAM(@Result));
end;

var
  hLib: HMODULE;
  ResId: Integer;
  RS: TResourceStream;
  Png: TPngImage;

begin
  hLib := LoadLibraryEx(PChar(GetWindowsPath + 'Resources\Themes\Aero\aero.msstyles'), 
                        0, LOAD_LIBRARY_AS_DATAFILE);
  ResId := GetStyleResourceId(hLib);
  RS := TResourceStream.CreateFromID(hLib, ResId, 'STREAM');
  Png := TPngImage.Create;
  Png.LoadFromStream(RS);  
  ...
end;

Обновление 2:

Найден не взломанный метод с использованием официальных API:

var
  h: HTHEME;
  Rect: TRect;
  PBuf, PPBuf: Pointer;
  BufSize: Cardinal;
  Buf: array[0..1024*1024] of Byte;


h := OpenThemeData(Handle, 'DWMWINDOW');
if h <> 0 then
try
  GetThemeRect(h, WP_MINCAPTION, MNCS_ACTIVE, TMT_ATLASRECT, Rect);
  PBuf := @Buf[0];
  PPBuf := @PBuf;
  GetThemeStream(h, WP_MINCAPTION, MNCS_ACTIVE, TMT_ATLASRECT, PBuf, BufSize, hInstance);
finally
  CloseThemeData(h);
end;

Я могу получить Rect для свернутой кнопки, но не понимаю, как использовать GetThemeStream? Там должны быть использованы PBuf или PPBuf?

Другие вопросы по тегам