From 34eccc80b93fab59aec8ee1cf3c47bf31ce7c1b6 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Thu, 19 Feb 2009 12:04:09 +0100 Subject: [PATCH] fusion: Implement the IAssemblyEnum interface. --- dlls/fusion/Makefile.in | 1 + dlls/fusion/asmcache.c | 83 --------- dlls/fusion/asmenum.c | 384 +++++++++++++++++++++++++++++++++++++++ dlls/fusion/asmname.c | 15 +- dlls/fusion/fusion.c | 12 -- dlls/fusion/fusionpriv.h | 15 ++ 6 files changed, 401 insertions(+), 109 deletions(-) create mode 100644 dlls/fusion/asmenum.c diff --git a/dlls/fusion/Makefile.in b/dlls/fusion/Makefile.in index 851fafcde21..788e1883203 100644 --- a/dlls/fusion/Makefile.in +++ b/dlls/fusion/Makefile.in @@ -7,6 +7,7 @@ IMPORTS = advapi32 dbghelp kernel32 shlwapi version C_SRCS = \ asmcache.c \ + asmenum.c \ asmname.c \ assembly.c \ fusion.c \ diff --git a/dlls/fusion/asmcache.c b/dlls/fusion/asmcache.c index 57c7aeded7d..d205de14e38 100644 --- a/dlls/fusion/asmcache.c +++ b/dlls/fusion/asmcache.c @@ -391,86 +391,3 @@ static const IAssemblyCacheItemVtbl AssemblyCacheItemVtbl = { IAssemblyCacheItemImpl_Commit, IAssemblyCacheItemImpl_AbortItem }; - -/* IAssemblyEnum */ - -typedef struct { - const IAssemblyEnumVtbl *lpIAssemblyEnumVtbl; - - LONG ref; -} IAssemblyEnumImpl; - -static HRESULT WINAPI IAssemblyEnumImpl_QueryInterface(IAssemblyEnum *iface, - REFIID riid, LPVOID *ppobj) -{ - IAssemblyEnumImpl *This = (IAssemblyEnumImpl *)iface; - - TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj); - - *ppobj = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAssemblyEnum)) - { - IUnknown_AddRef(iface); - *ppobj = This; - return S_OK; - } - - WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI IAssemblyEnumImpl_AddRef(IAssemblyEnum *iface) -{ - IAssemblyEnumImpl *This = (IAssemblyEnumImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before = %u)\n", This, refCount - 1); - - return refCount; -} - -static ULONG WINAPI IAssemblyEnumImpl_Release(IAssemblyEnum *iface) -{ - IAssemblyEnumImpl *This = (IAssemblyEnumImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before = %u)\n", This, refCount + 1); - - if (!refCount) - HeapFree(GetProcessHeap(), 0, This); - - return refCount; -} - -static HRESULT WINAPI IAssemblyEnumImpl_GetNextAssembly(IAssemblyEnum *iface, - LPVOID pvReserved, - IAssemblyName **ppName, - DWORD dwFlags) -{ - FIXME("(%p, %p, %p, %d) stub!\n", iface, pvReserved, ppName, dwFlags); - return E_NOTIMPL; -} - -static HRESULT WINAPI IAssemblyEnumImpl_Reset(IAssemblyEnum *iface) -{ - FIXME("(%p) stub!\n", iface); - return E_NOTIMPL; -} - -static HRESULT WINAPI IAssemblyEnumImpl_Clone(IAssemblyEnum *iface, - IAssemblyEnum **ppEnum) -{ - FIXME("(%p, %p) stub!\n", iface, ppEnum); - return E_NOTIMPL; -} - -static const IAssemblyEnumVtbl AssemblyEnumVtbl = { - IAssemblyEnumImpl_QueryInterface, - IAssemblyEnumImpl_AddRef, - IAssemblyEnumImpl_Release, - IAssemblyEnumImpl_GetNextAssembly, - IAssemblyEnumImpl_Reset, - IAssemblyEnumImpl_Clone -}; diff --git a/dlls/fusion/asmenum.c b/dlls/fusion/asmenum.c new file mode 100644 index 00000000000..929fff225e5 --- /dev/null +++ b/dlls/fusion/asmenum.c @@ -0,0 +1,384 @@ +/* + * IAssemblyEnum implementation + * + * Copyright 2008 James Hawkins + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "guiddef.h" +#include "fusion.h" +#include "corerror.h" +#include "fusionpriv.h" + +#include "wine/debug.h" +#include "wine/unicode.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(fusion); + +typedef struct _tagASMNAME +{ + struct list entry; + IAssemblyName *name; +} ASMNAME; + +typedef struct +{ + const IAssemblyEnumVtbl *lpIAssemblyEnumVtbl; + + struct list assemblies; + struct list *iter; + LONG ref; +} IAssemblyEnumImpl; + +static HRESULT WINAPI IAssemblyEnumImpl_QueryInterface(IAssemblyEnum *iface, + REFIID riid, LPVOID *ppobj) +{ + IAssemblyEnumImpl *This = (IAssemblyEnumImpl *)iface; + + TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj); + + *ppobj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IAssemblyEnum)) + { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI IAssemblyEnumImpl_AddRef(IAssemblyEnum *iface) +{ + IAssemblyEnumImpl *This = (IAssemblyEnumImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before = %u)\n", This, refCount - 1); + + return refCount; +} + +static ULONG WINAPI IAssemblyEnumImpl_Release(IAssemblyEnum *iface) +{ + IAssemblyEnumImpl *This = (IAssemblyEnumImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + struct list *item, *cursor; + + TRACE("(%p)->(ref before = %u)\n", This, refCount + 1); + + if (!refCount) + { + LIST_FOR_EACH_SAFE(item, cursor, &This->assemblies) + { + ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry); + + list_remove(&asmname->entry); + IAssemblyName_Release(asmname->name); + HeapFree(GetProcessHeap(), 0, asmname); + } + + HeapFree(GetProcessHeap(), 0, This); + } + + return refCount; +} + +static HRESULT WINAPI IAssemblyEnumImpl_GetNextAssembly(IAssemblyEnum *iface, + LPVOID pvReserved, + IAssemblyName **ppName, + DWORD dwFlags) +{ + IAssemblyEnumImpl *asmenum = (IAssemblyEnumImpl *)iface; + ASMNAME *asmname; + + TRACE("(%p, %p, %p, %d)\n", iface, pvReserved, ppName, dwFlags); + + if (!ppName) + return E_INVALIDARG; + + asmname = LIST_ENTRY(asmenum->iter, ASMNAME, entry); + if (!asmname) + return S_FALSE; + + *ppName = asmname->name; + IAssemblyName_AddRef(*ppName); + + asmenum->iter = list_next(&asmenum->assemblies, asmenum->iter); + + return S_OK; +} + +static HRESULT WINAPI IAssemblyEnumImpl_Reset(IAssemblyEnum *iface) +{ + IAssemblyEnumImpl *asmenum = (IAssemblyEnumImpl *)iface; + + TRACE("(%p)\n", iface); + + asmenum->iter = list_head(&asmenum->assemblies); + return S_OK; +} + +static HRESULT WINAPI IAssemblyEnumImpl_Clone(IAssemblyEnum *iface, + IAssemblyEnum **ppEnum) +{ + FIXME("(%p, %p) stub!\n", iface, ppEnum); + return E_NOTIMPL; +} + +static const IAssemblyEnumVtbl AssemblyEnumVtbl = { + IAssemblyEnumImpl_QueryInterface, + IAssemblyEnumImpl_AddRef, + IAssemblyEnumImpl_Release, + IAssemblyEnumImpl_GetNextAssembly, + IAssemblyEnumImpl_Reset, + IAssemblyEnumImpl_Clone +}; + +static void parse_name(IAssemblyName *name, int depth, LPWSTR path, LPWSTR buf) +{ + WCHAR disp[MAX_PATH]; + LPWSTR ptr, end; + LPCWSTR verptr, pubkeyptr; + HRESULT hr; + DWORD size; + + static const WCHAR star[] = {'*',0}; + static const WCHAR ss_fmt[] = {'%','s','\\','%','s',0}; + static const WCHAR verpubkey[] = {'%','s','\\','%','s','_','_','%','s',0}; + static const WCHAR version[] = {'V','e','r','s','i','o','n','=',0}; + static const WCHAR pubkeytok[] = { + 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0}; + + if (depth == 0) + { + size = MAX_PATH; + *disp = '\0'; + hr = IAssemblyName_GetName(name, &size, disp); + if (SUCCEEDED(hr)) + sprintfW(buf, ss_fmt, path, disp); + else + sprintfW(buf, ss_fmt, path, star); + } + else if (depth == 1) + { + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, disp, &size, 0); + if (FAILED(hr)) + { + sprintfW(buf, verpubkey, path, star, star); + return; + } + + ptr = disp; + verptr = strstrW(ptr, version); + if (!verptr) + verptr = star; + else + { + verptr = strchrW(verptr, '=') + 1; + if ((end = strchrW(verptr, ','))) + { + *end = '\0'; + ptr = end + 1; + } + } + + pubkeyptr = strstrW(ptr, pubkeytok); + if (!pubkeyptr) + pubkeyptr = star; + else + { + pubkeyptr = strchrW(pubkeyptr, '=') + 1; + if ((end = strchrW(pubkeyptr, ','))) + *end = '\0'; + } + + sprintfW(buf, verpubkey, path, verptr, pubkeyptr); + } +} + +static HRESULT enum_gac_assemblies(struct list *assemblies, IAssemblyName *name, + int depth, LPWSTR path) +{ + WIN32_FIND_DATAW ffd; + WCHAR buf[MAX_PATH]; + WCHAR disp[MAX_PATH]; + ASMNAME *asmname; + HANDLE hfind; + LPWSTR ptr; + HRESULT hr = S_OK; + + static WCHAR parent[MAX_PATH]; + + static const WCHAR dot[] = {'.',0}; + static const WCHAR dotdot[] = {'.','.',0}; + static const WCHAR search_fmt[] = {'%','s','\\','*',0}; + static const WCHAR parent_fmt[] = {'%','s',',',' ',0}; + static const WCHAR dblunder[] = {'_','_',0}; + static const WCHAR fmt[] = {'V','e','r','s','i','o','n','=','%','s',',',' ', + 'C','u','l','t','u','r','e','=','n','e','u','t','r','a','l',',',' ', + 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=','%','s',0}; + static const WCHAR ss_fmt[] = {'%','s','\\','%','s',0}; + + if (name) + parse_name(name, depth, path, buf); + else + sprintfW(buf, search_fmt, path); + + hfind = FindFirstFileW(buf, &ffd); + if (hfind == INVALID_HANDLE_VALUE) + return S_OK; + + do + { + if (!lstrcmpW(ffd.cFileName, dot) || !lstrcmpW(ffd.cFileName, dotdot)) + continue; + + if (depth == 0) + { + if (name) + ptr = strrchrW(buf, '\\') + 1; + else + ptr = ffd.cFileName; + + sprintfW(parent, parent_fmt, ptr); + } + else if (depth == 1) + { + ptr = strstrW(ffd.cFileName, dblunder); + *ptr = '\0'; + ptr += 2; + sprintfW(buf, fmt, ffd.cFileName, ptr); + + lstrcpyW(disp, parent); + lstrcatW(disp, buf); + + asmname = HeapAlloc(GetProcessHeap(), 0, sizeof(ASMNAME)); + if (!asmname) + { + hr = E_OUTOFMEMORY; + break; + } + + hr = CreateAssemblyNameObject(&asmname->name, disp, + CANOF_PARSE_DISPLAY_NAME, NULL); + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, asmname); + break; + } + + list_add_tail(assemblies, &asmname->entry); + continue; + } + + sprintfW(buf, ss_fmt, path, ffd.cFileName); + hr = enum_gac_assemblies(assemblies, name, depth + 1, buf); + if (FAILED(hr)) + break; + } while (FindNextFileW(hfind, &ffd) != 0); + + FindClose(hfind); + return hr; +} + +static HRESULT enumerate_gac(IAssemblyEnumImpl *asmenum, IAssemblyName *pName) +{ + WCHAR path[MAX_PATH]; + WCHAR buf[MAX_PATH]; + HRESULT hr; + DWORD size; + + static WCHAR under32[] = {'_','3','2',0}; + static WCHAR msil[] = {'_','M','S','I','L',0}; + + size = MAX_PATH; + hr = GetCachePath(ASM_CACHE_GAC, buf, &size); + if (FAILED(hr)) + return hr; + + lstrcpyW(path, buf); + lstrcatW(path, under32); + hr = enum_gac_assemblies(&asmenum->assemblies, pName, 0, path); + if (FAILED(hr)) + return hr; + + lstrcpyW(path, buf); + lstrcatW(path, msil); + hr = enum_gac_assemblies(&asmenum->assemblies, pName, 0, path); + if (FAILED(hr)) + return hr; + + hr = enum_gac_assemblies(&asmenum->assemblies, pName, 0, buf); + if (FAILED(hr)) + return hr; + + return S_OK; +} + +/****************************************************************** + * CreateAssemblyEnum (FUSION.@) + */ +HRESULT WINAPI CreateAssemblyEnum(IAssemblyEnum **pEnum, IUnknown *pUnkReserved, + IAssemblyName *pName, DWORD dwFlags, LPVOID pvReserved) +{ + IAssemblyEnumImpl *asmenum; + HRESULT hr; + + TRACE("(%p, %p, %p, %08x, %p)\n", pEnum, pUnkReserved, + pName, dwFlags, pvReserved); + + if (!pEnum) + return E_INVALIDARG; + + if (dwFlags == 0 || dwFlags == ASM_CACHE_ROOT) + return E_INVALIDARG; + + asmenum = HeapAlloc(GetProcessHeap(), 0, sizeof(IAssemblyEnumImpl)); + if (!asmenum) + return E_OUTOFMEMORY; + + asmenum->lpIAssemblyEnumVtbl = &AssemblyEnumVtbl; + asmenum->ref = 1; + list_init(&asmenum->assemblies); + + if (dwFlags & ASM_CACHE_GAC) + { + hr = enumerate_gac(asmenum, pName); + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, asmenum); + return hr; + } + } + + asmenum->iter = list_head(&asmenum->assemblies); + *pEnum = (IAssemblyEnum *)asmenum; + + return S_OK; +} diff --git a/dlls/fusion/asmname.c b/dlls/fusion/asmname.c index 50ae05ec525..490de2127c8 100644 --- a/dlls/fusion/asmname.c +++ b/dlls/fusion/asmname.c @@ -33,23 +33,10 @@ #include "wine/debug.h" #include "wine/unicode.h" +#include "fusionpriv.h" WINE_DEFAULT_DEBUG_CHANNEL(fusion); -static inline LPWSTR strdupW(LPCWSTR src) -{ - LPWSTR dest; - - if (!src) - return NULL; - - dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src) + 1) * sizeof(WCHAR)); - if (dest) - lstrcpyW(dest, src); - - return dest; -} - typedef struct { const IAssemblyNameVtbl *lpIAssemblyNameVtbl; diff --git a/dlls/fusion/fusion.c b/dlls/fusion/fusion.c index ac01cf415ee..5975d431c97 100644 --- a/dlls/fusion/fusion.c +++ b/dlls/fusion/fusion.c @@ -54,18 +54,6 @@ HRESULT WINAPI CompareAssemblyIdentity(LPCWSTR pwzAssemblyIdentity1, BOOL fUnifi return E_NOTIMPL; } -/****************************************************************** - * CreateAssemblyEnum (FUSION.@) - */ -HRESULT WINAPI CreateAssemblyEnum(IAssemblyEnum **pEnum, IUnknown *pUnkReserved, - IAssemblyName *pName, DWORD dwFlags, LPVOID pvReserved) -{ - FIXME("(%p, %p, %p, %08x, %p) stub!\n", pEnum, pUnkReserved, - pName, dwFlags, pvReserved); - - return E_NOTIMPL; -} - /****************************************************************** * CreateInstallReferenceEnum (FUSION.@) */ diff --git a/dlls/fusion/fusionpriv.h b/dlls/fusion/fusionpriv.h index a4e6193b054..848eab75b9c 100644 --- a/dlls/fusion/fusionpriv.h +++ b/dlls/fusion/fusionpriv.h @@ -26,6 +26,7 @@ #include "windef.h" #include "winbase.h" #include "winuser.h" +#include "winver.h" #include @@ -435,4 +436,18 @@ HRESULT assembly_get_version(ASSEMBLY *assembly, LPSTR *version); HRESULT assembly_get_architecture(ASSEMBLY *assembly, DWORD fixme); HRESULT assembly_get_pubkey_token(ASSEMBLY *assembly, LPSTR *token); +static inline LPWSTR strdupW(LPCWSTR src) +{ + LPWSTR dest; + + if (!src) + return NULL; + + dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src) + 1) * sizeof(WCHAR)); + if (dest) + lstrcpyW(dest, src); + + return dest; +} + #endif /* __WINE_FUSION_PRIVATE__ */