winemenubuilder: extract icons from NE binaries too
Damjan Jovanovic
damjan.jov at gmail.com
Mon May 16 23:55:24 CDT 2011
Changelog:
* winemenubuilder: extract icons from NE binaries too
Damjan Jovanovic
-------------- next part --------------
diff --git a/programs/winemenubuilder/Makefile.in b/programs/winemenubuilder/Makefile.in
index 3f8ec40..1b9db34 100644
--- a/programs/winemenubuilder/Makefile.in
+++ b/programs/winemenubuilder/Makefile.in
@@ -1,7 +1,7 @@
EXTRADEFS = -DWINE_NO_UNICODE_MACROS
MODULE = winemenubuilder.exe
APPMODE = -mwindows -municode
-IMPORTS = uuid windowscodecs shell32 shlwapi ole32 user32 advapi32
+IMPORTS = uuid windowscodecs shell32 shlwapi ole32 user32 advapi32 kernel
C_SRCS = \
winemenubuilder.c
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
index 5908e4e..d19ed1a 100644
--- a/programs/winemenubuilder/winemenubuilder.c
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -96,6 +96,7 @@
#include "wine/library.h"
#include "wine/list.h"
#include "wine/rbtree.h"
+#include "wine/winbase16.h"
WINE_DEFAULT_DEBUG_CHANNEL(menubuilder);
@@ -236,6 +237,35 @@ static char* heap_printf(const char *format, ...)
return ret;
}
+static WCHAR* heap_printfW(const WCHAR *format, ...)
+{
+ va_list args;
+ int size = 4096;
+ WCHAR *buffer, *ret;
+ int n;
+
+ va_start(args, format);
+ while (1)
+ {
+ buffer = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
+ if (buffer == NULL)
+ break;
+ n = vsnprintfW(buffer, size, format, args);
+ if (n == -1)
+ size *= 2;
+ else if (n >= size)
+ size = n + 1;
+ else
+ break;
+ HeapFree(GetProcessHeap(), 0, buffer);
+ }
+ va_end(args);
+ if (!buffer) return NULL;
+ ret = HeapReAlloc(GetProcessHeap(), 0, buffer, (strlenW(buffer) + 1)*sizeof(WCHAR) );
+ if (!ret) ret = buffer;
+ return ret;
+}
+
static int winemenubuilder_rb_string_compare(const void *key, const struct wine_rb_entry *entry)
{
const struct rb_string_entry *t = WINE_RB_ENTRY_VALUE(entry, const struct rb_string_entry, entry);
@@ -491,7 +521,79 @@ end:
return hr;
}
-static IStream *add_module_icons_to_stream(HMODULE hModule, GRPICONDIR *grpIconDir)
+static int populate_module16_icons(HMODULE16 hModule, GRPICONDIR *grpIconDir, ICONDIRENTRY *iconDirEntries, BYTE *icons, SIZE_T *iconOffset)
+{
+ int i;
+ int validEntries = 0;
+
+ for (i = 0; i < grpIconDir->idCount; i++)
+ {
+ HRSRC16 hResInfo;
+ LPCSTR lpName = MAKEINTRESOURCEA(grpIconDir->idEntries[i].nID);
+ if ((hResInfo = FindResource16(hModule, lpName, (LPCSTR)NE_RSCTYPE_ICON)))
+ {
+ HGLOBAL16 hResData;
+ if ((hResData = LoadResource16(hModule, hResInfo)))
+ {
+ BITMAPINFO *pIcon;
+ if ((pIcon = LockResource16(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;
+ }
+ FreeResource16(hResData);
+ }
+ }
+ }
+ 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(HMODULE16 hModule16, HMODULE hModule, GRPICONDIR *grpIconDir)
{
int i;
SIZE_T iconsSize = 0;
@@ -529,34 +631,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 (hModule16 >= HINSTANCE_ERROR)
+ validEntries = populate_module16_icons(hModule16, grpIconDir, iconDirEntries, icons, &iconOffset);
+ else if (hModule)
+ validEntries = populate_module_icons(hModule, grpIconDir, iconDirEntries, icons, &iconOffset);
if (validEntries == 0)
{
@@ -601,6 +679,117 @@ end:
return stream;
}
+static HRESULT open_module16_icon(LPCWSTR szFileName, int nIndex, IStream **ppStream)
+{
+ static const WCHAR PathW[] = {'P','A','T','H',0};
+ static const WCHAR PathPatternW[] = {'%','s',';','%','s',0};
+ char *fileNameA = NULL;
+ int lastSlash;
+ WCHAR *dir = NULL;
+ WCHAR *oldPath = NULL;
+ WCHAR *path = NULL;
+ HMODULE16 hModule = HINSTANCE_ERROR;
+ HRSRC16 hResInfo;
+ HGLOBAL16 hResData;
+ GRPICONDIR *pIconDir;
+ HRESULT hr = E_FAIL;
+
+ fileNameA = wchars_to_utf8_chars(szFileName);
+ if (fileNameA == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto end;
+ }
+
+ /* LoadLibrary16() searches the directory of the calling process for
+ * the module's required DLLs, not the directory of the module.
+ * The only way to override it seems to be to modify $PATH.
+ */
+ dir = HeapAlloc(GetProcessHeap(), 0, (strlenW(szFileName)+1)*sizeof(WCHAR));
+ if (dir == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto end;
+ }
+ strcpyW(dir, szFileName);
+ for (lastSlash = strlenW(dir) - 1; lastSlash >= 0; lastSlash--)
+ {
+ if (dir[lastSlash] == '\\')
+ break;
+ }
+ if (lastSlash >= 0)
+ {
+ dir[lastSlash] = 0;
+ oldPath = HeapAlloc(GetProcessHeap(), 0, 32767);
+ if (oldPath == NULL)
+ goto end;
+ if (!GetEnvironmentVariableW(PathW, oldPath, 32767))
+ goto end;
+ path = heap_printfW(PathPatternW, oldPath, dir);
+ if (path == NULL)
+ goto end;
+ if (!SetEnvironmentVariableW(PathW, path))
+ goto end;
+ }
+
+ /* LoadLibrary16() only looks for .dll files, so these are never found */
+ LoadLibrary16("gdi.exe");
+ LoadLibrary16("user.exe");
+
+ hModule = LoadLibrary16(fileNameA);
+ if (hModule < HINSTANCE_ERROR)
+ {
+ WINE_WARN("LoadLibrary16 (%s) failed, error %d\n",
+ wine_dbgstr_w(szFileName), hModule);
+ hr = HRESULT_FROM_WIN32(hModule);
+ goto end;
+ }
+
+ /* Not specifying an icon to PROGMAN leads to nIndex being 0,
+ * which means the "first icon" must be used. Unfortunately
+ * there is no EnumResourceNames16(), but the first icon
+ * usually appears to have index 1...
+ */
+ if (nIndex == 0)
+ nIndex = 1;
+
+ hResInfo = FindResource16(hModule, MAKEINTRESOURCEA(nIndex), (LPCSTR)NE_RSCTYPE_GROUP_ICON);
+ WINE_TRACE("FindResource16 (%s) called, return %d\n",
+ wine_dbgstr_w(szFileName), hResInfo);
+
+ if (hResInfo)
+ {
+ if ((hResData = LoadResource16(hModule, hResInfo)))
+ {
+ if ((pIconDir = LockResource16(hResData)))
+ {
+ *ppStream = add_module_icons_to_stream(hModule, NULL, pIconDir);
+ if (*ppStream)
+ hr = S_OK;
+ }
+
+ FreeResource16(hResData);
+ }
+ }
+ else
+ {
+ WINE_WARN("found no icon\n");
+ hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+ goto end;
+ }
+
+end:
+ HeapFree(GetProcessHeap(), 0, fileNameA);
+ HeapFree(GetProcessHeap(), 0, dir);
+ if (oldPath)
+ SetEnvironmentVariableW(PathW, oldPath);
+ HeapFree(GetProcessHeap(), 0, oldPath);
+ HeapFree(GetProcessHeap(), 0, path);
+ if (hModule >= HINSTANCE_ERROR)
+ FreeLibrary16(hModule);
+ return hr;
+}
+
static BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam)
{
ENUMRESSTRUCT *sEnumRes = (ENUMRESSTRUCT *) lParam;
@@ -626,9 +815,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 +850,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