如何使用Windows API将菜单背景渐变复制到位图上?

如何使用Windows API将菜单背景渐变复制到位图上?,windows,delphi,winapi,menubar,Windows,Delphi,Winapi,Menubar,我试图将Windows菜单栏的背景渐变复制/再现到位图上,但未成功 在下面的IconToBitmap函数中,FillRect希望使用GetSysColorBrushCOLOR\u菜单,尝试以Windows中的方式绘制菜单背景。毫不奇怪,笔刷不是渐变,但值得一试 下面的BitBlt是一个试图欺骗的行为。抓取已经绘制的菜单栏的一部分并使用它。这也不起作用,我怀疑原因可能是因为函数IconToBitmap是在主窗口的WM_创建期间调用的。我不确定菜单栏在窗口创建的早期是否存在。在窗口第一次可见之前,我

我试图将Windows菜单栏的背景渐变复制/再现到位图上,但未成功

在下面的IconToBitmap函数中,FillRect希望使用GetSysColorBrushCOLOR\u菜单,尝试以Windows中的方式绘制菜单背景。毫不奇怪,笔刷不是渐变,但值得一试

下面的BitBlt是一个试图欺骗的行为。抓取已经绘制的菜单栏的一部分并使用它。这也不起作用,我怀疑原因可能是因为函数IconToBitmap是在主窗口的WM_创建期间调用的。我不确定菜单栏在窗口创建的早期是否存在。在窗口第一次可见之前,我确实需要背景,这就是为什么在处理WM_CREATE时调用该函数的原因,但在窗口可见之前任何其他方式都是完美的

在这一点上,我没有主意了

如果有人知道如何抓取菜单背景或在位图上重现它,那就太好了

多谢各位

PS:函数中的硬编码值将在最终工作版本中删除,希望会有一个。此外,对于Delphi,必须将数据类型ptrint更改为NativeInt

function IconToBitmap(Wnd : HWND; Icon : HICON) : HBITMAP;
var
  Bitmap      : HBITMAP;
  BitmapDc    : HDC;
  BitmapRect  : TRECT;

  OldBitmap   : HBITMAP;

  dc          : HDC;

  MenuHeight  : ptrint;
  MenuY       : ptrint;

  WindowDc    : HDC;

begin
  Bitmap      := 0;
  BitmapDc    := 0;
  OldBitmap   := 0;
  dc          := 0;

  MenuY       := 0;
  MenuHeight  := 0;

  WindowDc    := 0;


  MenuY       := GetSystemMetrics(SM_CYSIZEFRAME) +
                 GetSystemMetrics(SM_CYCAPTION);
  MenuHeight  := GetSystemMetrics(SM_CYMENUSIZE);

  WindowDc    := GetWindowDC(Wnd);


  dc          := GetDC(0);
  BitmapDc    := CreateCompatibleDC(dc);

  Bitmap      := CreateCompatibleBitmap(dc, 16, 16);
  OldBitmap   := SelectObject(BitmapDc, Bitmap);

  with BitmapRect do
  begin
    Left      := 0;
    Top       := 0;
    Right     := 16;
    Bottom    := 16;
  end;

  FillRect(BitmapDc, BitmapRect, GetSysColorBrush(COLOR_MENU));
  BitBlt(BitmapDc, 0, 0, 16, 16, WindowDc, 20, MenuY, SRCCOPY);

  DrawIconEx(BitmapDc,
             0,
             0,
             Icon,
             16,
             16,
             0,
             0,
             DI_NORMAL);

  SelectObject(BitmapDc, OldBitmap);
  DeleteDC(BitmapDc);
  ReleaseDC(0, dc);

  IconToBitmap := Bitmap;
end;
使用绘制主题部件。下面的示例在窗体的客户端区域顶部绘制菜单栏背景。您可以调整它以在位图画布上绘制

uses
  uxtheme, types;

procedure TForm1.FormPaint(Sender: TObject);
var
  Theme: HTHEME;
  Size: TSize;
  Rect: TRect;
begin
  Theme := OpenThemeData(Handle, VSCLASS_MENU);
  GetThemePartSize(Theme, Canvas.Handle, MENU_BARBACKGROUND, MB_ACTIVE, nil,
      TS_TRUE, Size);
  Rect.Create(0, 0, ClientWidth, Size.cy);
  DrawThemeBackground(Theme, Canvas.Handle, MENU_BARBACKGROUND, MB_ACTIVE,
      Rect, nil);
  CloseThemeData(Theme);
end;
在WM_绘制处理程序中,这可能如下所示

procedure TForm1.WMPaint(var Message: TWMPaint);
var
  DC: HDC;
  PS: TPaintStruct;

  Theme: HTHEME;
  Size: TSize;
  Rect: TRect;
begin
  if Message.DC = 0 then
    DC := BeginPaint(Handle, PS)
  else
    DC := Message.DC;

  Theme := OpenThemeData(Handle, VSCLASS_MENU);
  GetThemePartSize(Theme, DC, MENU_BARBACKGROUND, MB_ACTIVE, nil,
      TS_TRUE, Size);
  Rect.Create(0, 0, ClientWidth, Size.cy);
  DrawThemeBackground(Theme, DC, MENU_BARBACKGROUND, MB_ACTIVE,
      Rect, nil);
  CloseThemeData(Theme);

  if Message.DC = 0 then begin
    Message.DC := DC;
    inherited;
    EndPaint(Handle, PS);
  end else
    inherited;
end;
使用绘制主题部件。下面的示例在窗体的客户端区域顶部绘制菜单栏背景。您可以调整它以在位图画布上绘制

uses
  uxtheme, types;

procedure TForm1.FormPaint(Sender: TObject);
var
  Theme: HTHEME;
  Size: TSize;
  Rect: TRect;
begin
  Theme := OpenThemeData(Handle, VSCLASS_MENU);
  GetThemePartSize(Theme, Canvas.Handle, MENU_BARBACKGROUND, MB_ACTIVE, nil,
      TS_TRUE, Size);
  Rect.Create(0, 0, ClientWidth, Size.cy);
  DrawThemeBackground(Theme, Canvas.Handle, MENU_BARBACKGROUND, MB_ACTIVE,
      Rect, nil);
  CloseThemeData(Theme);
end;
在WM_绘制处理程序中,这可能如下所示

procedure TForm1.WMPaint(var Message: TWMPaint);
var
  DC: HDC;
  PS: TPaintStruct;

  Theme: HTHEME;
  Size: TSize;
  Rect: TRect;
begin
  if Message.DC = 0 then
    DC := BeginPaint(Handle, PS)
  else
    DC := Message.DC;

  Theme := OpenThemeData(Handle, VSCLASS_MENU);
  GetThemePartSize(Theme, DC, MENU_BARBACKGROUND, MB_ACTIVE, nil,
      TS_TRUE, Size);
  Rect.Create(0, 0, ClientWidth, Size.cy);
  DrawThemeBackground(Theme, DC, MENU_BARBACKGROUND, MB_ACTIVE,
      Rect, nil);
  CloseThemeData(Theme);

  if Message.DC = 0 then begin
    Message.DC := DC;
    inherited;
    EndPaint(Handle, PS);
  end else
    inherited;
end;

你到底在说什么梯度?旧的空气玻璃效应?或者工具栏上使用的效果?菜单栏背景的渐变。当然,它会随着主题的不同而变化,一般来说,取决于用户的偏好,但是,不管它是什么,我想要么复制背景,要么在位图中复制背景。要了解我在说什么,请启动记事本,无论记事本显示的菜单栏背景是什么,这都是我要复制或复制的背景。@AlexK.:OP可能使用的是Windows 7或更早版本,其中菜单栏确实有渐变背景。例如,请参见。当然,在Windows 10中,菜单栏的背景是纯色的。是的,我目前正在使用Windows 7,但我想抓取/复制当前使用的任何背景。这很重要。这就是为什么我试图作弊,只是将菜单栏背景的一部分位图。这似乎是获得背景条带的最简单方法。我知道如果我在处理WM_油漆时做bitblt,我可以得到它,但我需要它早于此。理想情况下,在WM_创建期间,但在窗口可见之前的任何时间都可以使用。DrawThemeBackground&friends可能值得一看。你到底在说什么梯度?旧的空气玻璃效应?或者工具栏上使用的效果?菜单栏背景的渐变。当然,它会随着主题的不同而变化,一般来说,取决于用户的偏好,但是,不管它是什么,我想要么复制背景,要么在位图中复制背景。要了解我在说什么,请启动记事本,无论记事本显示的菜单栏背景是什么,这都是我要复制或复制的背景。@AlexK.:OP可能使用的是Windows 7或更早版本,其中菜单栏确实有渐变背景。例如,请参见。当然,在Windows 10中,菜单栏的背景是纯色的。是的,我目前正在使用Windows 7,但我想抓取/复制当前使用的任何背景。这很重要。这就是为什么我试图作弊,只是将菜单栏背景的一部分位图。这似乎是获得背景条带的最简单方法。我知道如果我在处理WM_油漆时做bitblt,我可以得到它,但我需要它早于此。理想情况下,在WM_创建期间,但在窗口可见之前的任何时候都可以使用。DrawThemeBackground&friends可能值得一看。@Sertac,我正在尝试将您发布的代码转换为straight Windows API。在WM_PAINT消息中,第一个语句主题:=OpenThemeDataWnd,VSCLASS_菜单;给我一个访问权限冲突。我不熟悉主题API,我对该语句的翻译有什么错误吗?谢谢。@Sci-不知道你在做什么就说不出来。我发布了一个例子。@ Sertac,我所做的是直接编程到Windows API,因为C程序员不C++。在任何地方都没有对象,只有API调用和窗口消息处理。I您的声明,主题:=OpenThemeDataHandle,VSCLASS\u菜单;我猜想Handle参数是MSDN文档中的一个窗口句柄,因此该语句变成了Theme:=openthemetedatawnd,VS_CLASS;Wnd变量I
am passing是接收消息的窗口的句柄。因此,该值是有效的。其他一切都是一样的,但我得到了访问冲突。你知道为什么吗?窗把手好吗。函数失败时通常返回0。VSCLASS_MENU是字符串“MENU”,MENU_BABACKGROUD是7,MB_ACTIVE是1。OpenThemeData使用stdcall约定从uxtheme.dll导出,接受句柄和PWideChar参数并返回句柄。我建议你问一个提供复制案例的问题。不要编辑这个,因为这是一个完全不同的问题。塞塔克,谢谢你的耐心和帮助。我明白了为什么会有例外。Free Pascal有一个指向OpenThemeData的指针变量,只有在调用InitThemeLibrary时才会初始化该变量,MSDN文档中没有这样的细节。现在我知道为什么这么简单的函数调用不起作用了,我可以集中讨论您提供的其余代码。不幸的是,在明天之前,我将无法在这个问题上投入更多的时间,但是,我将提供反馈。这是我至少能做的。再次感谢您。@Sertac,我正在尝试将您发布的代码转换为纯Windows API。在WM_PAINT消息中,第一个语句主题:=OpenThemeDataWnd,VSCLASS_菜单;给我一个访问权限冲突。我不熟悉主题API,我对该语句的翻译有什么错误吗?谢谢。@Sci-不知道你在做什么就说不出来。我发布了一个例子。@ Sertac,我所做的是直接编程到Windows API,因为C程序员不C++。在任何地方都没有对象,只有API调用和窗口消息处理。I您的声明,主题:=OpenThemeDataHandle,VSCLASS\u菜单;我猜想Handle参数是MSDN文档中的一个窗口句柄,因此该语句变成了Theme:=openthemetedatawnd,VS_CLASS;我传递的Wnd变量是接收消息的窗口的句柄。因此,该值是有效的。其他一切都是一样的,但我得到了访问冲突。你知道为什么吗?窗把手好吗。函数失败时通常返回0。VSCLASS_MENU是字符串“MENU”,MENU_BABACKGROUD是7,MB_ACTIVE是1。OpenThemeData使用stdcall约定从uxtheme.dll导出,接受句柄和PWideChar参数并返回句柄。我建议你问一个提供复制案例的问题。不要编辑这个,因为这是一个完全不同的问题。塞塔克,谢谢你的耐心和帮助。我明白了为什么会有例外。Free Pascal有一个指向OpenThemeData的指针变量,只有在调用InitThemeLibrary时才会初始化该变量,MSDN文档中没有这样的细节。现在我知道为什么这么简单的函数调用不起作用了,我可以集中讨论您提供的其余代码。不幸的是,在明天之前,我将无法在这个问题上投入更多的时间,但是,我将提供反馈。这是我至少能做的。再次感谢你。