none
VC获取文件超大图标 256x256 RRS feed

  • 问题

  • #include <shlobj.h>
    #include <shlguid.h>
    #include <shellapi.h>
    #include <commctrl.h>
    #include <commoncontrols.h>
    
    // Get the icon index using SHGetFileInfo
    SHFILEINFOW sfi = { 0 };
    SHGetFileInfo(filePath, -1, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX);
    
    // Retrieve the system image list.
    // To get the 48x48 icons, use SHIL_EXTRALARGE
    // To get the 256x256 icons (Vista only), use SHIL_JUMBO
    HIMAGELIST* imageList;
    HRESULT hResult = SHGetImageList(SHIL_EXTRALARGE, IID_IImageList, (void**)&imageList);
    
    if (hResult == S_OK) 
    {
    	// Get the icon we need from the list. Note that the HIMAGELIST we retrieved
    	// earlier needs to be casted to the IImageList interface before use.
    	HICON hIcon;
    	hResult = ((IImageList*)imageList)->GetIcon(sfi.iIcon, ILD_TRANSPARENT, &hIcon);
    
    	if (hResult == S_OK) 
    	{
    		// Do something with the icon here.
    	}
    }
    HRESULT hResult = SHGetImageList(SHIL_JUMBO, IID_IImageList, (void**)&imageList);

    上面是网上获取256图标的一个方法。将SHIL_EXTRALARGE改成SHIL_JUMBO即可。

    该方法好处是提交任何文件都可以。自动寻找关联的图标。

    但是如果文件没有256大小的图标,返回的是一个256x256的图像,但是图标部分会缩在左上角。比如256x256文件的左上角有一个48x48的图像,其余空白。

    -------

    求解:

    1、有没有办法修正缩在左上角的图像,将其居中并变回原有大小呢?或者直接放大到256x256?

    2、有没有办法在SHGetImageList前,判断文件拥有的图标大小?比如有没有256大小图标呢?这样就可以用其他flag了,比如SHIL_EXTRALARGE。

    3、PrivateExtractIcons这个API似乎能很好地工作,即使没有256大小的也会将48或32的放大到256,但是必须是exe、dll等文件。

    原本觉得可以配合SHGetFileInfo,用SHGFI_ICONLOCATION来获取图标的位置,可是这个flag似乎不能工作?

    ---------

    4、如果上面的都不能解决,打算用读取注册表的方法配合PrivateExtractIcons。

    根据我查找的资料,比如.bat,是在HKEY_CLASSES_ROOT找到.bat,然后获取名称是batfile。在寻找HKEY_CLASSES_ROOT\batfile\DefaultIcon下找到图标文件位置。

    ——可是有些文件,比如.sln,扩展名上的名称是VisualStudio.Launcher.sln,可是该项没有DefaultIcon,而是在VisualStudio.Launcher._sln下……

    ——还有似乎DefaultIcon只是默认的图标,而不一定是文件当前显示的图标(若有第三方软件改过关联)

    到底注册表中关联图标是怎么一个规则呢??

    ————谢谢各位~

    2014年4月17日 2:07

答案

  • 找到解决办法了!判断一下49-256像素是不是都是空白就行……

    这里我用的是GDI+,代码大概如下……

    bool IsIconOnly48(Bitmap* bmp)
    {
        bool is48 = true;
        Color color, checkColor(255, 0, 0, 0);
        for (int x = 49; x != 256; ++x)
        {
            for (int y = 49; y != 256; ++y)
            {
                bmp->GetPixel(x, y, &color);
                if (color.GetValue() != checkColor.GetValue())
                {
                    is48 = false;
                    break;
                }
            }
            if (is48 == false)
            {
                break;
            }
        }
        return is48;
    }
    
    void GetIcon()
    {
    	//……省略
    	//获取JUMBO后
    	HICON hIcon;
    	hResult = ((IImageList*)imageList)->GetIcon(SHFI.iIcon, ILD_TRANSPARENT, &hIcon);
    
    	if (hResult == S_OK)
    	{
    		ICONINFO ii = { 0 };
    		GetIconInfo(hIcon, &ii);
    		Bitmap bmpIcon(ii.hbmColor, NULL);//GDI+
    
    		if (IsIconOnly48(&bmpIcon))
    		{
    			hResult = SHGetImageList(SHIL_EXTRALARGE, IID_IImageList, (void**)&imageList);
    			//获得48X48
    		}
    	}
    }

    • 已标记为答案 raiwhiz 2014年4月19日 14:05
    2014年4月19日 14:04

全部回复

  • 能否得到图标HICON以后,自己利用DrawIconEx()指定大小位置贴图呢?即使获取的图标HICON不是256 * 256尺寸的。

    Visual C++ enthusiast, like network programming and driver development. At present is being engaged in the WinCE/Windows Mobile platform embedded development.

    2014年4月18日 10:03
    版主
  • 似乎指定了SHIL_JUMBO后,获取出来的HICON尺寸全部都是256*256的。

    只是没有256大小图标的,图像会在左上角。

    2014年4月18日 12:44
  • 找到解决办法了!判断一下49-256像素是不是都是空白就行……

    这里我用的是GDI+,代码大概如下……

    bool IsIconOnly48(Bitmap* bmp)
    {
        bool is48 = true;
        Color color, checkColor(255, 0, 0, 0);
        for (int x = 49; x != 256; ++x)
        {
            for (int y = 49; y != 256; ++y)
            {
                bmp->GetPixel(x, y, &color);
                if (color.GetValue() != checkColor.GetValue())
                {
                    is48 = false;
                    break;
                }
            }
            if (is48 == false)
            {
                break;
            }
        }
        return is48;
    }
    
    void GetIcon()
    {
    	//……省略
    	//获取JUMBO后
    	HICON hIcon;
    	hResult = ((IImageList*)imageList)->GetIcon(SHFI.iIcon, ILD_TRANSPARENT, &hIcon);
    
    	if (hResult == S_OK)
    	{
    		ICONINFO ii = { 0 };
    		GetIconInfo(hIcon, &ii);
    		Bitmap bmpIcon(ii.hbmColor, NULL);//GDI+
    
    		if (IsIconOnly48(&bmpIcon))
    		{
    			hResult = SHGetImageList(SHIL_EXTRALARGE, IID_IImageList, (void**)&imageList);
    			//获得48X48
    		}
    	}
    }

    • 已标记为答案 raiwhiz 2014年4月19日 14:05
    2014年4月19日 14:04
  • 你好:

    感谢你分享你的答案,这样可以帮助更多论坛上遇到同样问题的人。

    2014年4月22日 7:25
    版主