首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C++ 實現圖標資源提取與保存工具:從 EXE/DLL/ICO/BMP 多格式解析到 ICO/BMP 導出

     編輯:關於C語言

前言

在 Windows 開發中,經常需要從可執行文件、動態鏈接庫、圖標庫中提取圖標資源並保存為通用格式。本文基於 MFC 實現一個完整的圖標提取工具,封裝 CIcons 與 CDib 兩大核心類,支持從 .exe、.dll、.icl、.ico、.bmp 多種源格式提取圖標,並導出為 .ico 或 .bmp 文件。

圖 1 程序運行界面

一、核心類架構設計

1.1 文件組織

  • Icons.h / Icons.cpp:CIcons 類,負責圖標資源讀取、格式轉換、ICO 文件寫入
  • Dib.h / Dib.cpp:CDib 類,負責設備無關位圖(DIB)操作、BMP 文件讀寫

將四個文件加入項目即可直接調用,極易集成。

1.2 CIcons 核心接口

class CIcons {
public:
    // 從各類源讀取圖標資源
    LPICONRESOURCE ReadIconFromICOFile(LPCTSTR szFileName);
    LPICONRESOURCE ReadIconFromEXEFile(LPCTSTR szFileName, LPCTSTR szIconID);
    BOOL IconImageFromBMPFile(LPCTSTR szFileName, LPICONIMAGE pIconImage, BOOL bStretch);
    
    // 圖標創建與轉換
    HICON MakeIconFromResource(LPICONIMAGE pIconImage);
    HICON GetIconFromInstance(HINSTANCE hInst, LPCTSTR szIconID);
    
    // 導出文件
    BOOL WriteIconToICOFile(LPICONRESOURCE pIconRes, LPCTSTR szFileName);
    BOOL IconImageToBMPFile(LPCTSTR szFileName, LPICONIMAGE pIconImage);
    
    // 緩衝區管理
    void IconBuffer(LPICONIMAGE pIconImage, DWORD dwSize);
};

二、關鍵功能實現詳解

2.1 統一文件打開與資源枚舉


void CIconSnapDlg::OnOK() {
    // 1. 文件對話框選擇源文件
    CFileDialog fileDialog(TRUE, _T("*.ICO"), NULL, 0,
        _T("資源文件(*.ICO,*.BMP,*.EXE,*.DLL,*.ICL)|*.ICO;*.BMP;*.EXE;*.DLL;*.ICL||"));
    
    if (fileDialog.DoModal() != IDOK) return;
    
    CString szOpenFileName = fileDialog.GetPathName();
    CString szExt = fileDialog.GetFileExt(); szExt.MakeLower();
    
    // 2. 清空列表
    m_List.ResetContent();
    
    // 3. 根據擴展名分發處理
    if (szExt == _T("ico")) {
        LoadICOFile(szOpenFileName);
    } else if (szExt == _T("bmp")) {
        LoadBMPFile(szOpenFileName);
    } else { // exe, dll, icl
        LoadModuleResources(szOpenFileName);
    }
    
    // 4. 更新 UI 狀態
    m_List.SetCurSel(0);
    UpdateButtonsState();
    InvalidateRect(NULL, TRUE); // 觸發重繪
}

2.2 ICO 文件直接加載


void CIconSnapDlg::LoadICOFile(LPCTSTR szFileName) {
    LPICONRESOURCE lpIR = pIcons->ReadIconFromICOFile(szFileName);
    HICON hIcon = ExtractIcon(AfxGetInstanceHandle(), szFileName, 0);
    if (hIcon) {
        m_List.AddString(szFileName);
        m_List.SetItemData(0, (DWORD_PTR)szFileName); // 存儲標識
        CStatic* pStatic = (CStatic*)GetDlgItem(IDC_ICONS);
        pStatic->SetIcon(hIcon);
    }
}

2.3 BMP 文件轉圖標顯示


void CIconSnapDlg::LoadBMPFile(LPCTSTR szFileName) {
    ICONRESOURCE ir;
    pIcons->IconImageFromBMPFile(szFileName, &ir.IconImages[0], TRUE);
    HICON hIcon = pIcons->MakeIconFromResource(&ir.IconImages[0]);
    if (hIcon) {
        m_List.AddString(szFileName);
        m_List.SetItemData(0, (DWORD_PTR)szFileName);
        CStatic* pStatic = (CStatic*)GetDlgItem(IDC_ICONS);
        pStatic->SetIcon(hIcon);
    }
}

2.4 EXE/DLL/ICL 模塊資源枚舉(核心難點)


void CIconSnapDlg::LoadModuleResources(LPCTSTR szFileName) {
    // 1. 作為數據文件加載模塊(不執行代碼,安全)
    HINSTANCE hLib = LoadLibraryEx(szFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
    if (!hLib) {
        AfxMessageBox(_T("文件載入錯誤,必須是 Win32 文件!"));
        return;
    }
    
    EDII.szFileName = szOpenFileName;
    EDII.hInstance = hLib;
    
    // 2. 枚舉 RT_GROUP_ICON 資源
    if (!EnumResourceNames(hLib, RT_GROUP_ICON, 
        (ENUMRESNAMEPROC)MyEnumProc, (LPARAM)GetSafeHwnd())) {
        AfxMessageBox(_T("枚舉圖標資源失敗!"));
        FreeLibrary(hLib);
        return;
    }
    // 枚舉回調中將資源名稱添加到列表並關聯 ItemData
}

枚舉回調函數:


BOOL CALLBACK MyEnumProc(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam) {
    HWND hWnd = (HWND)lParam;
    CIconSnapDlg* pDlg = (CIconSnapDlg*)CWnd::FromHandle(hWnd);
    if (pDlg) {
        int nIndex = pDlg->m_List.AddString(lpszName);
        pDlg->m_List.SetItemData(nIndex, (DWORD_PTR)lpszName); // 關鍵:存儲資源名指針
    }
    return TRUE; // 繼續枚舉
}

2.5 列表選中項實時顯示(OnPaint 繪製)


void CIconSnapDlg::OnPaint() {
    CPaintDC dc(this);
    LPTSTR lpIconID = (LPTSTR)m_List.GetItemData(m_List.GetCurSel());
    if (lpIconID == (LPTSTR)LB_ERR) return;
    
    CString szExt = szOpenFileExtName; // 之前保存的擴展名
    if (szExt == _T("exe") || szExt == _T("dll") || szExt == _T("icl")) {
        HICON hIcon = pIcons->GetIconFromInstance(EDII.hInstance, lpIconID);
        CStatic* pStatic = (CStatic*)GetDlgItem(IDC_ICONS);
        pStatic->SetIcon(hIcon); // 靜態圖片控件顯示
    }
    // ICO/BMP 已在加載時顯示
}

三、圖標資源保存導出實現

3.1 統一保存入口


void CIconSnapDlg::OnButtonSaveas() {
    CFileDialog dlg(FALSE, _T("*.ICO"), NULL, 0,
        _T("圖標文件(*.ICO)|*.ICO|位圖文件(*.BMP)|*.BMP||"));
    if (dlg.DoModal() != IDOK) return;
    
    CString szSavePath = dlg.GetPathName();
    CString szSaveExt = dlg.GetFileExt(); szSaveExt.MakeLower();
    
    LPTSTR lpIconID = (LPTSTR)m_List.GetItemData(m_List.GetCurSel());
    if (lpIconID == (LPTSTR)LB_ERR) return;
    
    LPICONRESOURCE lpIR = NULL;
    
    // 如果源是模塊文件,需重新讀取選中資源
    if (szOpenFileExtName == _T("exe") || szOpenFileExtName == _T("dll") || szOpenFileExtName == _T("icl")) {
        lpIR = pIcons->ReadIconFromEXEFile(szOpenFileName, lpIconID);
    }
    // ICO/BMP 源已在加載時獲取 lpIR
    
    if (!lpIR || m_List.GetCount() == 0) {
        AfxMessageBox(_T("無可保存的圖標資源!"));
        return;
    }
    
    BeginWaitCursor();
    BOOL success = FALSE;
    if (szSaveExt == _T("bmp")) {
        success = pIcons->IconImageToBMPFile(szSavePath, &lpIR->IconImages[0]);
    } else if (szSaveExt == _T("ico")) {
        success = pIcons->WriteIconToICOFile(lpIR, szSavePath);
    }
    EndWaitCursor();
    
    if (!success) AfxMessageBox(_T("保存失敗!"));
}

3.2 ICO 文件結構寫入細節

WriteIconToICOFile 內部實現:

  1. 構建 ICONDIR 頭部(保留字、類型=1、圖標數量)
  2. 為每個圖標圖像構建 ICONDIRENTRY(寬、高、顏色數、保留、平面數、位深、數據大小、文件偏移)
  3. 寫入圖標數據(BMP 格式,含 BITMAPINFOHEADER + 色表 + 像素數據 + AND 掩碼)
  4. 計算並修正文件偏移量

3.3 BMP 導出實現

IconImageToBMPFile 將 ICONIMAGE 轉換為標準 DIB 格式寫入,處理顏色表、行字節對齊(4 字節倍數)、底-up 順序等細節。

四、關鍵技術難點與解決方案

難點解決方案
EXE/DLL 安全加載LoadLibraryEx(..., LOAD_LIBRARY_AS_DATAFILE) 僅映射資源節,不執行入口點代碼
資源枚舉回調上下文傳遞EnumResourceNames 的 lParam 傳遞 HWND,回調中 CWnd::FromHandle 獲取對話框指針
列表項關聯資源標識SetItemData 存儲資源名指針(LPTSTR),GetItemData 取回
多格式統一內部表示ICONRESOURCE 結構封裝多個 ICONIMAGE,屏蔽源格式差異
大圖標縮放顯示IconImageFromBMPFile 參數 bStretch=TRUE 啟用拉伸
內存管理GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE) + GlobalLock/Unlock/Free 管理緩衝區

五、擴展建議

  • 支持 PNG 格式圖標(Vista+ 支持),需解析 PNG 塊並轉換
  • 添加 圖標預覽縮略圖 列表視圖(CListCtrl + CImageList)
  • 支持 批量導出 模塊中所有圖標
  • 集成 圖標編輯功能(像素編輯、透明度調整、尺寸調整)
  • 支持 高 DPI 感知,正確顯示 256x256 高清圖標

六、總結

通過封裝 CIcons/CDib 核心類,實現了從 EXE/DLL/ICL/ICO/BMP 多源格式提取圖標資源,並導出為 ICO/BMP 通用格式的完整工具。關鍵技術點包括:安全模塊加載、資源枚舉回調、列表項數據關聯、多格式統一內部表示、ICO/BMP 文件結構精確讀寫。該設計模塊化程度高,四個文件即可集成到任意 MFC 專案,極大降低了圖標資源處理的開發門檻。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved