提取 Office 2016 工具栏图标

article/2025/4/26 2:13:32

Office 图标精美漂亮,作为微软的官方图标,与 Windows 具有一致的风格,但我们若想把这些图标用在自己的程序中,却并不容易,使用常规的提取程序资源的方法,根本得不到这些图标。
微软虽然没有把这些图标开放给我们下载使用,但在 Office VBA 中,微软却是允许我们随意使用的。通过调用 CommandBars.GetImageMso 方法,我们可以得到指定控件的图标。
CommandBars.GetImageMso 方法的第一个参数,要求提供控件的标识符。那么我们怎么知道 Office 中有哪些控件,标识符又是什么呢?在这方面,微软做的还是非常好的,Office Fluent UI Command Identifiers (https://github.com/OfficeDev/office-fluent-ui-command-identifiers),在这个网址,微软提供了 Office 所有控件的标识符。

本篇文章中,我们将新建一个 Excel 文件,并创建一个用户窗体,在用户窗体上显示一些带图标的按钮,点击按钮即可将按钮上的图标导出到 PNG 文件。

创建窗体

在窗体上摆放 500 个按钮,用于显示图标。由于图标较多,有几千个,再在窗体上放一个 TabStrip,用于切换显示的图标。

Private Sub AddControls()Set tabStrip1 = Me.Controls.Add("Forms.TabStrip.1", "tabStrip1", True)With tabStrip1.Left = 0.Top = 0.Width = 860.Height = 705End WithtabStrip1.Tabs(0).Caption = "1-500"tabStrip1.Tabs(1).Caption = "501-1000"Dim num As IntegerFor num = 1000 To 7000 Step 500tabStrip1.Tabs.Add "Forms.Tab." & (tabStrip1.Tabs.Count + 1), (num + 1) & "-" & (num + 500)Next numSet CheckBox1 = Me.Controls.Add("Forms.CheckBox.1", "checkBox1", True)With CheckBox1.Caption = "大图标".Left = 800.Top = 0.Width = 45.Height = 15.Value = TrueEnd WithDim CmdBtn As MSForms.CommandButtonDim rows As IntegerDim cols As IntegerFor rows = 1 To 20For cols = 1 To 25Set CmdBtn = Me.Controls.Add("Forms.CommandButton.1", "commandButton" & rows & cols)With CmdBtn.Name = "image" & ((rows - 1) * 25 + cols).Left = 5 + 34 * (cols - 1).Top = 18 + 34 * (rows - 1).Width = 34.Height = 34.PicturePosition = fmPicturePositionCenterEnd WithNext colsNext rows
End Sub

在这里插入图片描述

显示图标

获取 Office 图标的唯一方法 CommandBars.GetImageMso,用这个方法得到图标后,赋值给按钮的 Picture 属性。

Private Sub ShowImages()On Error Resume NextDim idx As Integer, imgIdx As IntegerDim btn As MSForms.CommandButtonDim pic As IPictureDispDim ImgSize As LongIf CheckBox1.Value = True Then ImgSize = 32 Else ImgSize = 16For idx = 1 To 500imgIdx = idx + 500 * tabStrip1.ValueSet btn = Me.Controls.Item("image" & idx)If imgIdx <= 7345 ThenSet pic = NothingSet pic = Application.CommandBars.GetImageMso(Replace(Range("A" & imgIdx).Value, Chr(34), ""), ImgSize, ImgSize)With btn.Visible = True.Caption = "".Picture = pic.ControlTipText = imgIdx & "-" & Replace(Range("A" & imgIdx).Value, Chr(34), "")End WithElsebtn.Visible = FalseEnd IfNext idx
End Sub

在这里插入图片描述

导出图标

要把图标导出到 PNG 文件,首先想到的就是使用 GDI+。GDI 不能处理 PNG 格式,可用 GDI+ 的 GdipCreateBitmapFromHBITMAP 函数把 StdPicture 转换成 GDI+ 的 Bitmap,然后再用 GdipSaveImageToFile 函数保存到 PNG 格式文件。
图样图森破,用这个方法虽然确实导出了 PNG 图片,但导出的 PNG 图片背景是白色的,这并不是我想要的结果,我希望导出的是背景透明的 PNG 图片。

试错

背景不透明,毫无疑问是 Alpha 值的问题。所以首先就想到,把转换来的 GDI+ 的 Bitmap 的 Alpha 值,根据原始图片的 Alpha 值重新设置一遍,然后再保存。具体思路是:

  1. 使用 GetDIBits 函数,获得通过 GetImageMso 得到的 StdPicture 的原始数据
  2. 使用 GdipBitmapGetPixel 函数取得 GDI+ 的 Bitmap 的每个像素值
  3. 根据原始数据,修改每个像素的 Alpha 值
  4. 使用 GdipBitmapSetPixel 函数,把修改 Alpha 后的像素值写回 Bitmap
  5. 保存成 PNG 图片

经过实践,发现执行 GdipBitmapSetPixel 函数后,各个像素的 Alpha 值并没有改变,导出的图片仍然是白色背景。

再试错

接着上面的思路,既然单独修改 Alpha 值不好用,那么干脆就把 GDI+ Bitmap 的图像数据全部替换成原始数据。具体步骤是:

  1. 使用 GetDIBits 函数,获得通过 GetImageMso 得到的 StdPicture 的原始数据
  2. 使用 GdipBitmapLockBits 函数取得 GDI+ 的 Bitmap 的图像数据
  3. 把得到的 GDI+ Bitmap 的图像数据替换成 StdPicture 的原始数据
  4. 使用 GdipBitmapUnlockBits 函数把修改后的图像数据写回 Bitmap
  5. 保存成 PNG 图片

实践之后,发现虽然 Alpha 值改变了,但导出的图片仍然是白色背景。这是为什么呢?

发现原因

突然想到,GDI+ Bitmap 有多种像素格式,那么使用 GdipCreateBitmapFromHBITMAP 函数得到的 Bitmap 的 PixelFormat 是什么呢?
通过 GdipGetImagePixelFormat 函数得到 Bitmap 的 PixelFormat,发现是 PixelFormat32bppRGB
这就不对了,透明背景的 Bitmap,PixelFormat 应该是 PixelFormat32bppARGB,上面的格式里明显少了一个 A,而正是这个 A 表示图像是否能够透明。
至此,就可以很容量理解上面一再试错仍不成功的原因了。无论修改 Alpha 值也好,还是替换整个图像数据也好,但 Bitmap 的 PixelFormat 仍然没有变,依然是 PixelFormat32bppRGB,是不支持透明的。要想让图片透明,必须把 PixelFormat 变成支持透明的格式。

创建透明 Bitmap

发现了问题原因,解决办法就很容易找到了。
既然 GdipCreateBitmapFromHBITMAP 函数得到的 Bitmap 是不透明的,那么就没必要在这上面折腾了,不如直接创建一个支持透明的图片。具体思路是:

  1. 使用 GetDIBits 函数,获得通过 GetImageMso 得到的 StdPicture 的原始数据
  2. 使用 GdipCreateBitmapFromScan0 函数创建一个 PixelFormat32bppARGB 格式的 Bitmap
  3. 使用 GdipBitmapLockBits 函数取得 Bitmap 的图像数据区
  4. 复制 StdPicture 的原始数据到 Bitmap 的图像数据区
  5. 使用 GdipBitmapUnlockBits 函数把图像数据写回到 Bitmap
  6. 把 Bitmap 保存成 PNG 图片
Public Sub HBITMAPToBitmapARGB(gdiHdc As Long, gdiHBITMAP As Long, gdipBitmap As Long)Dim bmi As BITMAPINFODim bBits() As ByteGetDIBitsInfo gdiHdc, gdiHBITMAP, bmiGetDIBitsData gdiHdc, gdiHBITMAP, bmi, bBitsDim bmWidth As Long, bmHeight As LongbmWidth = bmi.bmiHeader.biWidthbmHeight = Abs(bmi.bmiHeader.biHeight)Dim rc As RECTLrc.Left = 0rc.Top = 0rc.Right = bmWidthrc.Bottom = bmHeightDim data() As ByteReDim data(rc.Right * 4 - 1, rc.Bottom - 1)Dim BmpData As BitmapDataWith BmpData.Width = rc.Right.Height = rc.Bottom.PixelFormat = GpPixelFormat.PixelFormat32bppARGB.scan0 = VarPtr(data(0, 0)).stride = 4 * CLng(rc.Right)End WithDim lineSize As LonglineSize = iIconBPP / 8 * bmWidthDim x As Long, y As Long, z As LongDim lineStart As Long, colorStart As LongCreateBitmap gdipBitmap, bmWidth, bmHeight, PixelFormat32bppARGBGdipBitmapLockBits gdipBitmap, rc, ImageLockModeUserInputBuf Or ImageLockModeWrite Or ImageLockModeRead, GpPixelFormat.PixelFormat32bppARGB, BmpDataFor y = 0 To bmHeight - 1lineStart = (bmHeight - y - 1) * lineSizeCopyMemory ByVal VarPtr(data(0, y)), ByVal VarPtr(bBits(lineStart)), lineSizeNextGdipBitmapUnlockBits gdipBitmap, BmpData
End Sub

后记

在写本文时,发现了两个函数:

  • GdipBitmapConvertFormat
  • Bitmap.MakeTransparent

第一个函数 GdipBitmapConvertFormat 用于转换像素格式,那么我们把由 GdipCreateBitmapFromHBITMAP 函数得到的 Bitmap 的 PixelFormat 转换成 PixelFormat32bppARGB,然后再修改 Alpha 值,是不是就可以生成透明背景的 PNG 了?
GdipBitmapConvertFormat 可以参考 https://bbs.csdn.net/topics/390320347
第二个函数 Bitmap.MakeTransparent 是 .NET 里 Bitmap 类的 MakeTransparent 方法。这个方法可以把指定的颜色变为透明色。那么是不是可以考虑通过 Office PIA 的 CommandBarsClass.GetImageMso 得到图标,再用 Image.FromHbitmap 转换成 GDI+ Bitmap。此时得到的图片应该是白色背景的,这时候再用 Bitmap.MakeTransparent 方法把白色变为透明色,然后用 Bitmap.Save 方法保存成 PNG 格式图片。
但是仔细想想,如果图标中有白色的话,是不是也给变成透明色了,看来这个 Bitmap.MakeTransparent 还是不太适用。

源码下载

https://download.csdn.net/download/blackwoodcliff/11180913

此源码只适用于 32 位 Office,若要在 64 位 Office 上使用,需做如下修改:

  • 将 Long 型变量替换成 LongLong 型
  • 声明 API 函数的语句中的 Declare 后面要加 PtrSafe

参考

  • 提取Office 2003工具栏图标
  • 【VB6 Gdi+进阶】序章
  • 3. GDI+ Bitmap和GDI HBITMAP互转
  • EXCEL VBA GetSaveAsFilename保存文件例子

http://chatgpt.dhexx.cn/article/PHAXNDBW.shtml

相关文章

office图标异常解决办法

问题描述&#xff1a; 前不久才重装过系统&#xff0c;可是没多久就出现了一个很恶心的问题&#xff1a;word文档、excel文档图标异常&#xff0c;显示的是下面这样&#xff1a; &#xff08;造成这样的原因一般是装了 wps&#xff0c;卸载后又装了office&#xff09; 打开…

office图标显示异常和新建时图标没有显示等问题解决

1.office图标显示异常问题解决方法 1>点击“开始” 2>在在运行命令行中输入“regedit”&#xff0c;找到regedit.exe执行文件&#xff0c;点击进入注册表 3>在左侧找到HKEY_CLASSES_ROOT目录&#xff0c;并展开&#xff1a; 4>删除其中一些注册表选项&#xff1…

卸载office后桌面上的word文件图标变成了白色

如图所示&#xff1b; 解决办法&#xff1a;适用Office2016/365中的Word、PowerPoint、Excel文件图标因安装WPS造成图标异常&#xff0c;显示为无法识别的程序图标&#xff0c;卸载、重装都不能修复&#xff0c;但能正常使用。 解决办法&#xff1a; 1、运行regedit&#xff0c…

修复Microsoft Office的Word、Excel、PPT丢失图标

文章目录 打开注册表Word注册表Excel注册表PPT注册表修复 使用注册表方式修复&#xff0c;删除Word、Excel、PPT的对应文件夹&#xff0c;那个丢失&#xff0c;就删除那个&#xff0c;然后修复 打开注册表 Windows R 打开电脑中的运行界面&#xff0c;输入命令回车: regedit …

将默认打开方式改成Office后,桌面办公软件图标变成白板

(注意&#xff1a;修改注册表有风险&#xff0c;请谨慎使用) 通过注册表解决。关键看图标是否仍然关联WPS&#xff0c;如果有则删除相关关联参数 步骤1&#xff1a;同时按WinR键&#xff0c;输入regedit打开注册表 步骤2&#xff1a;在注册表中打开HKEY_CLASSES_ROOT​文件夹…

新建文件没有word、ppt、excel,office图标显示为白色,不能正常显示

新建文件没有word、ppt、excel&#xff0c;office图标显示为白色&#xff0c;不能正常显示 解决办法&#xff1a; 1、按“winR”输入“regedit”运行&#xff0c;打开系统注册表&#xff1b; 2、找到HKEY_CLASSES_ROOT下的.doc、.docx、.ppt、.pptx、.xls、.xlsx&#xff0c;删…

卸载wps后,win10的office所有图标变白最简单方法

wps卸载后&#xff0c;所有图标都变白了&#xff0c;找到简单的方法 网上很多需要修改注册表&#xff0c;重装之类&#xff0c;现在找到一个最简单的方法&#xff0c;测试有效 1、进入控制面板&#xff0c;找到office的安装程序 2、右键更改&#xff0c;选择快速修复&#xf…

window10安装office之后开始菜单不显示office快捷方式图标

window10安装office之后开始菜单不显示office图标 1、问题描述2、解决办法 1、问题描述 我安装的是office2019专业增强版 但是安装完之后开始菜单就是不出现 Word、Excel、PowerPoint 的快捷方式&#xff0c;只能通过右键选择 新建 进入。而且卸载了重装也还是不出现。 2、…

[Win10] 解决 Office 安装后图标空白的问题

本文介绍了安装 Office 后出现图标空白的解决方法。问题如下图所示。 步骤 1 打开控制面板 — 程序 — 默认程序 — 文件协议或类型关联&#xff0c;将 Word 相关的文件类型&#xff08;如.doc&#xff0c;.docx&#xff09;与 Word 相关联。 PPT&#xff0c; Excel 等同理 步…

WPS图标如何改成office图标(取消WPS默认方式)

1.在安装完WPS之后发现我们桌面关于office的图标都成了WPS图标并且默认打开方式都成为了WPS打开。而只是偶尔用一下WPS打开一些文件按下面步骤! 2.WPS安装好后&#xff0c;点击开始-- WPS Office–配置工具 3.双击配置工具-- 单击 高级(A) 4.取消勾选 WPS office兼容第三方系…

【window】解决word,excel,PowerPoint 等office图标不显示问题

记录一下,以防下次忘记 因为之前安装过wps 所以当我把wps卸载后重新用office,但是我的图标不见了。。卸载了重新安装了也不没显示。 进入正题 1、首先我们要先安装好office后,先找一下这些图标所在的文件夹,一般都在 C:\Program Files\Microsoft Office\root\vfs\Windo…

office中mathtype图标不显示或者显示但是功能灰色

最近在帮解决office中安装完mathtype后mathtype选项卡下方功能区灰色无法使用问题时&#xff0c;有一些经验在此分享。特别说明&#xff1a;mathtype必须激活才可以&#xff0c;不然还会有更多问题&#xff0c;请大家支持软件正版&#xff01; 写在前面&#xff1a;进行下列操…

Win10系统Office 软件图标变白两种解决方法

问题描述&#xff1a;因为清理C盘的时候&#xff0c;不小心把office的图标文件删除了。导致word、excel、ppt文件图标都变成白色的了。 问题原因&#xff1a;因为注册表里office的DefaultIcon键值找不到文件,导致图标空白。 解决方法&#xff1a;将对应的图标文件修改为offic…

【电脑Windows日常】解决Windows11 无法显示office图标的问题

运行 regedit 打开注册表 &#xff0c;已下的标红的部分&#xff0c;两个都改下 1. PPT 右边红框圈住的不一样&#xff0c;照着改 改下默认路径&#xff0c;我的路径&#xff08;C:\Program Files\Microsoft Office\root\Office16\POWERPNT.EXE&#xff09; 重置下默认应用…

Windows11 无法显示office图标

运行 regedit 打开注册表 &#xff0c;标红两个都改下 ppt 右边红框圈住的不一样&#xff0c;照着改 改下默认路径&#xff0c;我的路径&#xff08;D:\Program Files\Microsoft Office\Office16\POWERPNT.EXE&#xff09; 重置下默认应用就可以刷新图标了 word 同ppt…

Python编程 print输出函数

作者简介&#xff1a;一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.输入与输出 1.print&#xff08;&#xff09;输出函数 2.sep 3.e…

python基础-print输出函数

C语言的输出用的是printf&#xff0c;python的输出用的是print&#xff0c;那么具体要怎么用这个函数呢&#xff0c;我们利用这篇文章来讲解一下。 一、简单输出 a3 b2 print (a) #变量 print (ab) #表达式 print (99) #常量 print (Hello World!) #字符串&#…

输出函数print的使用

文章目录 前言print()函数的使用1、可以输出数字2、可以输出字符串3、含有运算符的表达式4、将数据输出文件中5、不进行换行输出&#xff08;输出内容在一行当中&#xff09; 前言 此篇文章是我在B站学习时所做的笔记&#xff0c;部分为亲自动手演示过的&#xff0c;方便复习用…

python语言中print函数的作用_python中如何使用print函数

Python中print语句 1.逗号分隔符 在Python中print语句可根据sys.stdout中包含的文件生成输出,它接受一个逗号分隔的对象表,如下实例:x = 1 y = 2 z = 3 print("the values are", x, y, z) #打印结果为 the values are 1 2 3 在上述实例中,对于每个对象,将…

python print 函数详解

python print 函数 文章目录 python print 函数1. 语法2. 实战2.1 输出不同格式字符串2.2 使用 flush 参数生成一个 Loading 的效果2.3 输出各类数据类型2.4 输出格式化字符串2.5 自动换行与不换行 1. 语法 以下是 print() 方法的语法: print(*objects, sep , end\n, filesys…