Skip to content
This repository has been archived by the owner on Jan 9, 2023. It is now read-only.

Commit

Permalink
save icons correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
zodiacon committed May 19, 2022
1 parent 6d4e59e commit f061391
Show file tree
Hide file tree
Showing 14 changed files with 234 additions and 17 deletions.
14 changes: 14 additions & 0 deletions TotalPE.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TotalPE", "TotalPE\TotalPE.
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "enma_pe", "enma_pe\enma_pe.vcxproj", "{5B0E07A2-6928-44E0-AF0A-445B067C71CC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WTLHelper", "WTLHelper\WTLHelper.vcxproj", "{AE53419F-A769-4548-8E15-E311904DF7DF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
Expand Down Expand Up @@ -41,6 +43,18 @@ Global
{5B0E07A2-6928-44E0-AF0A-445B067C71CC}.Release|x64.Build.0 = Release|x64
{5B0E07A2-6928-44E0-AF0A-445B067C71CC}.Release|x86.ActiveCfg = Release|Win32
{5B0E07A2-6928-44E0-AF0A-445B067C71CC}.Release|x86.Build.0 = Release|Win32
{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|ARM64.ActiveCfg = Debug|ARM64
{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|ARM64.Build.0 = Debug|ARM64
{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x64.ActiveCfg = Debug|x64
{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x64.Build.0 = Debug|x64
{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x86.ActiveCfg = Debug|Win32
{AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x86.Build.0 = Debug|Win32
{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|ARM64.ActiveCfg = Release|ARM64
{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|ARM64.Build.0 = Release|ARM64
{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x64.ActiveCfg = Release|x64
{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x64.Build.0 = Release|x64
{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x86.ActiveCfg = Release|Win32
{AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
44 changes: 41 additions & 3 deletions TotalPE/IconGroupView.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "pch.h"
#include "resource.h"
#include "IconGroupView.h"
#include "ResourceHelper.h"
#include "IconWriter.h"

void CIconGroupView::SetGroupIconData(std::vector<uint8_t> const& data) {
#pragma pack(push, 1)
Expand Down Expand Up @@ -43,13 +45,13 @@ void CIconGroupView::SetGroupIconData(std::vector<uint8_t> const& data) {
auto& idata = it->Entry->get_data();
auto width = entry.bWidth ? entry.bWidth : 256;
icon.CreateIconFromResourceEx(const_cast<PBYTE>(idata.data()),
(DWORD)idata.size(), 0x30000, width, width, LR_DEFAULTCOLOR);
(DWORD)idata.size(), 0x30000, width, width);
if (icon) {
IconData id;
id.Icon = icon;
id.Size = width;
id.Id = entry.Id;
id.Colors = entry.bColorCount ? entry.bColorCount : (entry.wBitCount * entry.wPlanes);
id.Colors = entry.wBitCount * entry.wPlanes;
m_Icons.emplace_back(std::move(id));
y += width + 12;
}
Expand All @@ -60,7 +62,7 @@ void CIconGroupView::SetGroupIconData(std::vector<uint8_t> const& data) {

void CIconGroupView::SetIconData(std::vector<uint8_t> const& data, bool icon) {
m_IconSize = *(int*)(data.data() + sizeof(DWORD));
m_Icon.CreateIconFromResourceEx((PBYTE)data.data(), (DWORD)data.size(), 0x30000, m_IconSize, m_IconSize, LR_DEFAULTCOLOR);
m_Icon.CreateIconFromResourceEx((PBYTE)data.data(), (DWORD)data.size(), 0x30000, m_IconSize, m_IconSize);
SetScrollSize(500, 300);
}

Expand All @@ -69,6 +71,27 @@ LRESULT CIconGroupView::OnCreate(UINT, WPARAM, LPARAM, BOOL& handled) {
return 0;
}

LRESULT CIconGroupView::OnContextMenu(UINT, WPARAM, LPARAM lp, BOOL&) {
CPoint pt(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));
CPoint pt2(pt);
ScreenToClient(&pt);
CPoint offset;
GetScrollOffset(offset);
pt += offset;
int i = 0;
for (auto const& icon : m_Icons) {
if (icon.Rect.PtInRect(pt)) {
CMenu menu;
menu.LoadMenu(IDR_CONTEXT);
m_SelectedIcon = i;
Frame()->TrackPopupMenu(menu.GetSubMenu(3), 0, pt2.x, pt2.y);
break;
}
i++;
}
return 0;
}

LRESULT CIconGroupView::OnDestroy(UINT, WPARAM, LPARAM, BOOL&) {
if(m_Icon)
m_Icon.DestroyIcon();
Expand All @@ -84,6 +107,20 @@ LRESULT CIconGroupView::OnEraseBkgnd(UINT, WPARAM wp, LPARAM, BOOL&) {
return 0;
}

LRESULT CIconGroupView::OnExportIcon(WORD, WORD, HWND, BOOL&) {
ATLASSERT(m_SelectedIcon >= 0);
CSimpleFileDialog dlg(FALSE, L"ico", nullptr, OFN_EXPLORER | OFN_ENABLESIZING | OFN_OVERWRITEPROMPT,
L"Icon Files (*.ico)\0*.ico\0All Files\0*.*\0", m_hWnd);
if (IDOK == dlg.DoModal()) {
auto const& icon = m_Icons[m_SelectedIcon];
if (!IconWriter::Save(dlg.m_szFileName, icon.Icon.m_hIcon, icon.Colors)) {
AtlMessageBox(m_hWnd, L"Failed to save icon", IDS_TITLE, MB_ICONERROR);
}
}

return 0;
}

void CIconGroupView::DoPaint(CDCHandle dc) {
CFont font;
font.CreatePointFont(110, L"Consolas");
Expand All @@ -102,6 +139,7 @@ void CIconGroupView::DoPaint(CDCHandle dc) {
dc.DrawText(text.c_str(),
-1, &rc, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
icon.Icon.DrawIconEx(dc, 180, y, size, size, 0, nullptr, DI_NORMAL);
icon.Rect = CRect(180, y, 180 + size, y + size);
y += size + 12;
}
}
Expand Down
6 changes: 6 additions & 0 deletions TotalPE/IconGroupView.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class CIconGroupView :
void DoPaint(CDCHandle);

BEGIN_MSG_MAP(CIconGroupView)
MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
COMMAND_ID_HANDLER(ID_ICON_EXPORT, OnExportIcon)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
//MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
Expand All @@ -26,13 +28,17 @@ class CIconGroupView :
int Size;
UINT Id;
UINT Colors;
CRect Rect;
};
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
LRESULT OnContextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
LRESULT OnExportIcon(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);

CIconHandle m_Icon;
int m_IconSize;
std::vector<IconData> m_Icons;
int m_SelectedIcon{ -1 };
};

128 changes: 128 additions & 0 deletions TotalPE/IconWriter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#include "pch.h"
#include "IconWriter.h"

namespace {
struct ICONDIRENTRY {
BYTE nWidth;
BYTE nHeight;
BYTE nNumColorsInPalette; // 0 if no palette
BYTE nReserved; // should be 0
WORD nNumColorPlanes; // 0 or 1
WORD nBitsPerPixel;
ULONG nDataLength; // length in bytes
ULONG nOffset; // offset of BMP or PNG data from beginning of file
};

struct ICONHEADER {
WORD idReserved; // must be 0
WORD idType; // 1 = ICON, 2 = CURSOR
WORD idCount; // number of images
};
}

static bool GetIconData(HICON hIcon, int nColorBits, std::vector<std::byte>& buff, bool icon) {

// Write header
ICONHEADER icoHeader{ 0 };
icoHeader.idCount = 1;
icoHeader.idType = icon ? 1 : 2;
auto header = reinterpret_cast<std::byte*>(&icoHeader);
buff.insert(buff.end(), header, header + sizeof(icoHeader));

// Get information about icon
ICONINFO iconInfo;
::GetIconInfo(hIcon, &iconInfo);
BITMAPINFO bmInfo = { 0 };
bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmInfo.bmiHeader.biBitCount = 0; // don't get the color table
HDC dc = CreateCompatibleDC(nullptr);
if (!::GetDIBits(dc, iconInfo.hbmColor, 0, 0, nullptr, &bmInfo, DIB_RGB_COLORS)) {
return false;
}

// Allocate size of bitmap info header plus space for color table:
uint32_t nBmInfoSize = sizeof(BITMAPINFOHEADER);
if (nColorBits < 24) {
nBmInfoSize += (int)sizeof(RGBQUAD) * (1 << nColorBits);
}

std::vector<UCHAR> bitmapInfo;
bitmapInfo.resize(nBmInfoSize);
auto pBmInfo = (BITMAPINFO*)bitmapInfo.data();
memcpy(pBmInfo, &bmInfo, sizeof(BITMAPINFOHEADER));

// Get bitmap data:
if (!bmInfo.bmiHeader.biSizeImage)
return false;
std::vector<UCHAR> bits;
bits.resize(bmInfo.bmiHeader.biSizeImage);
pBmInfo->bmiHeader.biBitCount = (WORD)nColorBits;
pBmInfo->bmiHeader.biCompression = BI_RGB;
if (!::GetDIBits(dc, iconInfo.hbmColor, 0, bmInfo.bmiHeader.biHeight, bits.data(), pBmInfo, DIB_RGB_COLORS)) {
return false;
}

// Get mask data
BITMAPINFO maskInfo = { 0 };
maskInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
maskInfo.bmiHeader.biBitCount = 0; // don't get the color table
if (!::GetDIBits(dc, iconInfo.hbmMask, 0, 0, nullptr, &maskInfo, DIB_RGB_COLORS) || maskInfo.bmiHeader.biBitCount != 1)
return false;

std::vector<UCHAR> maskBits;
maskBits.resize(maskInfo.bmiHeader.biSizeImage);
std::vector<UCHAR> maskInfoBytes;
maskInfoBytes.resize(sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD));
auto pMaskInfo = (BITMAPINFO*)maskInfoBytes.data();
memcpy(pMaskInfo, &maskInfo, sizeof(maskInfo));
if (!::GetDIBits(dc, iconInfo.hbmMask, 0, maskInfo.bmiHeader.biHeight, maskBits.data(), pMaskInfo, DIB_RGB_COLORS)) {
return false;
}

// Write directory entry:
ICONDIRENTRY dir;
dir.nWidth = (UCHAR)pBmInfo->bmiHeader.biWidth;
dir.nHeight = (UCHAR)pBmInfo->bmiHeader.biHeight;
dir.nNumColorsInPalette = (nColorBits == 4 ? 16 : 0);
dir.nReserved = 0;
dir.nNumColorPlanes = 0;
dir.nBitsPerPixel = pBmInfo->bmiHeader.biBitCount;
dir.nDataLength = pBmInfo->bmiHeader.biSizeImage + pMaskInfo->bmiHeader.biSizeImage + nBmInfoSize;
dir.nOffset = sizeof(dir) + sizeof(icoHeader);
buff.insert(buff.end(), reinterpret_cast<std::byte*>(&dir), reinterpret_cast<std::byte*>(&dir) + sizeof(dir));

// Write DIB header (including color table):
int nBitsSize = pBmInfo->bmiHeader.biSizeImage;
pBmInfo->bmiHeader.biHeight *= 2; // because the header is for both image and mask
pBmInfo->bmiHeader.biCompression = 0;
pBmInfo->bmiHeader.biSizeImage += pMaskInfo->bmiHeader.biSizeImage; // because the header is for both image and mask
buff.insert(buff.end(), reinterpret_cast<std::byte*>(&pBmInfo->bmiHeader), reinterpret_cast<std::byte*>(&pBmInfo->bmiHeader) + nBmInfoSize);

// Write image data
buff.insert(buff.end(), reinterpret_cast<std::byte*>(bits.data()), reinterpret_cast<std::byte*>(bits.data()) + nBitsSize);

// Write mask data
buff.insert(buff.end(), reinterpret_cast<std::byte*>(maskBits.data()), reinterpret_cast<std::byte*>(maskBits.data()) + pMaskInfo->bmiHeader.biSizeImage);

::DeleteObject(iconInfo.hbmColor);
::DeleteObject(iconInfo.hbmMask);

::DeleteDC(dc);

return true;
}

bool IconWriter::Save(PCWSTR path, HICON const hIcon, int colors, bool icon) {
std::vector<std::byte> data;
if (!GetIconData(hIcon, colors, data, icon))
return false;

auto hFile = ::CreateFile(path, GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, 0, nullptr);
if (hFile == INVALID_HANDLE_VALUE)
return false;

DWORD bytes;
auto ok = ::WriteFile(hFile, data.data(), (DWORD)data.size(), &bytes, nullptr);
::CloseHandle(hFile);
return ok;
}
7 changes: 7 additions & 0 deletions TotalPE/IconWriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

struct IconWriter final abstract {
public:
static bool Save(PCWSTR path, HICON const hIcon, int colors, bool icon = true);
};

6 changes: 0 additions & 6 deletions TotalPE/MainFrm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,6 @@
#include "SecurityHelper.h"
#include "IconHelper.h"

#ifdef _DEBUG
#pragma comment(lib, "../WTLHelper/x64/Debug/WTLHelper.lib")
#else
#pragma comment(lib, "../WTLHelper/x64/Release/WTLHelper.lib")
#endif

CMainFrame::CMainFrame() : m_ViewMgr(this) {
}

Expand Down
14 changes: 11 additions & 3 deletions TotalPE/SectionsView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "SectionsView.h"
#include "PEStrings.h"
#include "SortHelper.h"
#include "resource.h"

CString CSectionsView::GetColumnText(HWND, int row, int col) const {
auto& section = m_Sections[row];
Expand Down Expand Up @@ -36,9 +37,19 @@ void CSectionsView::DoSort(SortInfo const* si) {
m_Sections.Sort(compare);
}

int CSectionsView::GetRowImage(HWND, int row, int col) const {
return 0;
}

LRESULT CSectionsView::OnCreate(UINT, WPARAM, LPARAM, BOOL&) {
m_hWndClient = m_List.Create(*this, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
LVS_REPORT | LVS_OWNERDATA, WS_EX_CLIENTEDGE);
m_List.SetExtendedListViewStyle(LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
CImageList images;
images.Create(16, 16, ILC_COLOR32 | ILC_MASK, 1, 1);
images.AddIcon(AtlLoadIconImage(IDI_SECTION, 0, 16, 16));
m_List.SetImageList(images, LVSIL_SMALL);

auto cm = GetColumnManager(m_List);

cm->AddColumn(L"Name", LVCFMT_LEFT, 90);
Expand All @@ -47,11 +58,8 @@ LRESULT CSectionsView::OnCreate(UINT, WPARAM, LPARAM, BOOL&) {
cm->AddColumn(L"Ptr to Raw Data", LVCFMT_RIGHT, 110);
cm->AddColumn(L"Raw Data Size", LVCFMT_RIGHT, 130);
cm->AddColumn(L"Characteristics", LVCFMT_LEFT, 300);

cm->UpdateColumns();

m_List.SetExtendedListViewStyle(LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);

BuildItems();

return 0;
Expand Down
1 change: 1 addition & 0 deletions TotalPE/SectionsView.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class CSectionsView :

CString GetColumnText(HWND, int row, int col) const;
void DoSort(SortInfo const* si);
int GetRowImage(HWND, int row, int col) const;

BEGIN_MSG_MAP(CSectionsView)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
Expand Down
4 changes: 4 additions & 0 deletions TotalPE/TotalPE.rc
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ BEGIN
BEGIN
MENUITEM "View &Assembly", ID_EXPORTS_VIEWASSEMBLY
END
POPUP "icon"
BEGIN
MENUITEM "Export...", ID_ICON_EXPORT
END
END


Expand Down
Loading

0 comments on commit f061391

Please sign in to comment.