[01/12] fusion: Implement the IAssemblyEnum interface.

Hans Leidekker hans at codeweavers.com
Wed Feb 18 07:34:54 CST 2009


Changelog
 "James Hawkins" <truiken at gmail.com>
 fusion: Implement the IAssemblyEnum interface.

 -Hans

diff --git a/dlls/fusion/Makefile.in b/dlls/fusion/Makefile.in
index 851fafc..788e188 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 57c7aed..d205de1 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 0000000..929fff2
--- /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 <stdarg.h>
+
+#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 50ae05e..490de21 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 ac01cf4..5975d43 100644
--- a/dlls/fusion/fusion.c
+++ b/dlls/fusion/fusion.c
@@ -55,18 +55,6 @@ HRESULT WINAPI CompareAssemblyIdentity(LPCWSTR pwzAssemblyIdentity1, BOOL fUnifi
 }
 
 /******************************************************************
- *  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.@)
  */
 HRESULT WINAPI CreateInstallReferenceEnum(IInstallReferenceEnum **ppRefEnum,
diff --git a/dlls/fusion/fusionpriv.h b/dlls/fusion/fusionpriv.h
index a4e6193..848eab7 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 <pshpack1.h>
 
@@ -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__ */



More information about the wine-patches mailing list