C/C++ Windows API——将文件图标保存为PNG

// FileInfoDemo.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <shellapi.h>//SHGetFileInfo
#include <ShObjIdl.h>//IShellFolder::GetAttributesOf
#include <gdiplus.h>

#pragma comment(lib, "gdiplus.lib")

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
    UINT num = 0, size = 0;

    Gdiplus::GetImageEncodersSize(&num, &size);
    if (size == 0)
        return -1;  // Failure

    Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));

    Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);
    bool found = false;
    for (UINT ix = 0; !found && ix < num; ++ix)
    {
        if (_wcsicmp(pImageCodecInfo[ix].MimeType, format) == 0)
        {
            *pClsid = pImageCodecInfo[ix].Clsid;
            found = true;
            break;
        }
    }

    free(pImageCodecInfo);
    return found;
}

//根据图标HICON保存图片为Png图片
bool SaveHIconToPngFile(HICON hIcon, LPCTSTR lpszPicFileName)
{
    if (hIcon == NULL)
    {
        return false;
    }

    ICONINFO icInfo = { 0 };
    if (!::GetIconInfo(hIcon, &icInfo))
    {
        return false;
    }

    BITMAP bitmap;
    GetObject(icInfo.hbmColor, sizeof(BITMAP), &bitmap);

    Gdiplus::Bitmap* pBitmap = NULL;
    Gdiplus::Bitmap* pWrapBitmap = NULL;

    do
    {
        if (bitmap.bmBitsPixel != 32)
        {
            pBitmap = Gdiplus::Bitmap::FromHICON(hIcon);
        }
        else
        {
            pWrapBitmap = Gdiplus::Bitmap::FromHBITMAP(icInfo.hbmColor, NULL);
            if (!pWrapBitmap)
                break;

            Gdiplus::BitmapData bitmapData;
            Gdiplus::Rect rcImage(0, 0, pWrapBitmap->GetWidth(), pWrapBitmap->GetHeight());

            pWrapBitmap->LockBits(&rcImage, Gdiplus::ImageLockModeRead, pWrapBitmap->GetPixelFormat(), &bitmapData);
            pBitmap = new (Gdiplus::Bitmap)(bitmapData.Width, bitmapData.Height, bitmapData.Stride, PixelFormat32bppARGB, (BYTE*)bitmapData.Scan0);
            pWrapBitmap->UnlockBits(&bitmapData);
        }

        CLSID encoderCLSID;
        GetEncoderClsid(_T("image/png"), &encoderCLSID);
        Gdiplus::Status st = pBitmap->Save(lpszPicFileName, &encoderCLSID, NULL);
        if (st != Gdiplus::Ok)
            break;

    } while (false);

    delete pBitmap;
    if (pWrapBitmap)
        delete pWrapBitmap;
    DeleteObject(icInfo.hbmColor);
    DeleteObject(icInfo.hbmMask);

    return true;
}

int main()
{
    TCHAR *filePath = L"C:\\Users\\chenjia2014\\Desktop\\ReplDemo2.exe";
    TCHAR *imagePath = L"C:\\Users\\chenjia2014\\Desktop\\test_img.png";
    SHFILEINFO shFileInfo = { 0 };
    BOOL ret;
    CoInitialize(NULL);

    /*
    WINSHELLAPI DWORD WINAPI SHGetFileInfo (
        LPCWSTR pszPath,        //指定文件名,当uFlags的取值中不包含 SHGFI_PIDL时,可直接指定;当uFlags的取值中包含 SHGFI_PIDL时pszPath要通过计算获得,不能直接指定;
        DWORD dwFileAttributes, //文件属性,仅当uFlags的取值中包含SHGFI_USEFILEATTRIBUTES时有效,一般不用此参数;
        SHFILEINFOW *psfi,      //返回获得的文件信息,是一个记录类型
        UINT cbFileInfo,        //psfi的比特值
        UINT uFlags             //指明需要返回的文件信息标识符
    );
    函数SHGetFileInfo()的返回值也随uFlags的取值变化而有所不同。SHGetFileInfo()不能获得“我的电脑”等虚似文件夹的信息。
    在调用SHGetFileInfo()之前,必须使用 CoInitialize 或者OleInitialize 初始化COM,否则表面上能够使用,但是会造成不安全或者丧失部分功能。

    typedef struct _SHFILEINFOW {
        HICON       hIcon;                      // out: icon
        int         iIcon;                      // out: icon index
        DWORD       dwAttributes;               // out: SFGAO_ flags
        WCHAR       szDisplayName[MAX_PATH];    // out: display name (or path)
        WCHAR       szTypeName[80];             // out: type name
    } SHFILEINFOW;

    #define SHGFI_ICON              0x000000100     // get icon
    #define SHGFI_DISPLAYNAME       0x000000200     // get display name
    #define SHGFI_TYPENAME          0x000000400     // get type name
    #define SHGFI_ATTRIBUTES        0x000000800     // get attributes
    #define SHGFI_ICONLOCATION      0x000001000     // get icon location
    #define SHGFI_EXETYPE           0x000002000     // return exe type
    #define SHGFI_SYSICONINDEX      0x000004000     // get system icon index
    #define SHGFI_LINKOVERLAY       0x000008000     // put a link overlay on icon
    #define SHGFI_SELECTED          0x000010000     // show icon in selected state
    #if (NTDDI_VERSION >= NTDDI_WIN2K)
    #define SHGFI_ATTR_SPECIFIED    0x000020000     // get only specified attributes
    #endif // (NTDDI_VERSION >= NTDDI_WIN2K)
    #define SHGFI_LARGEICON         0x000000000     // get large icon
    #define SHGFI_SMALLICON         0x000000001     // get small icon
    #define SHGFI_OPENICON          0x000000002     // get open icon
    #define SHGFI_SHELLICONSIZE     0x000000004     // get shell size icon
    #define SHGFI_PIDL              0x000000008     // pszPath is a pidl
    #define SHGFI_USEFILEATTRIBUTES 0x000000010     // use passed dwFileAttribute

    #define SHGFI_ADDOVERLAYS       0x000000020     // apply the appropriate overlays
    #define SHGFI_OVERLAYINDEX      0x000000040     // Get the index of the overlay
    // in the upper 8 bits of the iIcon
    */
    ret = SHGetFileInfo(filePath, 0, &shFileInfo, sizeof(shFileInfo), SHGFI_DISPLAYNAME | SHGFI_TYPENAME | SHGFI_ATTRIBUTES);
    printf("SHGetFileInfo -> %d\n", ret);
    printf("szDisplayName = %ls, szTypeName = %ls\n", shFileInfo.szDisplayName, shFileInfo.szTypeName);
    printf("attribute = %d\n", shFileInfo.dwAttributes);

    ret = SHGetFileInfo(filePath, 0, &shFileInfo, sizeof(shFileInfo),  SHGFI_ICON | SHGFI_SYSICONINDEX);
    printf("SHGetFileInfo -> %d\n", ret);
    printf("shFileInfo.hIcon = 0x%x, shFileInfo.iIcon = %d\n", shFileInfo.hIcon, shFileInfo.iIcon);

    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    /*
    初始化GDI+函数库,否则无法生成图片
    extern "C" Status WINAPI GdiplusStartup(
        OUT ULONG_PTR *token,               //用于接受GDI+的TOKEN.TOKEN可以暂时理解成一个句柄,就像窗口的句柄类似。
        const GdiplusStartupInput *input,
        OUT GdiplusStartupOutput *output
    );

    struct GdiplusStartupInput {
        UINT32 GdiplusVersion;             // Must be 1  (or 2 for the Ex version)
        DebugEventProc DebugEventCallback; // Ignored on free builds
        BOOL SuppressBackgroundThread;     // FALSE unless you're prepared to call
        // the hook/unhook functions properly
        BOOL SuppressExternalCodecs;       // FALSE unless you want GDI+ only to use
        // its internal image codecs.

        GdiplusStartupInput(
            DebugEventProc debugEventCallback = NULL,
            BOOL suppressBackgroundThread = FALSE,
            BOOL suppressExternalCodecs = FALSE)
        {
            GdiplusVersion = 1;
            DebugEventCallback = debugEventCallback;
            SuppressBackgroundThread = suppressBackgroundThread;
            SuppressExternalCodecs = suppressExternalCodecs;
        }
    };
    */
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    ret = SaveHIconToPngFile(shFileInfo.hIcon, imagePath);
    printf("SaveHIconToPngFile -> %d\n", ret);

    //这个函数在结束GDI+编程后调用,起作用是释放GDI+的资源
    Gdiplus::GdiplusShutdown(gdiplusToken);

    //销毁一个图标并且释放该图标所占用的内存
    DestroyIcon(shFileInfo.hIcon);

    CoUninitialize();

    system("pause");
    return 0;
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值