Ваш анализ верен.SetWindowTheme
работает для оконных элементов управления, но TSpeedButton
и TBitBtn
не являются элементами управления без вывода на экран.
В моем быстром сканировании в XE кажется, что большинство элементов управления вызывают Themes.ThemeControl
, чтобы определить, следует лирисовать тематически.Таким образом, простое решение состоит в том, чтобы заменить эту процедуру на логику, которой вы управляете.Поскольку он не предоставляет никаких точек расширения, вам нужно подключить его.Например:
procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
OldProtect: DWORD;
begin
if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
begin
Move(NewCode, Address^, Size);
FlushInstructionCache(GetCurrentProcess, Address, Size);
VirtualProtect(Address, Size, OldProtect, @OldProtect);
end;
end;
type
PInstruction = ^TInstruction;
TInstruction = packed record
Opcode: Byte;
Offset: Integer;
end;
procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
NewCode: TInstruction;
begin
NewCode.Opcode := $E9;//jump relative
NewCode.Offset := NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode);
PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;
function MyThemeControl(AControl: TControl): Boolean;
begin
Result := False;
if AControl = nil then exit;
if AControl is TSpeedButton then exit;
if AControl is TBitBtn then exit;
Result := (not (csDesigning in AControl.ComponentState) and ThemeServices.ThemesEnabled) or
((csDesigning in AControl.ComponentState) and (AControl.Parent <> nil) and
(ThemeServices.ThemesEnabled and not UnthemedDesigner(AControl.Parent)));
end;
initialization
RedirectProcedure(@Themes.ThemeControl, @MyThemeControl);
В нынешнем виде это не будет работать с пакетами времени выполнения, но достаточно просто расширить код для работы с пакетами.