需求
幾年前,好聲音以獨特節目形式吸引了很多選手和觀眾的 觀注,旨在"只尋找優質聲音"; 可聲音各有特色時,還得看顏值,當然這也無可厚非。雖然扯得有點遠,我想表達的是軟件開發的穩定性與美觀性之間的平衡問題,亦或是功能需求與用戶體驗關系把握問題。有人認為只是功能強大,滿足需求,界面是次要的;而實際結果,功能也並不強大,界面操作也十分復雜;我個人觀點正好相反,如果我們的軟件並不能達到功能強大,運行穩定,我們更得加強界面的開發,正確地引導用戶,減少出錯機率。
下面是Excel 2019 的界面,引領着整個行業的界面風格:

現在需要將其圖標提取怎么操作?
實現
通過一些圖標提取軟件都無法提取,唯一可以使用的方法是調有官方的GetImageMso方法。
開發環境:VS2019+VSTO,以Excel為例。
首先新建一個Add In工程:

其次,在ThisAddIn類里創建一個Application對象,以便全局訪問。
public static Excel.Application App;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
App = this.Application;
}
然后,添加一個Ribbon,並新增按鍵及相關事件。

接着,使用GetImageMso方法下載相應名稱、大小的圖片。
IPictureDisp pictureDisp = ThisAddIn.App.CommandBars.GetImageMso(name, 32, 32);
最后,將IPictureDisp轉化透明圖標輸出,這是第二個關鍵點:
public class ImageHelper
{
/// <summary>
/// IPictureDisp轉Bitmap
/// </summary>
/// <param name="ipd">IPictureDisp</param>
/// <returns>Bitmap</returns>
public static Bitmap ConvertPixelByPixel(IPictureDisp ipd)
{
// get the info about the HBITMAP inside the IPictureDisp
var dibsection = new DIBSECTION();
GetObjectDIBSection((IntPtr)ipd.Handle, Marshal.SizeOf(dibsection), ref dibsection);
var width = dibsection.dsBm.bmWidth;
var height = dibsection.dsBm.bmHeight;
// create the destination Bitmap object
var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
unsafe
{
// get a pointer to the raw bits
var pBits = (RGBQUAD*)(void*)dibsection.dsBm.bmBits;
// copy each pixel manually
for (var x = 0; x < dibsection.dsBmih.biWidth; x++)
for (var y = 0; y < dibsection.dsBmih.biHeight; y++)
{
var offset = y * dibsection.dsBmih.biWidth + x;
if (pBits[offset].rgbReserved != 0)
{
bitmap.SetPixel(x, y, Color.FromArgb(pBits[offset].rgbReserved, pBits[offset].rgbRed, pBits[offset].rgbGreen, pBits[offset].rgbBlue));
}
}
}
return bitmap;
}
[StructLayout(LayoutKind.Sequential)]
private struct RGBQUAD
{
public byte rgbBlue;
public byte rgbGreen;
public byte rgbRed;
public byte rgbReserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct BITMAP
{
public int bmType;
public int bmWidth;
public int bmHeight;
public int bmWidthBytes;
public short bmPlanes;
public short bmBitsPixel;
public IntPtr bmBits;
}
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFOHEADER
{
public int biSize;
public int biWidth;
public int biHeight;
public short biPlanes;
public short biBitCount;
public int biCompression;
public int biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public int biClrUsed;
public int bitClrImportant;
}
[StructLayout(LayoutKind.Sequential)]
public struct DIBSECTION
{
public BITMAP dsBm;
public BITMAPINFOHEADER dsBmih;
public int dsBitField1;
public int dsBitField2;
public int dsBitField3;
public IntPtr dshSection;
public int dsOffset;
}
[DllImport("gdi32.dll", EntryPoint = "GetObject")]
public static extern int GetObjectDIBSection(IntPtr hObject, int nCount, ref DIBSECTION lpObject);
}

成果
Word圖標:

Excel圖標:

PowerPoint圖標:

Project圖標:

Visio 圖標:

打包圖片資源下載:
https://download.csdn.net/download/ADKIIDGTFK926/12078303
參考
https://blog.csdn.net/blackwoodcliff/article/details/89891405
https://github.com/OfficeDev/office-fluent-ui-command-identifiers
