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