2011年6月13日星期一

(C#)匯出系統檔案類型中的超大圖示(二)

因為專案開發的需要,需要轉存檔案圖示經過處理後產生專案所需要的圖示,但是使用SHGetFileInfo()或ExtractIconEx()等方法轉存出來的圖示最大也只有32 x 32,感覺不是很滿意,因為微軟系統自Vista以後就支援超大圖示,為什麼無法得到超大圖示,於是上網搜尋研究了一下,發現很多人遇到一樣的問題,下面這篇討論似乎可以得到一些線索:

http://stackoverflow.com/questions/220465/using-256-x-256-vista-icon-in-application

但是我用了上面的程式碼匯出圖示發現依然不是超大圖示,後來由下面這篇文章中的工具發現shell32.dll中的圖示最大也只有48 x 48,如果能會出256 x 256的超大圖示那就見鬼了。

http://www.codeproject.com/KB/cs/IconLib.aspx

所以繼續發揮google搜尋的強大功能,由下面這篇文章又知道了原來在登錄資料庫(Registry)中對每一種檔案類型都有預設的圖示(DefaultIcon)。

http://www.codeproject.com/KB/cs/IconExtractor.aspx

由上面的專業文章就知道,如果我要匯出特定檔案類型的超大圖示,必須先由登錄資料庫中查詢到檔案類型預設圖示所參照的DLL和其在DLL中的位置(index)。

string regIconString = null;
string systemDirectory = Environment.SystemDirectory + "\\";
string regFileType = null;
if (fileType[0] == '.')
{
try
{
regFileType = Registry.ClassesRoot.OpenSubKey(fileType, false).GetValue("
").ToString();
if (regFileType != null)
{
regIconString = Registry.ClassesRoot.OpenSubKey(regFileType +
@"
\DefaultIcon", false).GetValue("").ToString();
}
}
catch
{
regIconString = null;
}

if (regIconString == null)
{
regIconString = systemDirectory + "
imageres.dll,0";
}
}
else
{
regIconString = systemDirectory + "
imageres.dll,3";
}
label1.Text = regIconString;
string[] fileIcon = regIconString.Split(new char[] { ',' });
if (fileIcon.Length != 2)
{
fileIcon = new string[] { systemDirectory + "
imageres.dll", "2" };
}



找到正確的DLL,就可以透過IconExtractor將圖示取出,此時取出的圖示其實是一個Icon的陣列,裏面包含不同size和解析度的圖示,這時再利用下面的方法就可以轉存超大圖示

public void ExtractExtraSizeIcon(Icon icoIcon)
{
Bitmap bmpPngExtracted = null;
try
{
byte[] srcBuf = null;
using (MemoryStream stream = new 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);
MemoryStream destStream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(destStream);
writer.Write(srcBuf, iImageOffset, iImageSize);
destStream.Seek(0, SeekOrigin.Begin);
bmpPngExtracted = new Bitmap(destStream);
break;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
string fileName = saveFileDialog1.FileName;

bmpPngExtracted.Save(fileName,ImageFormat.Icon);
}

下面是我測試的專案,可以得到256 x 256的超到圖示


2011-06-14_110945


範例下載

沒有留言:

張貼留言