DEVENUM.DLL Implementation

Robert Shearman R.J.Shearman at warwick.ac.uk
Wed Dec 11 16:13:16 CST 2002


This should be an almost complete implementation of DEVENUM.DLL
What is not complete yet, is one function that uses IFilterMapper2 (not
implemented yet in quartz.dll) to generate some dynamic information about
the waveIn, waveOut and midi devices available. Also, it seems to fail when
using built-in oleaut32, but not when using native devenum and not when
using native oleaut32. I am hoping the reason for this should become
fixed/clearer after implementing quartz.dll (and no, I am not
volunteering!).

ChangeLog:
- Implement DEVENUM.DLL (ICreateDevEnum interface)

Rob
-------------- next part --------------
Index: wine/dlls/devenum/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/devenum/Makefile.in,v
retrieving revision 1.5
diff -u -r1.5 Makefile.in
--- wine/dlls/devenum/Makefile.in	17 May 2002 03:37:12 -0000	1.5
+++ wine/dlls/devenum/Makefile.in	11 Dec 2002 20:28:11 -0000
@@ -1,14 +1,20 @@
 TOPSRCDIR = @top_srcdir@
-TOPOBJDIR = ../..
-SRCDIR    = @srcdir@
-VPATH     = @srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
 MODULE    = devenum.dll
+IMPORTS   = kernel32 advapi32 ole32 oleaut32
+EXTRALIBS = $(LIBUUID)
 
 LDDLLFLAGS = @LDDLLFLAGS@
 SYMBOLFILE = $(MODULE).tmp.o
 
-C_SRCS = devenum_main.c
-
- at MAKE_DLL_RULES@
-
-### Dependencies:
+C_SRCS = devenum_main.c \
+         factory.c \
+         createdevenum.c \
+         mediacatenum.c \
+	 parsedisplayname.c
+
+ at MAKE_DLL_RULES@
+
+### Dependencies:
Index: wine/dlls/devenum/devenum.spec
===================================================================
RCS file: /home/wine/wine/dlls/devenum/devenum.spec,v
retrieving revision 1.4
diff -u -r1.4 devenum.spec
--- wine/dlls/devenum/devenum.spec	21 Jun 2002 19:15:46 -0000	1.4
+++ wine/dlls/devenum/devenum.spec	11 Dec 2002 20:28:11 -0000
@@ -1,4 +1,5 @@
-@ stub DllCanUnloadNow
-@ stub DllGetClassObject
-@ stub DllRegisterServer
-@ stub DllUnregisterServer
+
+@ stdcall DllCanUnloadNow() DEVENUM_DllCanUnloadNow
+@ stdcall DllGetClassObject(ptr ptr ptr) DEVENUM_DllGetClassObject
+@ stdcall DllRegisterServer() DEVENUM_DllRegisterServer
+@ stdcall DllUnregisterServer() DEVENUM_DllUnregisterServer
Index: wine/dlls/devenum/devenum_main.c
===================================================================
RCS file: /home/wine/wine/dlls/devenum/devenum_main.c,v
retrieving revision 1.1
diff -u -r1.1 devenum_main.c
--- wine/dlls/devenum/devenum_main.c	23 Oct 2001 20:35:23 -0000	1.1
+++ wine/dlls/devenum/devenum_main.c	11 Dec 2002 20:28:12 -0000
@@ -1 +1,339 @@
-/* nothing here yet */
+/*
+ *	exported dll functions for devenum.dll
+ *
+ * Copyright (C) 2002 John K. Hohm
+ * Copyright (C) 2002 Robert Shearman
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "devenum_private.h"
+#include "wine/debug.h"
+#include "winreg.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(devenum);
+
+DWORD dll_ref = 0;
+HINSTANCE DEVENUM_hInstance = 0;
+
+typedef struct
+{
+    REFCLSID clsid;
+    LPCWSTR friendly_name;
+    BOOL instance;
+} register_info;
+
+static HRESULT register_clsids(int count, const register_info * pRegInfo, LPCWSTR pszThreadingModel);
+
+/***********************************************************************
+ *		Global string constant definitions
+ */
+const WCHAR clsid_keyname[6] = { 'C', 'L', 'S', 'I', 'D', 0 };
+
+/***********************************************************************
+ *		Registration entries
+ */
+//{62BE5D10-60EB-11d0-BD3B-00A0C911CE86}
+
+/***********************************************************************
+ *		DllEntryPoint
+ */
+BOOL WINAPI DEVENUM_DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
+{
+    TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
+
+    switch(fdwReason) {
+    case DLL_PROCESS_ATTACH:
+        DEVENUM_hInstance = hinstDLL;
+	break;
+
+    case DLL_PROCESS_DETACH:
+        DEVENUM_hInstance = 0;
+	break;
+    }
+    return TRUE;
+}
+
+/***********************************************************************
+ *		DllGetClassObject (DEVENUM.@)
+ */
+HRESULT WINAPI DEVENUM_DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
+{
+    TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
+    *ppv = NULL;
+    if (IsEqualGUID(rclsid, &CLSID_SystemDeviceEnum) ||
+        IsEqualGUID(rclsid, &CLSID_CDeviceMoniker))
+	return IClassFactory_QueryInterface((LPCLASSFACTORY)&DEVENUM_ClassFactory, iid, ppv);
+    FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
+    return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+/***********************************************************************
+ *		DllCanUnloadNow (DEVENUM.@)
+ */
+HRESULT WINAPI DEVENUM_DllCanUnloadNow()
+{
+    return dll_ref != 0 ? S_FALSE : S_OK;
+}
+
+/***********************************************************************
+ *		DllRegisterServer (DEVENUM.@)
+ */
+HRESULT WINAPI DEVENUM_DllRegisterServer()
+{
+    HRESULT res;
+    HKEY hkeyClsid = NULL;
+    HKEY hkey1 = NULL;
+    HKEY hkey2 = NULL;
+    LPOLESTR pszClsidDevMon = NULL;
+#ifdef FILTERMAPPER2_IMPLEMENTED
+    IFilterMapper2 pMapper = NULL;
+#endif
+    const WCHAR threadingModel[] = {'B','o','t','h',0};
+    const WCHAR sysdevenum[] = {'S','y','s','t','e','m',' ','D','e','v','i','c','e',' ','E','n','u','m',0};
+    const WCHAR devmon[] = {'D','e','v','i','c','e','M','o','n','i','k','e','r',0};
+    const WCHAR acmcat[] = {'A','C','M',' ','C','l','a','s','s',' ','M','a','n','a','g','e','r',0};
+    const WCHAR vidcat[] = {'I','C','M',' ','C','l','a','s','s',' ','M','a','n','a','g','e','r',0};
+    const WCHAR filtcat[] = {'A','c','t','i','v','e','M','o','v','i','e',' ','F','i','l','t','e','r',' ','C','l','a','s','s',' ','M','a','n','a','g','e','r',0};
+    const WCHAR vfwcat[] = {'V','F','W',' ','C','a','p','t','u','r','e',' ','C','l','a','s','s',' ','M','a','n','a','g','e','r',0};
+    const WCHAR wavein[] = {'W','a','v','e','I','n',' ','C','l','a','s','s',' ','M','a','n','a','g','e','r', 0};
+    const WCHAR waveout[] = {'W','a','v','e','O','u','t',' ','a','n','d',' ','D','S','o','u','n','d',' ','C','l','a','s','s',' ','M','a','n','a','g','e','r',0};
+    const WCHAR midiout[] = {'M','i','d','i','O','u','t',' ','C','l','a','s','s',' ','M','a','n','a','g','e','r',0};
+    const WCHAR amcat[] = {'A','c','t','i','v','e','M','o','v','i','e',' ','F','i','l','t','e','r',' ','C','a','t','e','g','o','r','i','e','s',0};
+    const WCHAR device[] = {'d','e','v','i','c','e',0};
+    const WCHAR device_1[] = {'d','e','v','i','c','e','.','1',0};
+    const register_info ri[] =
+    {
+        {&CLSID_SystemDeviceEnum, sysdevenum, FALSE},
+	{&CLSID_CDeviceMoniker, devmon, FALSE},
+	{&CLSID_AudioCompressorCategory, acmcat, TRUE},
+	{&CLSID_VideoCompressorCategory, vidcat, TRUE},
+	{&CLSID_LegacyAmFilterCategory, filtcat, TRUE},
+	{&CLSID_VideoInputDeviceCategory, vfwcat, FALSE},
+	{&CLSID_AudioInputDeviceCategory, wavein, FALSE},
+	{&CLSID_AudioRendererCategory, waveout, FALSE},
+	{&CLSID_MidiRendererCategory, midiout, FALSE},
+	{&CLSID_ActiveMovieCategories, amcat, TRUE}
+    };
+
+    TRACE("\n");
+
+    res = register_clsids(sizeof(ri) / sizeof(register_info), ri, threadingModel);
+
+//    ActiveMovieFilter Categories
+#ifdef FILTERMAPPER2_IMPLEMENTED
+    {
+    const WCHAR friendlyvidcap[] = {'V','i','d','e','o',' ','C','a','p','t','u','r','e',' ','S','o','u','r','c','e','s',0};
+    const WCHAR friendlydshow[] = {'D','i','r','e','c','t','S','h','o','w',' ','F','i','l','t','e','r','s',0};
+    const WCHAR friendlyvidcomp[] = {'V','i','d','e','o',' ','C','o','m','p','r','e','s','s','o','r','s',0};
+    const WCHAR friendlyaudcap[] = {'A','u','d','i','o',' ','C','a','p','t','u','r','e',' ','S','o','u','r','c','e','s',0};
+    const WCHAR friendlyaudcomp[] = {'A','u','d','i','o',' ','C','o','m','p','r','e','s','s','o','r','s',0};
+    const WCHAR friendlyaudrend[] = {'A','u','d','i','o',' ','R','e','n','d','e','r','e','r','s',0};
+    const WCHAR friendlymidirend[] = {'M','i','d','i',' ','R','e','n','d','e','r','e','r','s',0};
+    const WCHAR friendlyextrend[] = {'E','x','t','e','r','n','a','l',' ','R','e','n','d','e','r','e','r','s',0};
+    const WCHAR friendlydevctrl[] = {'D','e','v','i','c','e',' ','C','o','n','t','r','o','l',' ','F','i','l','t','e','r','s',0);
+    CoInitialize();
+    res = CoCreateInstance(CLSID_FilerMapper2, NULL, CLSCTX_INPROC
+                           IID_IFilterMapper2, (void **) &pMapper);
+
+    IFilterMapper2_CreateCategory(pMapper, &CLSID_VideoInputDeviceCategory, MERIT_DO_NOT_USE, friendlyvidcap);
+    IFilterMapper2_CreateCategory(pMapper, &CLSID_LegacyAmFilterCategory, MERIT_NORMAL, friendlydshow);
+    IFilterMapper2_CreateCategory(pMapper, &CLSID_VideoCompressorCategory, MERIT_DO_NOT_USE, friendlyvidcomp);
+    IFilterMapper2_CreateCategory(pMapper, &CLSID_AudioInputDeviceCategory, MERIT_DO_NOT_USE, friendlyaudcap);
+    IFilterMapper2_CreateCategory(pMapper, &CLSID_AudioCompressorCategory, MERIT_DO_NOT_USE, friendlyaudcomp);
+    IFilterMapper2_CreateCategory(pMapper, &CLSID_AudioRendererCategory, MERIT_NORMAL, friendlyaudrend);
+    IFilterMapper2_CreateCategory(pMapper, &CLSID_MidiRendererCategory, MERIT_NORMAL, friendlymidirend);
+    IFilterMapper2_CreateCategory(pMapper, &CLSID_TransmitCategory, MERIT_DO_NOT_USE, friendlyextrend);
+    IFilterMapper2_CreateCategory(pMapper, &CLSID_DeviceControlCategory, MERIT_DO_NOT_USE, friendlydevctrl);
+
+    IFilterMapper2_Release(pMapper);
+    CoUninitialize();
+    }
+#endif
+
+//    CDeviceMoniker
+    if (SUCCEEDED(res))
+    {
+	res = StringFromCLSID(&CLSID_CDeviceMoniker, &pszClsidDevMon);
+    }
+    if (SUCCEEDED(res))
+    {
+        res = RegOpenKeyW(HKEY_CLASSES_ROOT, clsid_keyname, &hkeyClsid)
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    if (SUCCEEDED(res))
+    {
+        res = RegOpenKeyW(hkeyClsid, pszClsidDevMon, &hkey1)
+	       == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    if (SUCCEEDED(res))
+    {
+        const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
+        res = RegCreateKeyW(hkey1, wszProgID, &hkey2)
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    if (SUCCEEDED(res))
+    {
+        res = RegSetValueW(hkey2, NULL, REG_SZ, device_1, (lstrlenW(device_1) + 1) * sizeof(WCHAR))
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    RegCloseKey(hkey2);
+    if (SUCCEEDED(res))
+    {
+        const WCHAR wszVProgID[] = {'V','e','r','s','i','o','n','I','n','d','e','p','e','d','e','n','t','P','r','o','g','I','D',0};
+	res = RegCreateKeyW(hkey1, wszVProgID, &hkey2)
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    if (SUCCEEDED(res))
+    {
+        res = RegSetValueW(hkey2, NULL, REG_SZ, device, (lstrlenW(device) + 1) * sizeof(WCHAR))
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    RegCloseKey(hkey2);
+    RegCloseKey(hkey1);
+    if (SUCCEEDED(res))
+    {
+        res = RegCreateKeyW(hkeyClsid, device, &hkey1)
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    if (SUCCEEDED(res))
+    {
+        res = RegCreateKeyW(hkey1, clsid_keyname, &hkey2)
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    if (SUCCEEDED(res))
+    {
+        res = RegSetValueW(hkey2, NULL, REG_SZ, pszClsidDevMon, (lstrlenW(pszClsidDevMon) + 1) * sizeof(WCHAR))
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    RegCloseKey(hkey2);
+    RegCloseKey(hkey1);
+
+    if (SUCCEEDED(res))
+    {
+        res = RegCreateKeyW(hkeyClsid, device_1, &hkey1)
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    if (SUCCEEDED(res))
+    {
+        res = RegCreateKeyW(hkey1, clsid_keyname, &hkey2)
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    if (SUCCEEDED(res))
+    {
+        res = RegSetValueW(hkey2, NULL, REG_SZ, pszClsidDevMon, (lstrlenW(pszClsidDevMon) + 1) * sizeof(WCHAR))
+	      == ERROR_SUCCESS ? S_OK : E_FAIL;
+    }
+    RegCloseKey(hkey2);
+    RegCloseKey(hkey1);
+
+    RegCloseKey(hkeyClsid);
+
+    if (pszClsidDevMon)
+        CoTaskMemFree(pszClsidDevMon);
+
+    return res;
+}
+
+/***********************************************************************
+ *		DllUnregisterServer (DEVENUM.@)
+ */
+HRESULT WINAPI DEVENUM_DllUnregisterServer()
+{
+/*    WCHAR dll_module[MAX_PATH];
+
+    TRACE("\n");
+
+    if (!GetModuleFileNameW(DEVENUM_hInstance, dll_module,
+			    sizeof dll_module / sizeof(WCHAR)))
+	return HRESULT_FROM_WIN32(GetLastError());
+
+    regsvr_entries[4].value = dll_module;
+    return regsvr_unregister(regsvr_entries, 6);*/
+	FIXME("stub!\n");
+	return E_FAIL;
+}
+
+static HRESULT register_clsids(int count, const register_info * pRegInfo, LPCWSTR pszThreadingModel)
+{
+    HRESULT res = S_OK;
+    WCHAR dll_module[MAX_PATH];
+    LPOLESTR clsidString;
+    HKEY hkeyClsid;
+    HKEY hkeySub;
+    HKEY hkeyInproc32;
+    HKEY hkeyInstance = NULL;
+    int i;
+    const WCHAR wcszInproc32[] = {'I','n','p','r','o','c','S','e','r','e','r','3','2',0};
+    const WCHAR wcszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
+
+    res = RegOpenKeyW(HKEY_CLASSES_ROOT, clsid_keyname, &hkeyClsid)
+          == ERROR_SUCCESS ? S_OK : E_FAIL;
+
+    if (!GetModuleFileNameW(DEVENUM_hInstance, dll_module,
+			    sizeof dll_module / sizeof(WCHAR)))
+	return HRESULT_FROM_WIN32(GetLastError());
+
+    for (i = 0; i < count; i++)
+    {
+        if (SUCCEEDED(res))
+	{
+	    res = StringFromCLSID(pRegInfo[i].clsid, &clsidString);
+	}
+	if (SUCCEEDED(res))
+	{
+	    res = RegCreateKeyW(hkeyClsid, clsidString, &hkeySub)
+	          == ERROR_SUCCESS ? S_OK : E_FAIL;
+	}
+	if (pRegInfo[i].instance && SUCCEEDED(res))
+	{
+	    res = RegCreateKeyW(hkeySub, wszInstanceKeyName, &hkeyInstance)
+	          == ERROR_SUCCESS ? S_OK : E_FAIL;
+            RegCloseKey(hkeyInstance);
+	}
+	if (SUCCEEDED(res))
+	{
+	    RegSetValueW(hkeySub,
+	                 NULL,
+		         REG_SZ,
+	                 pRegInfo->friendly_name ? pRegInfo[i].friendly_name : clsidString,
+		         (lstrlenW(pRegInfo[i].friendly_name ? pRegInfo->friendly_name : clsidString) + 1) * sizeof(WCHAR));
+	    res = RegCreateKeyW(hkeySub, wcszInproc32, &hkeyInproc32)
+	          == ERROR_SUCCESS ? S_OK : E_FAIL;
+	}
+	if (SUCCEEDED(res))
+	{
+	    RegSetValueW(hkeyInproc32,
+	                 NULL,
+	                 REG_SZ,
+			 dll_module,
+			 (lstrlenW(dll_module) + 1) * sizeof(WCHAR));
+	    RegSetValueExW(hkeyInproc32,
+	                   wcszThreadingModel,
+			   0,
+			   REG_SZ,
+			   (LPVOID)pszThreadingModel,
+			   (lstrlenW(pszThreadingModel) + 1) * sizeof(WCHAR));
+            RegCloseKey(hkeyInproc32);
+        }
+        RegCloseKey(hkeySub);
+	CoTaskMemFree(clsidString);
+	clsidString = NULL;
+    }
+
+    RegCloseKey(hkeyClsid);
+
+    return res;
+}
Index: wine/ole/uuid.c
===================================================================
RCS file: /home/wine/wine/ole/uuid.c,v
retrieving revision 1.13
diff -u -r1.13 uuid.c
--- wine/ole/uuid.c	13 Aug 2002 18:20:24 -0000	1.13
+++ wine/ole/uuid.c	11 Dec 2002 20:29:20 -0000
@@ -50,6 +50,8 @@
 #include "comcat.h"
 #include "urlmon.h"

+#include "devenum.h"
+
 /* FIXME: cguids declares GUIDs but does not define their values */
-------------- next part --------------
--- /dev/null	Mon Jun 24 01:53:01 2002
+++ createdevenum.c	Tue Dec 10 21:31:14 2002
@@ -0,0 +1,216 @@
+/*
+ *	ICreateDevEnum implementation for DEVENUM.dll
+ *
+ * Copyright (C) 2002 Robert Shearman
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "devenum_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(devenum);
+
+extern ICOM_VTABLE(IEnumMoniker) IEnumMoniker_Vtbl;
+
+const WCHAR wszInstanceKeyName[] ={'I','n','s','t','a','n','c','e',0};
+const WCHAR wszRegSeperator[] =   {'\\', 0 };
+const WCHAR wszActiveMovieKey[] = {'S','o','f','t','w','a','r','e','\\',
+                                   'M','i','c','r','o','s','o','f','t','\\',
+                                   'A','c','t','i','v','e','M','o','v','i','e','\\',
+                                   'd','e','v','e','n','u','m','\\',0};
+
+static ULONG WINAPI DEVENUM_ICreateDevEnum_AddRef(LPCREATEDEVENUM iface);
+static HRESULT DEVENUM_CreateSpecialCategories();
+
+/**********************************************************************
+ * DEVENUM_ICreateDevEnum_QueryInterface (also IUnknown)
+ */
+static HRESULT WINAPI DEVENUM_ICreateDevEnum_QueryInterface(
+    LPCREATEDEVENUM iface,
+    REFIID riid,
+    LPVOID *ppvObj)
+{
+    ICOM_THIS(CreateDevEnumImpl, iface);
+    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+    if (This == NULL || ppvObj == NULL) return E_POINTER;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+	IsEqualGUID(riid, &IID_ICreateDevEnum))
+    {
+	*ppvObj = (LPVOID)iface;
+	DEVENUM_ICreateDevEnum_AddRef(iface);
+	return S_OK;
+    }
+
+    FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+/**********************************************************************
+ * DEVENUM_ICreateDevEnum_AddRef (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_ICreateDevEnum_AddRef(LPCREATEDEVENUM iface)
+{
+    ICOM_THIS(CreateDevEnumImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    if (InterlockedIncrement(&This->ref) == 1) {
+	InterlockedIncrement(&dll_ref);
+    }
+    return This->ref;
+}
+
+/**********************************************************************
+ * DEVENUM_ICreateDevEnum_Release (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_ICreateDevEnum_Release(LPCREATEDEVENUM iface)
+{
+    ICOM_THIS(CreateDevEnumImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    if (InterlockedDecrement(&This->ref) == 0) {
+	InterlockedDecrement(&dll_ref);
+    }
+    return This->ref;
+}
+
+/**********************************************************************
+ * DEVENUM_ICreateDevEnum_CreateClassEnumerator
+ */
+HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator(
+    LPCREATEDEVENUM iface,
+    REFCLSID clsidDeviceClass,
+    IEnumMoniker **ppEnumMoniker,
+    DWORD dwFlags)
+{
+    WCHAR wszRegKey[MAX_PATH];
+    EnumMonikerImpl * pEnumMoniker;
+    HKEY hkey;
+    HKEY hbasekey;
+    ICOM_THIS(CreateDevEnumImpl, iface);
+
+    TRACE("(%p)->(..., %p, %lx)\n\tDeviceClass:\t%s\n", This, ppEnumMoniker, dwFlags, debugstr_guid(clsidDeviceClass));
+
+    if (!ppEnumMoniker)
+        return E_POINTER;
+
+    *ppEnumMoniker = NULL;
+
+    if (IsEqualGUID(clsidDeviceClass, &CLSID_AudioRendererCategory) ||
+        IsEqualGUID(clsidDeviceClass, &CLSID_MidiRendererCategory))
+    {
+        if (FAILED(DEVENUM_CreateSpecialCategories()))
+             return E_FAIL;
+
+        hbasekey = HKEY_CURRENT_USER;
+        strcpyW(wszRegKey, wszActiveMovieKey);
+
+        if (!StringFromGUID2(clsidDeviceClass, wszRegKey + strlenW(wszRegKey), MAX_PATH - strlenW(wszRegKey)))
+            return E_OUTOFMEMORY;
+    }
+    else
+    {
+        hbasekey = HKEY_CLASSES_ROOT;
+        strcpyW(wszRegKey, clsid_keyname);
+        strcatW(wszRegKey, wszRegSeperator);
+
+        if (!StringFromGUID2(clsidDeviceClass, wszRegKey + CLSID_STR_LEN, MAX_PATH - CLSID_STR_LEN))
+            return E_OUTOFMEMORY;
+
+        strcatW(wszRegKey, wszRegSeperator);
+        strcatW(wszRegKey, wszInstanceKeyName);
+    }
+
+    if (RegOpenKeyW(hbasekey, wszRegKey, &hkey) != ERROR_SUCCESS)
+    {
+        FIXME("Category %s not found\n", debugstr_guid(clsidDeviceClass));
+        return S_FALSE;
+    }
+
+    pEnumMoniker = (EnumMonikerImpl *)CoTaskMemAlloc(sizeof(EnumMonikerImpl));
+    if (!pEnumMoniker)
+        return E_OUTOFMEMORY;
+
+    pEnumMoniker->lpVtbl = &IEnumMoniker_Vtbl;
+    pEnumMoniker->ref = 0;
+    pEnumMoniker->index = 0;
+    pEnumMoniker->hkey = hkey;
+
+    *ppEnumMoniker = (IEnumMoniker *)pEnumMoniker;
+
+    return S_OK;
+}
+
+/**********************************************************************
+ * ICreateDevEnum_Vtbl
+ */
+static ICOM_VTABLE(ICreateDevEnum) ICreateDevEnum_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    DEVENUM_ICreateDevEnum_QueryInterface,
+    DEVENUM_ICreateDevEnum_AddRef,
+    DEVENUM_ICreateDevEnum_Release,
+    DEVENUM_ICreateDevEnum_CreateClassEnumerator,
+};
+
+/**********************************************************************
+ * static CreateDevEnum instance
+ */
+CreateDevEnumImpl DEVENUM_CreateDevEnum = { &ICreateDevEnum_Vtbl, 0 };
+
+
+/**********************************************************************
+ * CreateSpecialCategories (INTERNAL)
+ *
+ * Creates the keys in the registry for the dynamic categories
+ */
+static HRESULT DEVENUM_CreateSpecialCategories()
+{
+    HRESULT res = S_OK;
+#ifdef FILTERMAPPER2_IMPLEMENTED
+    IFilterMapper2 * pMapper = NULL;
+
+    res = CoCreateInstance(CLSID_FilerMapper2, NULL, CLSCTX_INPROC
+                           IID_IFilterMapper2, (void **) &pMapper);
+    /*
+     * Fill in info for out devices
+     */
+    if (SUCCEEDED(res))
+    {
+        WAVEOUTCAPS caps;
+	UINT numDevs = waveOutGetNumDevs();
+
+	for (UINT i = 0; i < numDevs; i++)
+	{
+	    if (waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
+	        == MMSYSERR_NOERROR)
+	    {
+	        IFilterMapper2_RegisterDevice(pMapper, clsidFilter...
+	    }
+	}
+    }
+
+    if (pMapper)
+        IUnknown_Release((LPUKNOWN)pMapper);
+#endif
+    return res;
+}
-------------- next part --------------
--- /dev/null	Mon Jun 24 01:53:01 2002
+++ devenum_private.h	Mon Dec  9 04:41:07 2002
@@ -0,0 +1,99 @@
+/*
+ *	includes for devenum.dll
+ *
+ * Copyright (C) 2002 John K. Hohm
+ * Copyright (C) 2002 Robert Shearman
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+
+#include "ole2.h"
+#include "wine/obj_devenum.h"
+#include "wine/obj_oleaut.h"
+#include "wine/obj_property.h"
+#include "wine/unicode.h"
+#include "uuids.h"
+
+/**********************************************************************
+ * Dll lifetime tracking declaration for devenum.dll
+ */
+extern DWORD dll_ref;
+
+/**********************************************************************
+ * ClassFactory declaration for devenum.dll
+ */
+typedef struct
+{
+    /* IUnknown fields */
+    ICOM_VFIELD(IClassFactory);
+    DWORD ref;
+} ClassFactoryImpl;
+
+typedef struct
+{
+    ICOM_VFIELD(ICreateDevEnum);
+    DWORD ref;
+} CreateDevEnumImpl;
+
+typedef struct
+{
+    ICOM_VFIELD(IEnumMoniker);
+    DWORD ref;
+    DWORD index;
+    HKEY hkey;
+} EnumMonikerImpl;
+
+typedef struct
+{
+    ICOM_VFIELD(IMoniker); // lpVtbl
+
+    ICOM_VTABLE(IROTData)* lpVtbl2;
+
+    DWORD ref;
+    HKEY hkey;
+} MediaCatMoniker;
+
+typedef struct
+{
+    ICOM_VFIELD(IPropertyBag);
+    DWORD ref;
+    HKEY hkey;
+} RegPropBagImpl;
+
+typedef struct
+{
+    ICOM_VFIELD(IParseDisplayName);
+    DWORD ref;
+} ParseDisplayNameImpl;
+
+void CreateMonikerVtbl(MediaCatMoniker * pMoniker);
+
+extern ClassFactoryImpl DEVENUM_ClassFactory;
+extern CreateDevEnumImpl DEVENUM_CreateDevEnum;
+extern ParseDisplayNameImpl DEVENUM_ParseDisplayName;
+
+/**********************************************************************
+ * Global string constant declarations
+ */
+extern const WCHAR clsid_keyname[6];
+extern const WCHAR wszInstanceKeyName[];
+extern const WCHAR wszRegSeperator[];
+#define CLSID_STR_LEN (sizeof(clsid_keyname) / sizeof(WCHAR))
-------------- next part --------------
--- /dev/null	Mon Jun 24 01:53:01 2002
+++ factory.c	Mon Dec  9 03:09:38 2002
@@ -0,0 +1,155 @@
+/*
+ *	ClassFactory implementation for DEVENUM.dll
+ *
+ * Copyright (C) 2002 John K. Hohm
+ * Copyright (C) 2002 Robert Shearman
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "devenum_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(devenum);
+
+/**********************************************************************
+ * DEVENUM_IClassFactory_QueryInterface (also IUnknown)
+ */
+static HRESULT WINAPI DEVENUM_IClassFactory_QueryInterface(
+    LPCLASSFACTORY iface,
+    REFIID riid,
+    LPVOID *ppvObj)
+{
+    ICOM_THIS(ClassFactoryImpl, iface);
+    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+    if (This == NULL || ppvObj == NULL) return E_POINTER;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+	IsEqualGUID(riid, &IID_IClassFactory))
+    {
+	*ppvObj = (LPVOID)iface;
+	IClassFactory_AddRef(iface);
+	return S_OK;
+    }
+    if (IsEqualGUID(riid, &IID_IParseDisplayName))
+    {
+        return IClassFactory_CreateInstance(iface, NULL, riid, ppvObj);
+    }
+
+    FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+/**********************************************************************
+ * DEVENUM_IClassFactory_AddRef (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IClassFactory_AddRef(LPCLASSFACTORY iface)
+{
+    ICOM_THIS(ClassFactoryImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    This->ref++;
+
+    if (InterlockedIncrement(&This->ref) == 1) {
+	InterlockedIncrement(&dll_ref);
+    }
+    return This->ref;
+}
+
+/**********************************************************************
+ * DEVENUM_IClassFactory_Release (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IClassFactory_Release(LPCLASSFACTORY iface)
+{
+    ICOM_THIS(ClassFactoryImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    if (InterlockedDecrement(&This->ref) == 0) {
+	InterlockedDecrement(&dll_ref);
+    }
+    return This->ref;
+}
+
+/**********************************************************************
+ * DEVENUM_IClassFactory_CreateInstance
+ */
+static HRESULT WINAPI DEVENUM_IClassFactory_CreateInstance(
+    LPCLASSFACTORY iface,
+    LPUNKNOWN pUnkOuter,
+    REFIID riid,
+    LPVOID *ppvObj)
+{
+    ICOM_THIS(ClassFactoryImpl, iface);
+    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+    if (This == NULL || ppvObj == NULL) return E_POINTER;
+
+    /* Don't support aggregation (Windows doesn't) */
+    if (pUnkOuter != NULL) return CLASS_E_NOAGGREGATION;
+
+    if (IsEqualGUID(&IID_ICreateDevEnum, riid))
+    {
+        *ppvObj = &DEVENUM_CreateDevEnum;
+        return S_OK;
+    }
+    if (IsEqualGUID(&IID_IParseDisplayName, riid))
+    {
+        *ppvObj = &DEVENUM_ParseDisplayName;
+        return S_OK;
+    }
+
+    return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+/**********************************************************************
+ * DEVENUM_IClassFactory_LockServer
+ */
+static HRESULT WINAPI DEVENUM_IClassFactory_LockServer(
+    LPCLASSFACTORY iface,
+    BOOL fLock)
+{
+    TRACE("\n");
+
+    if (fLock != FALSE) {
+	IClassFactory_AddRef(iface);
+    } else {
+	IClassFactory_Release(iface);
+    }
+    return S_OK;
+}
+
+/**********************************************************************
+ * IClassFactory_Vtbl
+ */
+static ICOM_VTABLE(IClassFactory) IClassFactory_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    DEVENUM_IClassFactory_QueryInterface,
+    DEVENUM_IClassFactory_AddRef,
+    DEVENUM_IClassFactory_Release,
+    DEVENUM_IClassFactory_CreateInstance,
+    DEVENUM_IClassFactory_LockServer
+};
+
+/**********************************************************************
+ * static ClassFactory instance
+ */
+ClassFactoryImpl DEVENUM_ClassFactory = { &IClassFactory_Vtbl, 0 };
-------------- next part --------------
--- /dev/null	Mon Jun 24 01:53:01 2002
+++ mediacatenum.c	Mon Dec  9 04:58:57 2002
@@ -0,0 +1,846 @@
+/*
+ *	IEnumMoniker implementation for DEVENUM.dll
+ *
+ * Copyright (C) 2002 Robert Shearman
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "devenum_private.h"
+
+#include "oleauto.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(devenum);
+
+static ULONG WINAPI DEVENUM_IEnumMoniker_AddRef(LPENUMMONIKER iface);
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Hash(LPMONIKER iface, DWORD* pdwHash);
+static ULONG WINAPI DEVENUM_IMediaCatMoniker_AddRef(LPMONIKER iface);
+static ULONG WINAPI DEVENUM_IPropertyBag_AddRef(LPPROPERTYBAG iface);
+
+static HRESULT WINAPI DEVENUM_IPropertyBag_QueryInterface(
+    LPPROPERTYBAG iface,
+    REFIID riid,
+    LPVOID *ppvObj)
+{
+    ICOM_THIS(RegPropBagImpl, iface);
+    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+    if (This == NULL || ppvObj == NULL) return E_POINTER;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IPropertyBag))
+    {
+	*ppvObj = (LPVOID)iface;
+	DEVENUM_IPropertyBag_AddRef(iface);
+	return S_OK;
+    }
+
+    FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+/**********************************************************************
+ * DEVENUM_IPropertyBag_AddRef (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IPropertyBag_AddRef(LPPROPERTYBAG iface)
+{
+    ICOM_THIS(RegPropBagImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    return ++This->ref;
+}
+
+/**********************************************************************
+ * DEVENUM_IPropertyBag_Release (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IPropertyBag_Release(LPPROPERTYBAG iface)
+{
+    ICOM_THIS(RegPropBagImpl, iface);
+    ULONG ref;
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    ref = --This->ref;
+    if (ref == 0) {
+	RegCloseKey(This->hkey);
+	CoTaskMemFree(This);
+    }
+    return ref;
+}
+
+WCHAR wszNull = '\0';
+
+static HRESULT WINAPI DEVENUM_IPropertyBag_Read(
+    LPPROPERTYBAG iface,
+    LPCOLESTR pszPropName,
+    VARIANT* pVar,
+    IErrorLog* pErrorLog)
+{
+    WCHAR wszData[MAX_PATH + 1];
+    LONG received = MAX_PATH + 1;
+    DWORD type = 0;
+    ICOM_THIS(RegPropBagImpl, iface);
+    HRESULT res = S_OK;
+    const WCHAR wszMerit[] = {'M','e','r','i','t',0};
+    const WCHAR wszFilterData[] = {'F','i','l','t','e','r','D','a','t','a',0};
+    TRACE("(%p)->(%s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog);
+
+    if (!pszPropName || !pVar)
+        return E_POINTER;
+
+    if (RegQueryValueExW(This->hkey, pszPropName, NULL, &type, (LPVOID)wszData, &received) != ERROR_SUCCESS)
+        res = E_INVALIDARG;
+
+    if (FAILED(res) && !strcmpW(pszPropName, wszMerit))
+    {
+        TRACE("correcting missing Merit\n");
+        type = REG_DWORD;
+	*(DWORD *)wszData = 0x200000;
+	received = 4;
+	res = S_OK;
+    }
+    else if (FAILED(res) && !strcmpW(pszPropName, wszFilterData))
+    {
+        TRACE("correcting missing FilterData\n");
+        type = REG_BINARY;
+	*(DWORD *)wszData = 0x000000;
+	received = 4;
+	res = S_OK;
+    }
+
+    if (SUCCEEDED(res))
+    {
+        TRACE("%ld, %s\n", received, debugstr_w(wszData));
+        switch (type)
+	{
+	case REG_SZ:
+            switch (V_VT(pVar))
+            {
+	    case VT_LPWSTR:
+	        V_UNION(pVar, bstrVal) = CoTaskMemAlloc(received * sizeof(WCHAR));
+		strcpyW(V_UNION(pVar, bstrVal), wszData);
+		return S_OK;
+            case VT_EMPTY:
+                V_VT(pVar) = VT_BSTR;
+            // fall through
+            case VT_BSTR:
+                V_UNION(pVar, bstrVal) = SysAllocStringLen(wszData, received - 1);
+                return S_OK;
+            }
+            break;
+        case REG_DWORD:
+	    TRACE("REG_DWORD: %lx\n", *(DWORD *)wszData);
+            switch (V_VT(pVar))
+            {
+            case VT_EMPTY:
+                V_VT(pVar) = VT_I4;
+                // fall through
+            case VT_I4:
+            case VT_UI4:
+                V_UNION(pVar, ulVal) = *(DWORD *)wszData;
+		return S_OK;
+	    }
+	    break;
+	case REG_BINARY:
+	{
+            SAFEARRAYBOUND bound;
+	    void * pArrayElements;
+	    bound.lLbound = 0;
+	    bound.cElements = received;
+	    TRACE("REG_BINARY: len = %ld\n", received);
+	    switch (V_VT(pVar))
+	    {
+	    case VT_EMPTY:
+            case VT_ARRAY | VT_UI1:
+	    	if (!(V_UNION(pVar, parray) = SafeArrayCreate(VT_UI4, 1, &bound)))
+                    return E_OUTOFMEMORY;
+	        break;
+	    default:
+		return E_FAIL;
+	    }
+
+	    SafeArrayAccessData(V_UNION(pVar, parray), &pArrayElements);
+	    CopyMemory(pArrayElements, wszData, received);
+	    SafeArrayUnaccessData(V_UNION(pVar, parray));
+	    return S_OK;
+	}
+	}
+        FIXME("Variant type %x not supported for regtype %lx\n", V_VT(pVar), type);
+        return E_FAIL;
+    }
+
+    FIXME("RegQueryValue failed\n");
+    return res;
+}
+
+static HRESULT WINAPI DEVENUM_IPropertyBag_Write(
+    LPPROPERTYBAG iface,
+    LPCOLESTR pszPropName,
+    VARIANT* pVar)
+{
+    ICOM_THIS(RegPropBagImpl, iface);
+    FIXME("(%p)->(%s, %p)\n", This, debugstr_w(pszPropName), pVar);
+
+    return E_FAIL;
+}
+
+static ICOM_VTABLE(IPropertyBag) IPropertyBag_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    DEVENUM_IPropertyBag_QueryInterface,
+    DEVENUM_IPropertyBag_AddRef,
+    DEVENUM_IPropertyBag_Release,
+    DEVENUM_IPropertyBag_Read,
+    DEVENUM_IPropertyBag_Write
+};
+
+
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_QueryInterface(
+    LPMONIKER iface,
+    REFIID riid,
+    LPVOID *ppvObj)
+{
+    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+    if (This == NULL || ppvObj == NULL) return E_POINTER;
+
+    *ppvObj = NULL;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IPersist) ||
+	IsEqualGUID(riid, &IID_IPersistStream) ||
+	IsEqualGUID(riid, &IID_IMoniker))
+    {
+	*ppvObj = (LPVOID)iface;
+	DEVENUM_IMediaCatMoniker_AddRef(iface);
+	return S_OK;
+    }
+
+
+    if (IsEqualGUID(riid, &IID_IROTData))
+    {
+        *ppvObj = (LPVOID)&(This->lpVtbl2);
+	DEVENUM_IMediaCatMoniker_AddRef(iface);
+	return S_OK;
+    }
+
+    FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+/**********************************************************************
+ * DEVENUM_IMediaCatMoniker_AddRef (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IMediaCatMoniker_AddRef(LPMONIKER iface)
+{
+    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    return ++This->ref;
+}
+
+/**********************************************************************
+ * DEVENUM_IMediaCatMoniker_Release (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IMediaCatMoniker_Release(LPMONIKER iface)
+{
+    ICOM_THIS(MediaCatMoniker, iface);
+    ULONG ref;
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    ref = --This->ref;
+    if (ref == 0) {
+	RegCloseKey(This->hkey);
+	CoTaskMemFree(This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetClassID(
+    LPMONIKER iface,
+    CLSID* pClassID)
+{
+    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p)->(%p)\n", This, pClassID);
+
+    if (pClassID == NULL)
+        return E_POINTER;
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsDirty(LPMONIKER iface)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("()\n");
+
+    return S_FALSE;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Load(LPMONIKER iface, IStream* pStm)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p)\n", pStm);
+
+    return E_FAIL;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Save(LPMONIKER iface, IStream* pStm, BOOL fClearDirty)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p, %s)\n", pStm, fClearDirty ? "true" : "false");
+
+    return STG_E_CANTSAVE;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetSizeMax(
+    LPMONIKER iface,
+    ULARGE_INTEGER* pcbSize)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p)\n", pcbSize);
+
+//    *pcbSize = 0;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToObject(
+    LPMONIKER iface,
+    IBindCtx* pbc,
+    IMoniker* pmkToLeft,
+    REFIID riidResult,
+    void** ppvResult)
+{
+    IUnknown * pObj = NULL;
+    IPropertyBag * pProp = NULL;
+    IRunningObjectTable * prot = NULL;
+    CLSID clsID;
+    VARIANT var;
+    HRESULT res = E_FAIL;
+
+    ICOM_THIS(MediaCatMoniker, iface);
+
+    VariantClear(&var);
+
+    TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riidResult), ppvResult);
+
+    *ppvResult = NULL;
+
+    if(pmkToLeft==NULL)
+    {
+            /* first activation of this class */
+            res=IMoniker_BindToStorage(iface, NULL, NULL, &IID_IPropertyBag, (void**)&pProp);
+	    if (SUCCEEDED(res))
+	    {
+	        V_VT(&var) = VT_LPWSTR;
+	        res = IPropertyBag_Read(pProp, clsid_keyname, &var, NULL);
+	    }
+	    if (SUCCEEDED(res))
+	    {
+	        res = CLSIDFromString(V_UNION(&var,bstrVal), &clsID);
+                TRACE("2: 0x%lx\n", res);
+		CoTaskMemFree(V_UNION(&var, bstrVal));
+	    }
+            if (SUCCEEDED(res))
+            {
+                res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IUnknown,(void**)&pObj);
+                TRACE("3: 0x%lx\n", res);
+            }
+    }
+
+    if (pObj!=NULL)
+    {
+        /* get the requested interface from the loaded class */
+        res= IUnknown_QueryInterface(pObj,riidResult,ppvResult);
+
+        IBindCtx_RegisterObjectBound(pbc,(IUnknown*)*ppvResult);
+
+//        IUnknown_Release(pObj);
+    }
+
+    if (prot)
+        IRunningObjectTable_Release(prot);
+
+    if (pProp)
+    {
+        IPropertyBag_Release(pProp);
+    }
+
+    TRACE("<- 0x%lx\n", res);
+
+    return res;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToStorage(
+    LPMONIKER iface,
+    IBindCtx* pbc,
+    IMoniker* pmkToLeft,
+    REFIID riid,
+    void** ppvObj)
+{
+    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObj);
+
+    *ppvObj = NULL;
+
+    if (pbc || pmkToLeft)
+        return MK_E_NOSTORAGE;
+
+    if (IsEqualGUID(riid, &IID_IPropertyBag))
+    {
+        RegPropBagImpl * rpb = CoTaskMemAlloc(sizeof(RegPropBagImpl));
+	if (!rpb)
+	    return E_OUTOFMEMORY;
+	rpb->lpVtbl = &IPropertyBag_Vtbl;
+	DuplicateHandle(GetCurrentProcess(), This->hkey, GetCurrentProcess(), (LPHANDLE)&(rpb->hkey), 0, 0, DUPLICATE_SAME_ACCESS);
+	rpb->ref = 0;
+	DEVENUM_IPropertyBag_AddRef((LPPROPERTYBAG)rpb);
+	*ppvObj = (LPVOID)rpb;
+	return S_OK;
+    }
+
+    return MK_E_NOSTORAGE;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Reduce(
+    LPMONIKER iface,
+    IBindCtx* pbc,
+    DWORD dwReduceHowFar,
+    IMoniker** ppmkToLeft,
+    IMoniker** ppmkReduced)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p, %ld, %p, %p)\n", pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
+
+    if (ppmkToLeft)
+        *ppmkToLeft = NULL;
+    *ppmkReduced = iface;
+
+    return MK_S_REDUCED_TO_SELF;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ComposeWith(
+    LPMONIKER iface,
+    IMoniker* pmkRight,
+    BOOL fOnlyIfNotGeneric,
+    IMoniker** ppmkComposite)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    FIXME("(%p, %s, %p)\n", pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite);
+
+    // FIXME: use CreateGenericComposite
+    *ppmkComposite = NULL;
+
+    return E_FAIL;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Enum(
+    LPMONIKER iface,
+    BOOL fForward,
+    IEnumMoniker** ppenumMoniker)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%s, %p)\n", fForward ? "true" : "false", ppenumMoniker);
+
+    *ppenumMoniker = NULL;
+
+    return E_UNEXPECTED;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsEqual(
+    LPMONIKER iface,
+    IMoniker* pmkOtherMoniker)
+{
+    DWORD thisHash;
+    DWORD otherHash;
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p)\n", pmkOtherMoniker);
+    if (FAILED(DEVENUM_IMediaCatMoniker_Hash(iface, &thisHash)) ||
+        FAILED(IMoniker_Hash(pmkOtherMoniker, &otherHash)))
+        return E_FAIL;
+    return (thisHash == otherHash) ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Hash(
+    LPMONIKER iface,
+    DWORD* pdwHash)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    FIXME("(%p)\n", pdwHash);
+
+    return E_FAIL;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsRunning(
+    LPMONIKER iface,
+    IBindCtx* pbc,
+    IMoniker* pmkToLeft,
+    IMoniker* pmkNewlyRunning)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    FIXME("(%p, %p, %p)\n", pbc, pmkToLeft, pmkNewlyRunning);
+
+    return S_FALSE;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetTimeOfLastChange(
+    LPMONIKER iface,
+    IBindCtx* pbc,
+    IMoniker* pmkToLeft,
+    FILETIME* pFileTime)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, pFileTime);
+
+    pFileTime->dwLowDateTime = 0xFFFFFFFF;
+    pFileTime->dwHighDateTime = 0x7FFFFFFF;
+
+    return MK_E_UNAVAILABLE;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Inverse(
+    LPMONIKER iface,
+    IMoniker** ppmk)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p)\n", ppmk);
+
+    *ppmk = NULL;
+
+    return MK_E_NOINVERSE;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_CommonPrefixWith(
+    LPMONIKER iface,
+    IMoniker* pmkOtherMoniker,
+    IMoniker** ppmkPrefix)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p, %p)\n", pmkOtherMoniker, ppmkPrefix);
+
+    *ppmkPrefix = NULL;
+
+    return MK_E_NOPREFIX;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_RelativePathTo(
+    LPMONIKER iface,
+    IMoniker* pmkOther,
+    IMoniker** ppmkRelPath)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p, %p)\n", pmkOther, ppmkRelPath);
+
+    *ppmkRelPath = pmkOther;
+
+    return MK_S_HIM;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetDisplayName(
+    LPMONIKER iface,
+    IBindCtx* pbc,
+    IMoniker* pmkToLeft,
+    LPOLESTR* ppszDisplayName)
+{
+    // FIXME: shouldn't this be the weird stuff we have to parse in IParseDisplayName?
+    ICOM_THIS(MediaCatMoniker, iface);
+    WCHAR wszBuffer[MAX_PATH];
+    const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
+    LONG received = sizeof(wszFriendlyName);
+
+    TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, ppszDisplayName);
+
+    *ppszDisplayName = NULL;
+
+    if (RegQueryValueW(This->hkey, wszFriendlyName, wszBuffer, &received) == ERROR_SUCCESS)
+    {
+        *ppszDisplayName = CoTaskMemAlloc(received);
+	strcpyW(*ppszDisplayName, wszBuffer);
+	return S_OK;
+    }
+
+    return E_FAIL;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ParseDisplayName(
+    LPMONIKER iface,
+    IBindCtx* pbc,
+    IMoniker* pmkToLeft,
+    LPOLESTR pszDisplayName,
+    ULONG* pchEaten,
+    IMoniker** ppmkOut)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p, %p, %s, %p, %p)\n", pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
+
+    *pchEaten = 0;
+    *ppmkOut = NULL;
+
+    return MK_E_SYNTAX;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsSystemMoniker(
+    LPMONIKER iface,
+    DWORD* pdwMksys)
+{
+//    ICOM_THIS(MediaCatMoniker, iface);
+    TRACE("(%p)\n", pdwMksys);
+
+    return S_FALSE;
+}
+
+static HRESULT WINAPI DEVENUM_IROTData_QueryInterface(
+    IROTData* iface,
+    REFIID riid,
+    LPVOID *ppvObj)
+{
+    ICOM_THIS_From_IROTData(MediaCatMoniker, iface);
+
+    return DEVENUM_IMediaCatMoniker_QueryInterface((LPMONIKER)This, riid, ppvObj);
+}
+
+static ULONG WINAPI DEVENUM_IROTData_AddRef(IROTData* iface)
+{
+    ICOM_THIS_From_IROTData(MediaCatMoniker, iface);
+
+    return DEVENUM_IMediaCatMoniker_AddRef((LPMONIKER)This);
+}
+
+static ULONG WINAPI DEVENUM_IROTData_Release(IROTData* iface)
+{
+    ICOM_THIS_From_IROTData(MediaCatMoniker, iface);
+
+    return DEVENUM_IMediaCatMoniker_Release((LPMONIKER)This);
+}
+
+static HRESULT WINAPI DEVENUM_IROTData_GetComparisonData(IROTData* iface,
+                                                         BYTE* pbData,
+                                                         ULONG cbMax,
+                                                         ULONG* pcbData)
+{
+    ICOM_THIS_From_IROTData(MediaCatMoniker, iface);
+    FIXME("(%p, %ld, %p): semi-stub\n", pbData, cbMax, pcbData);
+
+    *pcbData = /*sizeof(HKEY)*/ 100;
+
+    if (cbMax < sizeof(HKEY))
+    {
+        TRACE("<- E_OUTOFMEMORY\n");
+        return E_OUTOFMEMORY;
+    }
+
+    (HKEY *)pbData = This->hkey;
+    TRACE("<- S_OK\n");
+    return S_OK;
+}
+
+static ICOM_VTABLE(IMoniker) IMoniker_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    DEVENUM_IMediaCatMoniker_QueryInterface,
+    DEVENUM_IMediaCatMoniker_AddRef,
+    DEVENUM_IMediaCatMoniker_Release,
+    DEVENUM_IMediaCatMoniker_GetClassID,
+    DEVENUM_IMediaCatMoniker_IsDirty,
+    DEVENUM_IMediaCatMoniker_Load,
+    DEVENUM_IMediaCatMoniker_Save,
+    DEVENUM_IMediaCatMoniker_GetSizeMax,
+    DEVENUM_IMediaCatMoniker_BindToObject,
+    DEVENUM_IMediaCatMoniker_BindToStorage,
+    DEVENUM_IMediaCatMoniker_Reduce,
+    DEVENUM_IMediaCatMoniker_ComposeWith,
+    DEVENUM_IMediaCatMoniker_Enum,
+    DEVENUM_IMediaCatMoniker_IsEqual,
+    DEVENUM_IMediaCatMoniker_Hash,
+    DEVENUM_IMediaCatMoniker_IsRunning,
+    DEVENUM_IMediaCatMoniker_GetTimeOfLastChange,
+    DEVENUM_IMediaCatMoniker_Inverse,
+    DEVENUM_IMediaCatMoniker_CommonPrefixWith,
+    DEVENUM_IMediaCatMoniker_RelativePathTo,
+    DEVENUM_IMediaCatMoniker_GetDisplayName,
+    DEVENUM_IMediaCatMoniker_ParseDisplayName,
+    DEVENUM_IMediaCatMoniker_IsSystemMoniker
+};
+
+
+static ICOM_VTABLE(IROTData) IROTData_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    DEVENUM_IROTData_QueryInterface,
+    DEVENUM_IROTData_AddRef,
+    DEVENUM_IROTData_Release,
+    DEVENUM_IROTData_GetComparisonData
+};
+
+void CreateMonikerVtbl(MediaCatMoniker * pMoniker)
+{
+    pMoniker->lpVtbl = &IMoniker_Vtbl;
+    pMoniker->lpVtbl2 = &IROTData_Vtbl;
+}
+
+
+/**********************************************************************
+ * DEVENUM_IEnumMoniker_QueryInterface (also IUnknown)
+ */
+static HRESULT WINAPI DEVENUM_IEnumMoniker_QueryInterface(
+    LPENUMMONIKER iface,
+    REFIID riid,
+    LPVOID *ppvObj)
+{
+    ICOM_THIS(EnumMonikerImpl, iface);
+    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+    if (This == NULL || ppvObj == NULL) return E_POINTER;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+	IsEqualGUID(riid, &IID_IEnumMoniker))
+    {
+	*ppvObj = (LPVOID)iface;
+	DEVENUM_IEnumMoniker_AddRef(iface);
+	return S_OK;
+    }
+
+    FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+/**********************************************************************
+ * DEVENUM_IEnumMoniker_AddRef (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IEnumMoniker_AddRef(LPENUMMONIKER iface)
+{
+    ICOM_THIS(EnumMonikerImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    return ++This->ref;
+}
+
+/**********************************************************************
+ * DEVENUM_IEnumMoniker_Release (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IEnumMoniker_Release(LPENUMMONIKER iface)
+{
+    ICOM_THIS(EnumMonikerImpl, iface);
+    ULONG ref;
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    ref = --This->ref;
+    if (ref == 0) {
+	RegCloseKey(This->hkey);
+	CoTaskMemFree(This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(LPENUMMONIKER iface, ULONG celt, IMoniker ** rgelt, ULONG * pceltFetched)
+{
+    WCHAR buffer[MAX_PATH + 1];
+    LONG res;
+    ULONG fetched = 0;
+    MediaCatMoniker * pMoniker;
+    ICOM_THIS(EnumMonikerImpl, iface);
+    TRACE("(%ld, %p, %p)\n", celt, rgelt, pceltFetched);
+
+    while (fetched < celt)
+    {
+        res = RegEnumKeyW(This->hkey, This->index, buffer, sizeof(buffer) / sizeof(WCHAR));
+        if (res != ERROR_SUCCESS)
+        {
+            break;
+        }
+	pMoniker = CoTaskMemAlloc(sizeof(MediaCatMoniker));
+	DEVENUM_IMediaCatMoniker_AddRef((LPMONIKER)pMoniker);
+	if (!pMoniker)
+	    break;
+	CreateMonikerVtbl(pMoniker);
+	pMoniker->hkey = NULL;
+	if (RegOpenKeyW(This->hkey, buffer, &pMoniker->hkey) != ERROR_SUCCESS)
+	{
+	    DEVENUM_IMediaCatMoniker_Release((LPMONIKER)pMoniker);
+	    break;
+	}
+	rgelt[fetched] = (LPMONIKER)pMoniker;
+	fetched++;
+    }
+
+    This->index += fetched;
+
+    if (pceltFetched)
+        *pceltFetched = fetched;
+
+    if (fetched != celt)
+        return S_FALSE;
+    else
+        return S_OK;
+}
+
+static HRESULT WINAPI DEVENUM_IEnumMoniker_Skip(LPENUMMONIKER iface, ULONG celt)
+{
+    ICOM_THIS(EnumMonikerImpl, iface);
+    TRACE("(%ld)\n", celt);
+
+    This->index += celt;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI DEVENUM_IEnumMoniker_Reset(LPENUMMONIKER iface)
+{
+    ICOM_THIS(EnumMonikerImpl, iface);
+    TRACE("()\n");
+
+    This->index = 0;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI DEVENUM_IEnumMoniker_Clone(LPENUMMONIKER iface, IEnumMoniker ** ppenum)
+{
+//    ICOM_THIS(EnumMonikerImpl, iface);
+    FIXME("(%p): stub\n", ppenum);
+
+    return E_UNEXPECTED;
+}
+
+/**********************************************************************
+ * IEnumMoniker_Vtbl
+ */
+ICOM_VTABLE(IEnumMoniker) IEnumMoniker_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    DEVENUM_IEnumMoniker_QueryInterface,
+    DEVENUM_IEnumMoniker_AddRef,
+    DEVENUM_IEnumMoniker_Release,
+    DEVENUM_IEnumMoniker_Next,
+    DEVENUM_IEnumMoniker_Skip,
+    DEVENUM_IEnumMoniker_Reset,
+    DEVENUM_IEnumMoniker_Clone
+};
-------------- next part --------------
--- /dev/null	Mon Jun 24 01:53:01 2002
+++ parsedisplayname.c	Mon Dec  9 04:40:25 2002
@@ -0,0 +1,150 @@
+/*
+ *	IParseDisplayName implementation for DEVENUM.dll
+ *
+ * Copyright (C) 2002 Robert Shearman
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "devenum_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(devenum);
+
+static HRESULT WINAPI DEVENUM_IParseDisplayName_QueryInterface(
+    LPPARSEDISPLAYNAME iface,
+    REFIID riid,
+    LPVOID *ppvObj)
+{
+    ICOM_THIS(ParseDisplayNameImpl, iface);
+    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+    if (This == NULL || ppvObj == NULL) return E_POINTER;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IParseDisplayName))
+    {
+	*ppvObj = (LPVOID)iface;
+	IParseDisplayName_AddRef(iface);
+	return S_OK;
+    }
+
+    FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+/**********************************************************************
+ * DEVENUM_IParseDisplayName_AddRef (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IParseDisplayName_AddRef(LPPARSEDISPLAYNAME iface)
+{
+    ICOM_THIS(ParseDisplayNameImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    if (InterlockedIncrement(&This->ref) == 1) {
+	InterlockedIncrement(&dll_ref);
+    }
+
+    return ++This->ref;
+}
+
+/**********************************************************************
+ * DEVENUM_IParseDisplayName_Release (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IParseDisplayName_Release(LPPARSEDISPLAYNAME iface)
+{
+    ICOM_THIS(ParseDisplayNameImpl, iface);
+    ULONG ref;
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    ref = --This->ref;
+    if (InterlockedDecrement(&This->ref) == 0) {
+	InterlockedDecrement(&dll_ref);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(
+    LPPARSEDISPLAYNAME iface,
+    IBindCtx *pbc,
+    LPOLESTR pszDisplayName,
+    ULONG *pchEaten,
+    IMoniker **ppmkOut)
+{
+    LPOLESTR pszBetween = NULL;
+    IEnumMoniker * pEm = NULL;
+    MediaCatMoniker * pMoniker = NULL;
+    CLSID clsidDevice;
+    HRESULT res = S_OK;
+    TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
+
+    *ppmkOut = NULL;
+    if (pchEaten)
+        *pchEaten = strlenW(pszDisplayName);
+
+    pszDisplayName = strchrW(pszDisplayName, '{');
+    pszBetween = strchrW(pszDisplayName, '}') + 2;
+    TRACE("Reg. query string: %s\n", debugstr_w(pszBetween));
+    res = CLSIDFromString(pszDisplayName, &clsidDevice);
+
+    if (SUCCEEDED(res))
+    {
+        res = DEVENUM_ICreateDevEnum_CreateClassEnumerator((LPCREATEDEVENUM)&DEVENUM_CreateDevEnum, &clsidDevice, &pEm, 0);
+    }
+
+    if (SUCCEEDED(res))
+    {
+	pMoniker = CoTaskMemAlloc(sizeof(MediaCatMoniker));
+	IMoniker_AddRef((LPMONIKER)pMoniker);
+	if (pMoniker)
+	{
+	CreateMonikerVtbl(pMoniker);
+	pMoniker->hkey = NULL;
+	if (RegOpenKeyW(((EnumMonikerImpl *)pEm)->hkey, pszBetween, &pMoniker->hkey) != ERROR_SUCCESS)
+	{
+	    IMoniker_Release((LPMONIKER)pMoniker);
+	    res = MK_E_NOOBJECT;
+	}
+	else
+    		*ppmkOut = (LPMONIKER)pMoniker;
+	}
+    }
+
+    IEnumMoniker_Release(pEm);
+
+    if (*ppmkOut != NULL)
+    {
+        IUnknown_AddRef(*ppmkOut);
+    }
+    return res;
+}
+
+/**********************************************************************
+ * IClassFactory_Vtbl
+ */
+static ICOM_VTABLE(IParseDisplayName) IParseDisplayName_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    DEVENUM_IParseDisplayName_QueryInterface,
+    DEVENUM_IParseDisplayName_AddRef,
+    DEVENUM_IParseDisplayName_Release,
+    DEVENUM_IParseDisplayName_ParseDisplayName
+};
+
+ParseDisplayNameImpl DEVENUM_ParseDisplayName = { &IParseDisplayName_Vtbl, 0 };


More information about the wine-patches mailing list