From: Owen Rudge Subject: [2/2] fusion: Implement IAssemblyNameImpl_GetDisplayName more completely Message-Id: <4C449A9A.9080600@codeweavers.com> Date: Mon, 19 Jul 2010 19:34:02 +0100 This patch provides a more complete implementation of IAssemblyNameImpl_GetDisplayName, and is also required to fix the slow DirectX installer bug (22774). --- dlls/fusion/Makefile.in | 2 +- dlls/fusion/asmname.c | 134 +++++++++++++++++++++++++++++++++++++++---- dlls/fusion/tests/asmname.c | 96 +++++++++++++++++++++++++++++-- 3 files changed, 215 insertions(+), 17 deletions(-) diff --git a/dlls/fusion/Makefile.in b/dlls/fusion/Makefile.in index 17ad08f..5904f07 100644 --- a/dlls/fusion/Makefile.in +++ b/dlls/fusion/Makefile.in @@ -3,7 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = fusion.dll -IMPORTS = advapi32 dbghelp kernel32 shlwapi version +IMPORTS = advapi32 dbghelp kernel32 shlwapi version user32 C_SRCS = \ asmcache.c \ diff --git a/dlls/fusion/asmname.c b/dlls/fusion/asmname.c index 3c014ea..13b6f32 100644 --- a/dlls/fusion/asmname.c +++ b/dlls/fusion/asmname.c @@ -43,6 +43,7 @@ typedef struct { LPWSTR displayname; LPWSTR name; LPWSTR culture; + LPWSTR procarch; WORD version[4]; DWORD versize; @@ -53,6 +54,16 @@ typedef struct { LONG ref; } IAssemblyNameImpl; +static const WCHAR separator[] = {',',' ',0}; +static const WCHAR version[] = {'V','e','r','s','i','o','n',0}; +static const WCHAR culture[] = {'C','u','l','t','u','r','e',0}; +static const WCHAR pubkey[] = + {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0}; +static const WCHAR procarch[] = {'p','r','o','c','e','s','s','o','r', + 'A','r','c','h','i','t','e','c','t','u','r','e',0}; + +#define CHARS_PER_PUBKEY 16 + static HRESULT WINAPI IAssemblyNameImpl_QueryInterface(IAssemblyName *iface, REFIID riid, LPVOID *ppobj) { @@ -208,16 +219,120 @@ static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface, DWORD dwDisplayFlags) { IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface; + WCHAR verstr[30]; + DWORD size; + LPWSTR cultureval = 0; + + static const WCHAR equals[] = {'=',0}; TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName, pccDisplayName, dwDisplayFlags); - if (!name->displayname || !*name->displayname) + if (dwDisplayFlags == 0) + { + if (!name->displayname || !*name->displayname) + return FUSION_E_INVALID_NAME; + + size = min(*pccDisplayName, lstrlenW(name->displayname) + 1); + + lstrcpynW(szDisplayName, name->displayname, size); + *pccDisplayName = size; + + return S_OK; + } + + if (!name->name || !*name->name) return FUSION_E_INVALID_NAME; - lstrcpyW(szDisplayName, name->displayname); - *pccDisplayName = lstrlenW(szDisplayName) + 1; + /* Verify buffer size is sufficient */ + size = lstrlenW(name->name) + 1; + + if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0)) + { + static const WCHAR spec[] = {'%','d',0}; + static const WCHAR period[] = {'.',0}; + int i; + + wsprintfW(verstr, spec, name->version[0]); + + for (i = 1; i < name->versize; i++) + { + WCHAR value[6]; + wsprintfW(value, spec, name->version[i]); + + lstrcatW(verstr, period); + lstrcatW(verstr, value); + } + + size += lstrlenW(separator) + lstrlenW(version) + lstrlenW(equals) + lstrlenW(verstr); + } + + if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture)) + { + static const WCHAR neutral[] = {'n','e','u','t','r','a','l', 0}; + + cultureval = (lstrlenW(name->culture) == 2) ? name->culture : (LPWSTR) neutral; + size += lstrlenW(separator) + lstrlenW(culture) + lstrlenW(equals) + lstrlenW(cultureval); + } + + if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey)) + size += lstrlenW(separator) + lstrlenW(pubkey) + lstrlenW(equals) + CHARS_PER_PUBKEY; + if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch)) + size += lstrlenW(separator) + lstrlenW(procarch) + lstrlenW(equals) + lstrlenW(name->procarch); + + if (size > *pccDisplayName) + return S_FALSE; + + /* Construct the string */ + lstrcpyW(szDisplayName, name->name); + + if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0)) + { + lstrcatW(szDisplayName, separator); + + lstrcatW(szDisplayName, version); + lstrcatW(szDisplayName, equals); + lstrcatW(szDisplayName, verstr); + } + + if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture)) + { + lstrcatW(szDisplayName, separator); + + lstrcatW(szDisplayName, culture); + lstrcatW(szDisplayName, equals); + lstrcatW(szDisplayName, cultureval); + } + + if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey)) + { + WCHAR pkt[CHARS_PER_PUBKEY + 1]; + static const WCHAR spec[] = {'%','0','x','%','0','x','%','0','x', + '%','0','x','%','0','x','%','0','x','%','0','x','%','0','x',0}; + + lstrcatW(szDisplayName, separator); + + lstrcatW(szDisplayName, pubkey); + lstrcatW(szDisplayName, equals); + + wsprintfW(pkt, spec, name->pubkey[0], name->pubkey[1], name->pubkey[2], + name->pubkey[3], name->pubkey[4], name->pubkey[5], name->pubkey[6], + name->pubkey[7]); + + lstrcatW(szDisplayName, pkt); + } + + if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch)) + { + lstrcatW(szDisplayName, separator); + + lstrcatW(szDisplayName, procarch); + lstrcatW(szDisplayName, equals); + lstrcatW(szDisplayName, name->procarch); + } + + *pccDisplayName = size; return S_OK; } @@ -347,8 +462,6 @@ static HRESULT parse_culture(IAssemblyNameImpl *name, LPWSTR culture) return S_OK; } -#define CHARS_PER_PUBKEY 16 - static BOOL is_hex(WCHAR c) { return ((c >= 'a' && c <= 'f') || @@ -397,12 +510,6 @@ static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyNam HRESULT hr = S_OK; BOOL done = FALSE; - static const WCHAR separator[] = {',',' ',0}; - static const WCHAR version[] = {'V','e','r','s','i','o','n',0}; - static const WCHAR culture[] = {'C','u','l','t','u','r','e',0}; - static const WCHAR pubkey[] = - {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0}; - if (!szAssemblyName) return S_OK; @@ -462,6 +569,11 @@ static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyNam hr = parse_culture(name, ptr); else if (!lstrcmpW(str, pubkey)) hr = parse_pubkey(name, ptr); + else if (!lstrcmpW(str, procarch)) + { + name->procarch = strdupW(ptr); + hr = S_OK; + } if (FAILED(hr)) goto done; diff --git a/dlls/fusion/tests/asmname.c b/dlls/fusion/tests/asmname.c index 824837b..15ecb0b 100644 --- a/dlls/fusion/tests/asmname.c +++ b/dlls/fusion/tests/asmname.c @@ -718,6 +718,95 @@ static void test_CreateAssemblyNameObject(void) IAssemblyName_Release(name); + /* Processor architecture tests */ + to_widechar(namestr, "wine, processorArchitecture=x86"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK || + broken(hr == FUSION_E_INVALID_NAME), /* .NET 1.x */ + "Expected S_OK, got %08x\n", hr); + + if (hr != S_OK) + win_skip("processorArchitecture not supported on .NET 1.x\n"); + else + { + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_PROCESSORARCHITECTURE); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, processorArchitecture=x86", str); + ok(size == 32, "Expected 32, got %d\n", size); + + IAssemblyName_Release(name); + + /* amd64 */ + to_widechar(namestr, "wine, processorArchitecture=AMD64"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_PROCESSORARCHITECTURE); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, processorArchitecture=AMD64", str); + ok(size == 34, "Expected 34, got %d\n", size); + + IAssemblyName_Release(name); + + /* ia64 */ + to_widechar(namestr, "wine, processorArchitecture=IA64"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_PROCESSORARCHITECTURE); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, processorArchitecture=IA64", str); + ok(size == 33, "Expected 33, got %d\n", size); + + IAssemblyName_Release(name); + + /* msil */ + to_widechar(namestr, "wine, processorArchitecture=MSIL"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_PROCESSORARCHITECTURE); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, processorArchitecture=MSIL", str); + ok(size == 33, "Expected 33, got %d\n", size); + + IAssemblyName_Release(name); + } + + /* Pulling out various different values */ + to_widechar(namestr, "wine, Version=1.2.3.4, Culture=en, PublicKeyToken=1234567890abcdef"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_VERSION | ASM_DISPLAYF_CULTURE); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, Version=1.2.3.4, Culture=en", str); + ok(size == 34, "Expected 34, got %d\n", size); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_CULTURE | ASM_DISPLAYF_PUBLIC_KEY_TOKEN); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, Culture=en, PublicKeyToken=1234567890abcdef", str); + ok(size == 50, "Expected 50, got %d\n", size); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, Version=1.2.3.4, Culture=en, PublicKeyToken=1234567890abcdef", str); + ok(size == 67, "Expected 67, got %d\n", size); + + IAssemblyName_Release(name); + /* invalid property */ to_widechar(namestr, "wine, BadProp=42"); name = NULL; @@ -729,11 +818,8 @@ static void test_CreateAssemblyNameObject(void) str[0] = '\0'; hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); - todo_wine - { - ok_aw("wine", str); - ok(size == 5, "Expected 5, got %d\n", size); - } + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); size = MAX_PATH; str[0] = '\0';