winemenubuilder: extract icons from NE binaries too (try 2)
Damjan Jovanovic
damjan.jov at gmail.com
Sun May 22 07:09:05 CDT 2011
Changelog:
* winemenubuilder: extract icons from NE binaries too
Try 2 manually parses the NE file instead of using krnl386.exe functions.
Damjan Jovanovic
-------------- next part --------------
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
index 5908e4e..2aa4b2a 100644
--- a/programs/winemenubuilder/winemenubuilder.c
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -147,6 +147,25 @@ typedef struct
WORD idCount;
} ICONDIR;
+typedef struct
+{
+ WORD offset;
+ WORD length;
+ WORD flags;
+ WORD id;
+ WORD handle;
+ WORD usage;
+} NE_NAMEINFO;
+
+typedef struct
+{
+ WORD type_id;
+ WORD count;
+ DWORD resloader;
+} NE_TYPEINFO;
+
+#define NE_RSCTYPE_ICON 0x8003
+#define NE_RSCTYPE_GROUP_ICON 0x800e
#include "poppack.h"
@@ -491,7 +510,99 @@ end:
return hr;
}
-static IStream *add_module_icons_to_stream(HMODULE hModule, GRPICONDIR *grpIconDir)
+struct IconData16 {
+ BYTE *fileBytes;
+ DWORD fileSize;
+ NE_TYPEINFO *iconResources;
+ WORD alignmentShiftCount;
+};
+
+static int populate_module16_icons(struct IconData16 *iconData16, GRPICONDIR *grpIconDir, ICONDIRENTRY *iconDirEntries, BYTE *icons, SIZE_T *iconOffset)
+{
+ int i, j;
+ int validEntries = 0;
+
+ for (i = 0; i < grpIconDir->idCount; i++)
+ {
+ BYTE *iconPtr = (BYTE*)iconData16->iconResources;
+ NE_NAMEINFO *matchingIcon = NULL;
+ iconPtr += sizeof(NE_TYPEINFO);
+ for (j = 0; j < iconData16->iconResources->count; j++)
+ {
+ NE_NAMEINFO *iconInfo = (NE_NAMEINFO*)iconPtr;
+ if ((((BYTE*)iconPtr) + sizeof(NE_NAMEINFO)) > (iconData16->fileBytes + iconData16->fileSize))
+ {
+ WINE_WARN("file too small for icon NE_NAMEINFO\n");
+ break;
+ }
+ if (iconInfo->id == (0x8000 | grpIconDir->idEntries[i].nID))
+ {
+ matchingIcon = iconInfo;
+ break;
+ }
+ iconPtr += sizeof(NE_NAMEINFO);
+ }
+
+ if (matchingIcon == NULL)
+ continue;
+ if (((matchingIcon->offset << iconData16->alignmentShiftCount) + grpIconDir->idEntries[i].dwBytesInRes) > iconData16->fileSize)
+ {
+ WINE_WARN("file too small for icon contents\n");
+ break;
+ }
+
+ iconDirEntries[validEntries].bWidth = grpIconDir->idEntries[i].bWidth;
+ iconDirEntries[validEntries].bHeight = grpIconDir->idEntries[i].bHeight;
+ iconDirEntries[validEntries].bColorCount = grpIconDir->idEntries[i].bColorCount;
+ iconDirEntries[validEntries].bReserved = grpIconDir->idEntries[i].bReserved;
+ iconDirEntries[validEntries].wPlanes = grpIconDir->idEntries[i].wPlanes;
+ iconDirEntries[validEntries].wBitCount = grpIconDir->idEntries[i].wBitCount;
+ iconDirEntries[validEntries].dwBytesInRes = grpIconDir->idEntries[i].dwBytesInRes;
+ iconDirEntries[validEntries].dwImageOffset = *iconOffset;
+ validEntries++;
+ memcpy(&icons[*iconOffset], &iconData16->fileBytes[matchingIcon->offset << iconData16->alignmentShiftCount], grpIconDir->idEntries[i].dwBytesInRes);
+ *iconOffset += grpIconDir->idEntries[i].dwBytesInRes;
+ }
+ return validEntries;
+}
+
+static int populate_module_icons(HMODULE hModule, GRPICONDIR *grpIconDir, ICONDIRENTRY *iconDirEntries, BYTE *icons, SIZE_T *iconOffset)
+{
+ int i;
+ int validEntries = 0;
+
+ for (i = 0; i < grpIconDir->idCount; i++)
+ {
+ HRSRC hResInfo;
+ LPCWSTR lpName = MAKEINTRESOURCEW(grpIconDir->idEntries[i].nID);
+ if ((hResInfo = FindResourceW(hModule, lpName, (LPCWSTR)RT_ICON)))
+ {
+ HGLOBAL hResData;
+ if ((hResData = LoadResource(hModule, hResInfo)))
+ {
+ BITMAPINFO *pIcon;
+ if ((pIcon = LockResource(hResData)))
+ {
+ iconDirEntries[validEntries].bWidth = grpIconDir->idEntries[i].bWidth;
+ iconDirEntries[validEntries].bHeight = grpIconDir->idEntries[i].bHeight;
+ iconDirEntries[validEntries].bColorCount = grpIconDir->idEntries[i].bColorCount;
+ iconDirEntries[validEntries].bReserved = grpIconDir->idEntries[i].bReserved;
+ iconDirEntries[validEntries].wPlanes = grpIconDir->idEntries[i].wPlanes;
+ iconDirEntries[validEntries].wBitCount = grpIconDir->idEntries[i].wBitCount;
+ iconDirEntries[validEntries].dwBytesInRes = grpIconDir->idEntries[i].dwBytesInRes;
+ iconDirEntries[validEntries].dwImageOffset = *iconOffset;
+ validEntries++;
+ memcpy(&icons[*iconOffset], pIcon, grpIconDir->idEntries[i].dwBytesInRes);
+ *iconOffset += grpIconDir->idEntries[i].dwBytesInRes;
+ }
+ FreeResource(hResData);
+ }
+ }
+ }
+ return validEntries;
+}
+
+static IStream *add_module_icons_to_stream(struct IconData16 *iconData16, HMODULE hModule, GRPICONDIR *grpIconDir)
{
int i;
SIZE_T iconsSize = 0;
@@ -529,34 +640,10 @@ static IStream *add_module_icons_to_stream(HMODULE hModule, GRPICONDIR *grpIconD
}
iconOffset = 0;
- for (i = 0; i < grpIconDir->idCount; i++)
- {
- HRSRC hResInfo;
- LPCWSTR lpName = MAKEINTRESOURCEW(grpIconDir->idEntries[i].nID);
- if ((hResInfo = FindResourceW(hModule, lpName, (LPCWSTR)RT_ICON)))
- {
- HGLOBAL hResData;
- if ((hResData = LoadResource(hModule, hResInfo)))
- {
- BITMAPINFO *pIcon;
- if ((pIcon = LockResource(hResData)))
- {
- iconDirEntries[validEntries].bWidth = grpIconDir->idEntries[i].bWidth;
- iconDirEntries[validEntries].bHeight = grpIconDir->idEntries[i].bHeight;
- iconDirEntries[validEntries].bColorCount = grpIconDir->idEntries[i].bColorCount;
- iconDirEntries[validEntries].bReserved = grpIconDir->idEntries[i].bReserved;
- iconDirEntries[validEntries].wPlanes = grpIconDir->idEntries[i].wPlanes;
- iconDirEntries[validEntries].wBitCount = grpIconDir->idEntries[i].wBitCount;
- iconDirEntries[validEntries].dwBytesInRes = grpIconDir->idEntries[i].dwBytesInRes;
- iconDirEntries[validEntries].dwImageOffset = iconOffset;
- validEntries++;
- memcpy(&icons[iconOffset], pIcon, grpIconDir->idEntries[i].dwBytesInRes);
- iconOffset += grpIconDir->idEntries[i].dwBytesInRes;
- }
- FreeResource(hResData);
- }
- }
- }
+ if (iconData16)
+ validEntries = populate_module16_icons(iconData16, grpIconDir, iconDirEntries, icons, &iconOffset);
+ else if (hModule)
+ validEntries = populate_module_icons(hModule, grpIconDir, iconDirEntries, icons, &iconOffset);
if (validEntries == 0)
{
@@ -601,6 +688,137 @@ end:
return stream;
}
+static HRESULT open_module16_icon(LPCWSTR szFileName, int nIndex, IStream **ppStream)
+{
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ HANDLE hFileMapping = NULL;
+ DWORD fileSize;
+ BYTE *fileBytes = NULL;
+ IMAGE_DOS_HEADER *dosHeader;
+ IMAGE_OS2_HEADER *neHeader;
+ BYTE *rsrcTab;
+ NE_TYPEINFO *iconGroupResources;
+ NE_TYPEINFO *iconResources;
+ NE_NAMEINFO *iconDirPtr;
+ GRPICONDIR *iconDir;
+ WORD alignmentShiftCount;
+ struct IconData16 iconData16;
+ HRESULT hr = E_FAIL;
+
+ hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ WINE_WARN("opening %s failed with error %d\n", wine_dbgstr_w(szFileName), GetLastError());
+ goto end;
+ }
+
+ hFileMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
+ if (hFileMapping == NULL)
+ {
+ WINE_WARN("CreateFileMapping failed, error %d\n", GetLastError());
+ goto end;
+ }
+
+ fileSize = GetFileSize(hFile, NULL);
+
+ fileBytes = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
+ if (fileBytes == NULL)
+ {
+ WINE_WARN("MapViewOfFile failed, error %d\n", GetLastError());
+ goto end;
+ }
+
+ dosHeader = (IMAGE_DOS_HEADER*)fileBytes;
+ if (sizeof(IMAGE_DOS_HEADER) >= fileSize || dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
+ {
+ WINE_WARN("file too small for MZ header\n");
+ goto end;
+ }
+
+ neHeader = (IMAGE_OS2_HEADER*)(fileBytes + dosHeader->e_lfanew);
+ if ((((BYTE*)neHeader) + sizeof(IMAGE_OS2_HEADER)) > (fileBytes + fileSize) ||
+ neHeader->ne_magic != IMAGE_OS2_SIGNATURE)
+ {
+ WINE_WARN("file too small for NE header\n");
+ goto end;
+ }
+
+ rsrcTab = ((BYTE*)neHeader) + neHeader->ne_rsrctab;
+ if ((rsrcTab + 2) > (fileBytes + fileSize))
+ {
+ WINE_WARN("file too small for resource table\n");
+ goto end;
+ }
+
+ alignmentShiftCount = *(WORD*)rsrcTab;
+ rsrcTab += 2;
+ iconGroupResources = NULL;
+ iconResources = NULL;
+ for (;;)
+ {
+ NE_TYPEINFO *neTypeInfo = (NE_TYPEINFO*)rsrcTab;
+ if ((rsrcTab + sizeof(NE_TYPEINFO)) > (fileBytes + fileSize))
+ {
+ WINE_WARN("file too small for resource table\n");
+ goto end;
+ }
+ if (neTypeInfo->type_id == 0)
+ break;
+ else if (neTypeInfo->type_id == NE_RSCTYPE_GROUP_ICON)
+ iconGroupResources = neTypeInfo;
+ else if (neTypeInfo->type_id == NE_RSCTYPE_ICON)
+ iconResources = neTypeInfo;
+ rsrcTab += sizeof(NE_TYPEINFO) + neTypeInfo->count*sizeof(NE_NAMEINFO);
+ }
+ if (iconGroupResources == NULL)
+ {
+ WINE_WARN("no group icon resource type found\n");
+ goto end;
+ }
+ if (iconResources == NULL)
+ {
+ WINE_WARN("no icon resource type found\n");
+ goto end;
+ }
+
+ if (nIndex >= iconGroupResources->count)
+ {
+ WINE_WARN("icon index out of range\n");
+ goto end;
+ }
+
+ iconDirPtr = (NE_NAMEINFO*)(((BYTE*)iconGroupResources) + sizeof(NE_TYPEINFO) + nIndex*sizeof(NE_NAMEINFO));
+ if ((((BYTE*)iconDirPtr) + sizeof(NE_NAMEINFO)) > (fileBytes + fileSize))
+ {
+ WINE_WARN("file to small for icon group NE_NAMEINFO\n");
+ goto end;
+ }
+ iconDir = (GRPICONDIR*)(fileBytes + (iconDirPtr->offset << alignmentShiftCount));
+ if ((((BYTE*)iconDir) + sizeof(GRPICONDIR) + iconDir->idCount*sizeof(GRPICONDIRENTRY)) > (fileBytes + fileSize))
+ {
+ WINE_WARN("file too small for GRPICONDIR\n");
+ goto end;
+ }
+
+ iconData16.fileBytes = fileBytes;
+ iconData16.fileSize = fileSize;
+ iconData16.iconResources = iconResources;
+ iconData16.alignmentShiftCount = alignmentShiftCount;
+ *ppStream = add_module_icons_to_stream(&iconData16, NULL, iconDir);
+ if (*ppStream)
+ hr = S_OK;
+
+end:
+ if (hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hFile);
+ if (hFileMapping != NULL)
+ CloseHandle(hFileMapping);
+ if (fileBytes != NULL)
+ UnmapViewOfFile(fileBytes);
+ return hr;
+}
+
static BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam)
{
ENUMRESSTRUCT *sEnumRes = (ENUMRESSTRUCT *) lParam;
@@ -626,9 +844,14 @@ static HRESULT open_module_icon(LPCWSTR szFileName, int nIndex, IStream **ppStre
hModule = LoadLibraryExW(szFileName, 0, LOAD_LIBRARY_AS_DATAFILE);
if (!hModule)
{
- WINE_WARN("LoadLibraryExW (%s) failed, error %d\n",
- wine_dbgstr_w(szFileName), GetLastError());
- return HRESULT_FROM_WIN32(GetLastError());
+ if (GetLastError() == ERROR_BAD_EXE_FORMAT)
+ return open_module16_icon(szFileName, nIndex, ppStream);
+ else
+ {
+ WINE_WARN("LoadLibraryExW (%s) failed, error %d\n",
+ wine_dbgstr_w(szFileName), GetLastError());
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
}
if (nIndex < 0)
@@ -656,7 +879,7 @@ static HRESULT open_module_icon(LPCWSTR szFileName, int nIndex, IStream **ppStre
{
if ((pIconDir = LockResource(hResData)))
{
- *ppStream = add_module_icons_to_stream(hModule, pIconDir);
+ *ppStream = add_module_icons_to_stream(0, hModule, pIconDir);
if (*ppStream)
hr = S_OK;
}
More information about the wine-patches
mailing list