【问题标题】:Windows 10 Close, Minimize and Maximize buttonsWindows 10 关闭、最小化和最大化按钮
【发布时间】:2016-03-04 10:56:25
【问题描述】:

要绘制主题按钮,我使用以下代码:

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 主题绘制关闭按钮吗?

【问题讨论】:

  • 你用的是什么版本的Delphi?
  • 添加标签delphi-xe7,这对这个不重要(我认为),而且,我是在Window 8下开发的,但是这个画得像在Windows 7下
  • 不是很清楚你的问题是什么。按照我的理解,您正在尝试绘制与 Windows 版本匹配的主题。这应该默认发生,无需任何编码。听起来您使用的是非常旧的 Delphi 版本,没有运行时主题。你能提供你所期望的和你看到的截图吗?
  • 我认为不可能做你想做的事。我觉得你需要自己画。
  • 我不认为有用于此的 api。我也认为这个问题的标签很糟糕。正如你所知,尽管@Jerry 说这不是德尔福问题。如果我是你,我会删除 Delphi 标记并仅使用 winapi 重新标记。

标签: winapi windows-themes


【解决方案1】:

解决此问题的方法之一:手动解析活动 *.msstyles 文件。通常这是 aero.msstyles。存储在 STREAM 部分中的不同窗口控件的位图。对于 Windows 7 ResId = 971,Windows 8:Id = 1060,Windows 10:Id = 1194。但这是手动工作,此位图不同。

更新:

我发现,即使对于一个版本的 Windows(测试为 8),我们也可以为该位图(png 图像)设置不同的资源 id 值,现在我可以提供在任何 Windows 上获取资源 id 的代码(测试 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?

【讨论】:

  • 破解实现细节是不可行的。这是一个非常糟糕的主意。
  • 为什么这是个坏主意?解决这个问题我们有3种可能: 1.使用官方api(未提供); 2. 制作按钮截图(这很简单,但不支持其他主题); 3. 提供了阅读主题png内容的代码(目前我正在准备解析这个png,会支持不同的主题)。我很高兴听到另一个更方便的解决方案
  • 因为它不会像你发现的那样可靠地工作
  • 其他调查显示,来自 Wine 和 ReactOS 的人拥有读取 *.msstyles 文件的源代码。而这项工作可以在阅读此来源后完成:source.winehq.org/source/dlls/uxtheme/stylemap.c
  • 在发布新版本操作系统之前一直有效
【解决方案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 usage,非常感谢 Vista Style Builder 程序的作者 Andreas Verhoeven

【讨论】:

    猜你喜欢
    • 2011-03-13
    • 2016-10-04
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    • 2012-12-16
    相关资源
    最近更新 更多