11

256 x 256 の Windows Vista アイコンを作成したアプリケーションがあります。

アプリケーション アイコンとして使用される ico ファイルで 256x256 PNG ファイルを使用し、フォームの画像ボックスに表示するにはどうすればよいか考えていました。

私は VB.NET を使用していますが、C# での回答は問題ありません。リフレクションを使用する必要があるかもしれないと考えています。

これが Windows XP でも可能かどうかはわかりません。また、Windows Vista API が必要になる可能性があります。

4

5 に答える 5

10

今日、私はVista のアイコンから 256x256 ビットマップを抽出するための非常に優れた関数を作成しました。

あなたと同じように、Nathan W、私はそれを使用して、[About] ボックスに大きなアイコンをビットマップとして表示します。たとえば、次のコードは Vista アイコンを PNG 画像として取得し、256x256 の PictureBox に表示します。

picboxAppLogo.Image = ExtractVistaIcon(myIcon);

この関数は Icon オブジェクトをパラメーターとして受け取ります。そのため、リソース、ファイル、ストリームなど、あらゆるアイコンで使用できます。(EXEアイコンの抽出については以下をお読みください)。

Win32 API を使用しないため、任意の OSで実行できます。100% マネージ コードです:-)

// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx
// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx

Bitmap ExtractVistaIcon(Icon icoIcon)
{
    Bitmap bmpPngExtracted = null;
    try
    {
        byte[] srcBuf = null;
        using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
            { icoIcon.Save(stream); srcBuf = stream.ToArray(); }
        const int SizeICONDIR = 6;
        const int SizeICONDIRENTRY = 16;
        int iCount = BitConverter.ToInt16(srcBuf, 4);
        for (int iIndex=0; iIndex<iCount; iIndex++)
        {
            int iWidth  = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex];
            int iHeight = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex + 1];
            int iBitCount   = BitConverter.ToInt16(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 6);
            if (iWidth == 0 && iHeight == 0 && iBitCount == 32)
            {
                int iImageSize   = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 8);
                int iImageOffset = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 12);
                System.IO.MemoryStream destStream = new System.IO.MemoryStream();
                System.IO.BinaryWriter writer = new System.IO.BinaryWriter(destStream);
                writer.Write(srcBuf, iImageOffset, iImageSize);
                destStream.Seek(0, System.IO.SeekOrigin.Begin);
                bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
                break;
            }
        }
    }
    catch { return null; }
    return bmpPngExtracted;
}

重要!このアイコンを EXE ファイルから直接ロードする場合は、Icon.ExtractAssociatedIcon(Application.ExecutablePath)をパラメーターとして使用することはできません。.NET関数 ExtractAssociatedIcon() は非常に馬鹿げているため、32x32 アイコンしか抽出できません!

代わりに、 Tsuda Kageyu ( http://www.codeproject.com/KB/cs/IconExtractor.aspx ) によって作成されたIconExtractorクラス全体を使用することをお勧めします。このクラスを少し単純化して、小さくすることができます。IconExtractorを次のように使用します。

// Getting FILL icon set from EXE, and extracting 256x256 version for logo...
using (TKageyu.Utils.IconExtractor IconEx = new TKageyu.Utils.IconExtractor(Application.ExecutablePath))
{
    Icon icoAppIcon = IconEx.GetIcon(0); // Because standard System.Drawing.Icon.ExtractAssociatedIcon() returns ONLY 32x32.
    picboxAppLogo.Image = ExtractVistaIcon(icoAppIcon);
}

注: ここでも ExtractVistaIcon() 関数を使用しています。IconExtractorがこのジョブを処理する方法が気に入らないためです。まず、IconExtractor.SplitIcon(icoAppIcon) を使用してすべてのアイコン形式を抽出し、次に正確な目的のビスタ アイコンを取得するための 256x256 アイコン インデックス。したがって、ここで ExtractVistaIcon() を使用すると、はるかに高速で簡単な方法になります:)

于 2009-12-22T11:18:42.873 に答える
3

ここで情報を見つけました。大きな Vista アイコンを取得するには、Shell32 の SHGetFileInfo メソッドを使用する必要があります。関連するテキストを以下にコピーしました。もちろん、ファイル名変数を「Assembly.GetExecutingAssembly().Location」に置き換えます。

using System.Runtime.InteropServices;

取得するアイコンのサイズを指定するために SHGetFileInfo() の呼び出しで使用する一連の定数:

// Constants that we need in the function call
private const int SHGFI_ICON = 0x100;
private const int SHGFI_SMALLICON = 0x1;
private const int SHGFI_LARGEICON = 0x0;

SHFILEINFO 構造体は、グラフィック アイコンを含むさまざまなファイル情報へのハンドルとなるため、非常に重要です。

// This structure will contain information about the file
public struct SHFILEINFO
{
    // Handle to the icon representing the file
    public IntPtr hIcon;
    // Index of the icon within the image list
    public int iIcon;
    // Various attributes of the file
    public uint dwAttributes;
    // Path to the file
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string szDisplayName;
    // File type
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
    public string szTypeName;
};

アンマネージ コードの最終的な準備は、一般的な Shell32.dll 内にある SHGetFileInfo の署名を定義することです。

// The signature of SHGetFileInfo (located in Shell32.dll)
[DllImport("Shell32.dll")]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, uint uFlags);

すべての準備が整ったので、関数を呼び出して、取得したアイコンを表示します。取得されるオブジェクトは Icon タイプ (System.Drawing.Icon) ですが、PictureBox に表示したいので、ToBitmap() メソッドを使用して Icon を Bitmap に変換します。

しかし、まず、フォームに追加する必要がある 3 つのコントロールがあります。Text プロパティに "Extract Icon" を持つ Button btnExtract、PictureBox である picIconSmall、および PictureBox でもある picIconLarge です。これは、2 つのアイコン サイズを取得するためです。Visual Studio のデザイン ビューで btnExtract をダブルクリックすると、その Click イベントが表示されます。その中には残りのコードがあります:

private void btnExtract_Click(object sender, EventArgs e)
{
    // Will store a handle to the small icon
    IntPtr hImgSmall;
    // Will store a handle to the large icon
    IntPtr hImgLarge;

    SHFILEINFO shinfo = new SHFILEINFO();

    // Open the file that we wish to extract the icon from
    if(openFile.ShowDialog() == DialogResult.OK)
    {
        // Store the file name
        string FileName = openFile.FileName;
        // Sore the icon in this myIcon object
        System.Drawing.Icon myIcon;

        // Get a handle to the small icon
        hImgSmall = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_SMALLICON);
        // Get the small icon from the handle
        myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
        // Display the small icon
        picIconSmall.Image = myIcon.ToBitmap();

        // Get a handle to the large icon
        hImgLarge = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON);
        // Get the large icon from the handle
        myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
        // Display the large icon
        picIconLarge.Image = myIcon.ToBitmap();

    }
}

更新:ここでさらに詳しい情報を見つけました。

于 2008-10-21T01:19:10.970 に答える
2

ICOファイルの256*256 * 32画像を画像ボックスに表示するのと同じ問題があり、SAL80のソリューションが最も効率的である(そしてほとんど機能している)ことがわかりました。ただし、元のコードはBMPとして保存された画像をサポートしていません(大きなアイコンは通常PNGですが、常にではありません...)。

これが将来の参考のために私のバージョンです。ビットマップを作成するコードも少し単純です:

    /// <summary>
    /// Extracts  the large Vista icon from a ICO file 
    /// </summary>
    /// <param name="srcBuf">Bytes of the ICO file</param>
    /// <returns>The large icon or null if not found</returns>
    private static Bitmap ExtractVistaIcon(byte[] srcBuf)
    {
        const int SizeIcondir = 6;
        const int SizeIcondirentry = 16;

        // Read image count from ICO header
        int iCount = BitConverter.ToInt16(srcBuf, 4);

        // Search for a large icon
        for (int iIndex = 0; iIndex < iCount; iIndex++)
        {
            // Read image information from image directory entry
            int iWidth = srcBuf[SizeIcondir + SizeIcondirentry * iIndex];
            int iHeight = srcBuf[SizeIcondir + SizeIcondirentry * iIndex + 1];
            int iBitCount = BitConverter.ToInt16(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 6);

            // If Vista icon
            if (iWidth == 0 && iHeight == 0 && iBitCount == 32)
            {
                // Get image data position and length from directory
                int iImageSize = BitConverter.ToInt32(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 8);
                int iImageOffset = BitConverter.ToInt32(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 12);

                // Check if the image has a PNG signature
                if (srcBuf[iImageOffset] == 0x89 && srcBuf[iImageOffset+1] == 0x50 && srcBuf[iImageOffset+2] == 0x4E && srcBuf[iImageOffset+3] == 0x47)
                {
                    // the PNG data is stored directly in the file
                    var x = new MemoryStream(srcBuf, iImageOffset, iImageSize, false, false);
                    return new Bitmap(x); 
                }

                // Else it's bitmap data with a partial bitmap header
                // Read size from partial header
                int w = BitConverter.ToInt32(srcBuf, iImageOffset + 4);
                // Create a full header
                var b = new Bitmap(w, w, PixelFormat.Format32bppArgb);
                // Copy bits into bitmap
                BitmapData bmpData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.WriteOnly, b.PixelFormat);
                Marshal.Copy(srcBuf, iImageOffset + Marshal.SizeOf(typeof(Bitmapinfoheader)), bmpData.Scan0, b.Width*b.Height*4);
                b.UnlockBits(bmpData);
                return b;
            }
        }

        return null;
    }
于 2012-02-01T15:54:34.283 に答える
2

上記の回答はどれもVistaアイコンを処理しません-小さい(32x32)と大きい(48x48)のみ

Vista アイコンを扱うライブラリはこちら

...デュアル png アルファ チャネル形式のため、かなり複雑に見えます。

vb .net で簡潔な回答を作成しようとしますが、時間がかかる場合があります。

于 2008-10-21T03:26:00.123 に答える
0

利用可能なWindowsアイコン機能をご覧ください。さまざまなアイコン サイズのクエリについて言及している概要もあります。C# で API を使用するためのDream.In.Codeフォーラム スレッドとPinvoke.net リファレンスがあります。

于 2008-10-21T02:17:44.050 に答える