For some reason muirct.exe is aware of the opaque structure used by BeginUpdateResource, it access the filename field of the opaque structure during it's processing.
MS documentation for the muirct utility: https://docs.microsoft.com/en-us/windows/desktop/intl/resource-utilities
Sample execution: MUIRCT.EXE -c "ui.exe" -e "de-DE\ui.exe.mui" --- dlls/kernel32/tests/resource.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/dlls/kernel32/tests/resource.c b/dlls/kernel32/tests/resource.c index 74066cfba3..6db9655833 100644 --- a/dlls/kernel32/tests/resource.c +++ b/dlls/kernel32/tests/resource.c @@ -24,6 +24,7 @@ #include "wine/test.h"
static const char filename[] = "test_.exe"; +static const wchar_t filenameW[] = L"test_.exe"; static DWORD GLE;
enum constants { @@ -463,6 +464,28 @@ static void test_find_resource(void) ok( GetLastError() == ERROR_RESOURCE_LANG_NOT_FOUND, "wrong error %u\n", GetLastError() ); }
+static void test_muirct_compatiblity(void) +{ + HANDLE res = NULL; + PVOID res_data; + PWCHAR res_filename; + + res = BeginUpdateResourceW( (PWCHAR)filenameW, FALSE ); + ok( res != NULL, "BeginUpdateResourceW failed\n" ); + res_data = GlobalLock(res); + ok( res_data != NULL, "GlobalLock failed\n" ); +#ifdef _WIN64 + res_filename = (PWCHAR)GlobalLock( *(HGLOBAL*)((ULONG_PTR)res_data + 0x30) ); +#else + res_filename = (PWCHAR)GlobalLock( *(HGLOBAL*)((ULONG_PTR)res_data + 0x18) ); +#endif + ok( res_filename != NULL, "GlobalLock for res_filename failed\n" ); + ok( !lstrcmpW(res_filename, (PWCHAR)filenameW), "Filename fields do not match\n" ); + ok( GlobalUnlock( res_filename ), "GlobalUnlock res_filenamed failed\n" ); + ok( GlobalUnlock( res_data ), "GlobalUnlock res_data failed\n" ); + ok( EndUpdateResourceW( res, TRUE ), "EndUpdateResourceW failed\n"); +} + START_TEST(resource) { DWORD i; @@ -482,6 +505,7 @@ START_TEST(resource) { const struct _sec_variants *sec = &sec_variants[i]; build_exe( &sec->build ); + test_muirct_compatiblity(); update_resources_none(); check_exe( &sec->chk_none ); update_resources_delete();
The utility muirct.exe for some reason accesses the opaque HANDLE that is returned by BeginUpdateResource, it assumes a certain structure in which (on 32bit systems) there is a pointer to the wide repesentation of the file name in offset 0x18.
Refer to: muirct!BldToolsEndUpdateResourceW called from muirct!CopyChecksumToFile
Sample execution: MUIRCT.EXE -c "ui.exe" -e "de-DE\ui.exe.mui" --- dlls/kernel32/resource.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/resource.c b/dlls/kernel32/resource.c index 73f3cca363..c5f2d79db0 100644 --- a/dlls/kernel32/resource.c +++ b/dlls/kernel32/resource.c @@ -635,7 +635,12 @@ DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
typedef struct { - LPWSTR pFileName; +#ifdef _WIN64 + UCHAR Reserved[0x30]; +#else + UCHAR Reserved[0x18]; +#endif + LPWSTR pFileName; // Must be in offset 0x18 on 32bit and 0x30 on 64bit BOOL bDeleteExistingResources; struct list root; } QUEUEDUPDATES;
On 07/09/2018 07:51 AM, Jon Doron wrote:
The utility muirct.exe for some reason accesses the opaque HANDLE that is returned by BeginUpdateResource, it assumes a certain structure in which (on 32bit systems) there is a pointer to the wide repesentation of the file name in offset 0x18.
Refer to: muirct!BldToolsEndUpdateResourceW called from muirct!CopyChecksumToFile
Sample execution: MUIRCT.EXE -c "ui.exe" -e "de-DE\ui.exe.mui"
dlls/kernel32/resource.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/resource.c b/dlls/kernel32/resource.c index 73f3cca363..c5f2d79db0 100644 --- a/dlls/kernel32/resource.c +++ b/dlls/kernel32/resource.c @@ -635,7 +635,12 @@ DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
typedef struct {
- LPWSTR pFileName;
+#ifdef _WIN64
- UCHAR Reserved[0x30];
+#else
- UCHAR Reserved[0x18];
+#endif
- LPWSTR pFileName; // Must be in offset 0x18 on 32bit and 0x30 on 64bit BOOL bDeleteExistingResources; struct list root; } QUEUEDUPDATES;
It'd be cleaner to use pointer-sized fields here.
More importantly, patch 1/2 will introduce failing tests, that normally should be marked with todo_wine, and you'd remove such marks in patch 2/2. In this case it's easier to simply send patches in opposite order, because failing test will be reading fields from incompatible data structure.
On 07/09/2018 07:51 AM, Jon Doron wrote:
For some reason muirct.exe is aware of the opaque structure used by BeginUpdateResource, it access the filename field of the opaque structure during it's processing.
MS documentation for the muirct utility: https://docs.microsoft.com/en-us/windows/desktop/intl/resource-utilities
Sample execution: MUIRCT.EXE -c "ui.exe" -e "de-DE\ui.exe.mui"
dlls/kernel32/tests/resource.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/dlls/kernel32/tests/resource.c b/dlls/kernel32/tests/resource.c index 74066cfba3..6db9655833 100644 --- a/dlls/kernel32/tests/resource.c +++ b/dlls/kernel32/tests/resource.c @@ -24,6 +24,7 @@ #include "wine/test.h"
static const char filename[] = "test_.exe"; +static const wchar_t filenameW[] = L"test_.exe";
Please use WCHAR[] type, and avoid L"" initializers.
static DWORD GLE;
enum constants { @@ -463,6 +464,28 @@ static void test_find_resource(void) ok( GetLastError() == ERROR_RESOURCE_LANG_NOT_FOUND, "wrong error %u\n", GetLastError() ); }
+static void test_muirct_compatiblity(void) +{
- HANDLE res = NULL;
No need to initialize this one.
- PVOID res_data;
- PWCHAR res_filename;
Preferred names for those are "void *" and "WCHAR *".
- res = BeginUpdateResourceW( (PWCHAR)filenameW, FALSE );
- ok( res != NULL, "BeginUpdateResourceW failed\n" );
- res_data = GlobalLock(res);
- ok( res_data != NULL, "GlobalLock failed\n" );
+#ifdef _WIN64
- res_filename = (PWCHAR)GlobalLock( *(HGLOBAL*)((ULONG_PTR)res_data + 0x30) );
+#else
- res_filename = (PWCHAR)GlobalLock( *(HGLOBAL*)((ULONG_PTR)res_data + 0x18) );
+#endif
It's better to introduce a structure type instead, similar to what implementation is using.
- ok( res_filename != NULL, "GlobalLock for res_filename failed\n" );
- ok( !lstrcmpW(res_filename, (PWCHAR)filenameW), "Filename fields do not match\n" );
- ok( GlobalUnlock( res_filename ), "GlobalUnlock res_filenamed failed\n" );
- ok( GlobalUnlock( res_data ), "GlobalUnlock res_data failed\n" );
- ok( EndUpdateResourceW( res, TRUE ), "EndUpdateResourceW failed\n");
+}
- START_TEST(resource) { DWORD i;
@@ -482,6 +505,7 @@ START_TEST(resource) { const struct _sec_variants *sec = &sec_variants[i]; build_exe( &sec->build );
test_muirct_compatiblity();
Test function should be named in a more generic manner, after fixed functionality, not the application that's using it.
update_resources_none(); check_exe( &sec->chk_none ); update_resources_delete();