[DSHOW-03] DevEnum Implementation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

This patch implements the DevEnum DLL. It doesn't depend on DSHOW-02, but 
does depend on DSHOW-01.

Changelog:
- Implement DevEnum DLL

Rob
diff -u -N -r -x *~ -x .#* -x CVS -x Makefile wine/dlls/devenum03/Makefile.in wine/dlls/devenum/Makefile.in
--- wine/dlls/devenum03/Makefile.in	Fri May 17 04:37:12 2002
+++ wine/dlls/devenum/Makefile.in	Mon Jun 30 00:27:21 2003
@@ -3,11 +3,19 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = devenum.dll
+IMPORTS   = kernel32 advapi32 ole32 oleaut32 winmm user32
+EXTRALIBS = $(LIBUUID)
 
 LDDLLFLAGS = @LDDLLFLAGS@
 SYMBOLFILE = $(MODULE).tmp.o
 
-C_SRCS = devenum_main.c
+C_SRCS = devenum_main.c \
+         factory.c \
+         createdevenum.c \
+         mediacatenum.c \
+         parsedisplayname.c
+
+RC_SRCS = devenum.rc
 
 @MAKE_DLL_RULES@
 
diff -u -N -r -x *~ -x .#* -x CVS -x Makefile wine/dlls/devenum03/createdevenum.c wine/dlls/devenum/createdevenum.c
--- wine/dlls/devenum03/createdevenum.c	Thu Jan  1 01:00:00 1970
+++ wine/dlls/devenum/createdevenum.c	Mon Jun 23 16:51:32 2003
@@ -0,0 +1,378 @@
+/*
+ *	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
+ *
+ * NOTES ON THIS FILE:
+ * - Implements ICreateDevEnum interface which creates an IEnumMoniker
+ *   implementation
+ * - Also creates the special registry keys created at run-time
+ * - ...
+ */
+
+#include "devenum_private.h"
+
+#include "wine/debug.h"
+#include "mmddk.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(devenum);
+
+extern ICOM_VTABLE(IEnumMoniker) IEnumMoniker_Vtbl;
+
+extern HINSTANCE DEVENUM_hInstance;
+
+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(ICreateDevEnum * iface);
+static HRESULT DEVENUM_CreateSpecialCategories();
+
+/**********************************************************************
+ * DEVENUM_ICreateDevEnum_QueryInterface (also IUnknown)
+ */
+static HRESULT WINAPI DEVENUM_ICreateDevEnum_QueryInterface(
+    ICreateDevEnum * 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(ICreateDevEnum * 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(ICreateDevEnum * 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(
+    ICreateDevEnum * iface,
+    REFCLSID clsidDeviceClass,
+    IEnumMoniker **ppEnumMoniker,
+    DWORD dwFlags)
+{
+    WCHAR wszRegKey[MAX_PATH];
+    EnumMonikerImpl * pEnumMoniker;
+    HKEY hkey;
+    HKEY hbasekey;
+    ICOM_THIS(CreateDevEnumImpl, iface);
+
+    TRACE("(%p)->(%s, %p, %lx)\n\tDeviceClass:\t%s\n", This, debugstr_guid(clsidDeviceClass), 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 = 1;
+    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;
+/* this section below needs some attention - when it is enabled it appears to create
+ * a circular dependency. IE IFilterMapper2_RegisterFilter calls back into this library
+ * which again calls RegisterFilter.
+ */
+#if 0
+    IMoniker * pMoniker = NULL;
+    WCHAR szAltNameFormat[MAX_PATH + 1];
+    WCHAR szAltName[MAX_PATH + 1];
+    DWORD iDefaultDevice = -1;
+    UINT numDevs;
+    IFilterMapper2 * pMapper = NULL;
+    REGFILTER2 rf2;
+    REGFILTERPINS2 rfp2;
+
+    rf2.dwVersion = 2;
+    rf2.dwMerit = MERIT_PREFERRED;
+    rf2.u.s1.cPins2 = 1;
+    rf2.u.s1.rgPins2 = &rfp2;
+    rfp2.dwFlags = REG_PINFLAG_B_RENDERER;
+    rfp2.cInstances = 1;
+    rfp2.nMediums = 0;
+    rfp2.lpMedium = NULL;
+    rfp2.clsPinCategory = &IID_NULL;
+
+    res = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC,
+                           &IID_IFilterMapper2, (void **) &pMapper);
+    /*
+     * Fill in info for out devices
+     */
+    if (SUCCEEDED(res))
+    {
+        UINT i;
+        WAVEOUTCAPSW wocaps;
+	WAVEINCAPSW wicaps;
+        MIDIOUTCAPSW mocaps;
+        REGPINTYPES * pTypes;
+	numDevs = waveOutGetNumDevs();
+
+	for (i = 0; i < numDevs; i++)
+	{
+	    LoadStringW(DEVENUM_hInstance, IDS_DEVENUM_DS, szAltNameFormat, MAX_PATH);
+	    if (waveOutGetDevCapsW(i, &wocaps, sizeof(WAVEOUTCAPSW))
+	        == MMSYSERR_NOERROR)
+	    {
+                rfp2.nMediaTypes = 1;
+                pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES));
+                if (!pTypes)
+                {
+                    IFilterMapper2_Release(pMapper);
+                    return E_OUTOFMEMORY;
+                }
+                /* FIXME: Native devenum seems to register a lot more types for
+                 * DSound than we do. Not sure what purpose they serve */
+                pTypes[0].clsMajorType = &MEDIATYPE_Audio;
+                pTypes[0].clsMinorType = &MEDIASUBTYPE_PCM;
+
+                rfp2.lpMediaType = pTypes;
+
+                IFilterMapper2_RegisterFilter(pMapper,
+		                              &CLSID_AudioRender,
+					      wocaps.szPname,
+					      &pMoniker,
+					      &CLSID_AudioRendererCategory,
+					      wocaps.szPname,
+					      &rf2);
+
+                /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */
+
+		if (pMoniker)
+		    IMoniker_Release(pMoniker);
+
+		wsprintfW(szAltName, szAltNameFormat, wocaps.szPname);
+	        IFilterMapper2_RegisterFilter(pMapper,
+		                              &CLSID_DSoundRender,
+					      szAltName,
+					      &pMoniker,
+					      &CLSID_AudioRendererCategory,
+					      szAltName,
+					      &rf2);
+
+                /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */
+
+		if (pMoniker)
+		    IMoniker_Release(pMoniker);
+
+		if (i == iDefaultDevice)
+		{
+		    FIXME("Default device\n");
+		}
+
+                CoTaskMemFree(pTypes);
+	    }
+	}
+
+        numDevs = waveInGetNumDevs();
+
+        for (i = 0; i < numDevs; i++)
+        {
+            if (waveInGetDevCapsW(i, &wicaps, sizeof(WAVEINCAPSW))
+                == MMSYSERR_NOERROR)
+            {
+                rfp2.nMediaTypes = 1;
+                pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES));
+                if (!pTypes)
+                {
+                    IFilterMapper2_Release(pMapper);
+                    return E_OUTOFMEMORY;
+                }
+
+                /* FIXME: Not sure if these are correct */
+                pTypes[0].clsMajorType = &MEDIATYPE_Audio;
+                pTypes[0].clsMinorType = &MEDIASUBTYPE_PCM;
+
+                rfp2.lpMediaType = pTypes;
+
+	        IFilterMapper2_RegisterFilter(pMapper,
+		                              &CLSID_AudioRecord,
+					      wicaps.szPname,
+					      &pMoniker,
+					      &CLSID_AudioInputDeviceCategory,
+					      wicaps.szPname,
+					      &rf2);
+
+                /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */
+
+		if (pMoniker)
+		    IMoniker_Release(pMoniker);
+
+                CoTaskMemFree(pTypes);
+	    }
+	}
+	numDevs = midiOutGetNumDevs();
+
+	for (i = 0; i < numDevs; i++)
+	{
+	    if (midiOutGetDevCapsW(i, &mocaps, sizeof(MIDIOUTCAPSW))
+	        == MMSYSERR_NOERROR)
+	    {
+                rfp2.nMediaTypes = 1;
+                pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES));
+                if (!pTypes)
+                {
+                    IFilterMapper2_Release(pMapper);
+                    return E_OUTOFMEMORY;
+                }
+
+                /* FIXME: Not sure if these are correct */
+                pTypes[0].clsMajorType = &MEDIATYPE_Midi;
+                pTypes[0].clsMinorType = &MEDIASUBTYPE_None;
+
+                rfp2.lpMediaType = pTypes;
+
+                IFilterMapper2_RegisterFilter(pMapper,
+		                              &CLSID_AVIMIDIRender,
+					      mocaps.szPname,
+					      &pMoniker,
+					      &CLSID_MidiRendererCategory,
+					      mocaps.szPname,
+					      &rf2);
+
+                /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */
+		/* Native version sets MidiOutId */
+
+		if (pMoniker)
+		    IMoniker_Release(pMoniker);
+
+		if (i == iDefaultDevice)
+		{
+		    FIXME("Default device\n");
+		}
+
+                CoTaskMemFree(pTypes);
+	    }
+	}
+    }
+
+    if (pMapper)
+        IFilterMapper2_Release(pMapper);
+#endif
+    return res;
+}
diff -u -N -r -x *~ -x .#* -x CVS -x Makefile wine/dlls/devenum03/devenum.rc wine/dlls/devenum/devenum.rc
--- wine/dlls/devenum03/devenum.rc	Thu Jan  1 01:00:00 1970
+++ wine/dlls/devenum/devenum.rc	Mon Jun 30 00:34:53 2003
@@ -0,0 +1,59 @@
+/*
+ * Resources for Device Enumerator
+ *
+ * Copyright 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 "winnls.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+	7  "Default DirectSound"
+	8  "DirectSound: %s"
+	9  "Default WaveOut Device"
+	10 "Default MidiOut Device"
+}
+
+1 VERSIONINFO
+ FILEVERSION 6,3,1,881
+ PRODUCTVERSION 6,3,1,881
+ FILEFLAGSMASK 0x30003fL
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "04090000"
+	BEGIN
+            VALUE "CompanyName", "Wine Developer Team\000"
+            VALUE "FileDescription", "Wine Device Enumerator Library\000"
+            VALUE "FileVersion", "6.3.1.881\000"
+            VALUE "InternalName", "DEVENUM\000"
+            VALUE "LegalCopyright", "Copyright \251 2002\000"
+            VALUE "OriginalFilename", "DEVENUM.DLL\000"
+            VALUE "ProductName", "Wine\000"
+            VALUE "ProductVersion", "6.3.1.881\000"
+	END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 0
+    END
+END
diff -u -N -r -x *~ -x .#* -x CVS -x Makefile wine/dlls/devenum03/devenum.spec wine/dlls/devenum/devenum.spec
--- wine/dlls/devenum03/devenum.spec	Thu Jan  2 17:55:45 2003
+++ wine/dlls/devenum/devenum.spec	Tue Jan  7 17:24:24 2003
@@ -1,4 +1,4 @@
-@ stub DllCanUnloadNow
-@ stub DllGetClassObject
+@ stdcall DllCanUnloadNow() DEVENUM_DllCanUnloadNow
+@ stdcall DllGetClassObject(ptr ptr ptr) DEVENUM_DllGetClassObject
 @ stdcall DllRegisterServer() DEVENUM_DllRegisterServer
-@ stub DllUnregisterServer
+@ stdcall DllUnregisterServer() DEVENUM_DllUnregisterServer
\ No newline at end of file
diff -u -N -r -x *~ -x .#* -x CVS -x Makefile wine/dlls/devenum03/devenum_main.c wine/dlls/devenum/devenum_main.c
--- wine/dlls/devenum03/devenum_main.c	Thu Jan  2 17:55:45 2003
+++ wine/dlls/devenum/devenum_main.c	Fri Jun 27 01:49:51 2003
@@ -1,12 +1,327 @@
+/*
+ *	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;
+
+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 };
+
+
+/***********************************************************************
+ *		DllEntryPoint
+ */
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
+{
+    TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
+
+    switch(fdwReason) {
+    case DLL_PROCESS_ATTACH:
+        DEVENUM_hInstance = hinstDLL;
+        DisableThreadLibraryCalls(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;
+
+    /* FIXME: we should really have two class factories.
+     * Oh well - works just fine as it is */
+    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;
+}
+
 /***********************************************************************
- *      DllRegisterServer (DEVENUM.@)
+ *		DllCanUnloadNow (DEVENUM.@)
+ */
+HRESULT WINAPI DEVENUM_DllCanUnloadNow()
+{
+    return dll_ref != 0 ? S_FALSE : S_OK;
+}
+
+/***********************************************************************
+ *		DllRegisterServer (DEVENUM.@)
  */
 HRESULT WINAPI DEVENUM_DllRegisterServer()
 {
-	FIXME("(): stub\n");
-	return 0;
+    HRESULT res;
+    HKEY hkeyClsid = NULL;
+    HKEY hkey1 = NULL;
+    HKEY hkey2 = NULL;
+    LPOLESTR pszClsidDevMon = NULL;
+    IFilterMapper2 * pMapper = NULL;
+    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 ***/
+    {
+    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(NULL);
+    res = CoCreateInstance(&CLSID_FilterMapper2, 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();
+    }
+
+/*** 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(HKEY_CLASSES_ROOT, 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(HKEY_CLASSES_ROOT, 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()
+{
+	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','v','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;
+
+    TRACE("HModule = %p\n", DEVENUM_hInstance);
+    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;
 }
diff -u -N -r -x *~ -x .#* -x CVS -x Makefile wine/dlls/devenum03/devenum_private.h wine/dlls/devenum/devenum_private.h
--- wine/dlls/devenum03/devenum_private.h	Thu Jan  1 01:00:00 1970
+++ wine/dlls/devenum/devenum_private.h	Mon Jun 30 00:34:31 2003
@@ -0,0 +1,115 @@
+/*
+ *	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
+ *
+ * NOTES ON FILE:
+ * - Private file where devenum globals are declared
+ */
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+
+#define COM_NO_WINDOWS_H
+#include "ole2.h"
+#include "strmif.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);
+
+    DWORD ref;
+    HKEY hkey;
+} MediaCatMoniker;
+
+typedef struct
+{
+    ICOM_VFIELD(IPropertyBag);
+    DWORD ref;
+    HKEY hkey;
+} RegPropBagImpl;
+
+typedef struct
+{
+    ICOM_VFIELD(IParseDisplayName);
+    DWORD ref;
+} ParseDisplayNameImpl;
+
+MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct();
+HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator(
+    ICreateDevEnum * iface,
+    REFCLSID clsidDeviceClass,
+    IEnumMoniker **ppEnumMoniker,
+    DWORD dwFlags);
+
+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))
+
+/**********************************************************************
+ * Resource IDs
+ */
+#define IDS_DEVENUM_DSDEFAULT 7
+#define IDS_DEVENUM_DS        8
+#define IDS_DEVENUM_WODEFAULT 9
+#define IDS_DEVENUM_MIDEFAULT 10
+#define IDS_DEVENUM_KSDEFAULT 11
+#define IDS_DEVENUM_KS        12
diff -u -N -r -x *~ -x .#* -x CVS -x Makefile wine/dlls/devenum03/factory.c wine/dlls/devenum/factory.c
--- wine/dlls/devenum03/factory.c	Thu Jan  1 01:00:00 1970
+++ wine/dlls/devenum/factory.c	Fri Jun 27 00:19:32 2003
@@ -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;
+    }
+    else 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 };
diff -u -N -r -x *~ -x .#* -x CVS -x Makefile wine/dlls/devenum03/mediacatenum.c wine/dlls/devenum/mediacatenum.c
--- wine/dlls/devenum03/mediacatenum.c	Thu Jan  1 01:00:00 1970
+++ wine/dlls/devenum/mediacatenum.c	Sun Jun 29 23:52:28 2003
@@ -0,0 +1,800 @@
+/*
+ *	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
+ *
+ * NOTES ON THIS FILE:
+ * - Implements IEnumMoniker interface which enumerates through moniker
+ *   objects created from HKEY_CLASSES/CLSID/{DEVICE_CLSID}/Instance
+ */
+
+#include "devenum_private.h"
+#include "vfwmsgs.h"
+#include "oleauto.h"
+
+#include "wine/debug.h"
+
+
+/* #define ICOM_THIS_From_IROTData(class, name) class* This = (class*)(((char*)name)-sizeof(void*)) */
+
+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");
+
+    return InterlockedIncrement(&This->ref);
+}
+
+/**********************************************************************
+ * DEVENUM_IPropertyBag_Release (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IPropertyBag_Release(LPPROPERTYBAG iface)
+{
+    ICOM_THIS(RegPropBagImpl, iface);
+
+    TRACE("\n");
+
+    if (InterlockedDecrement(&This->ref) == 0) {
+        RegCloseKey(This->hkey);
+        CoTaskMemFree(This);
+        return 0;
+    }
+    return This->ref;
+}
+
+static const 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;
+    LONG reswin32;
+
+    TRACE("(%p)->(%s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog);
+
+    if (!pszPropName || !pVar)
+        return E_POINTER;
+
+    /* work around a GCC bug that occurs here unless we use the reswin32 variable as well */
+    reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, &type, (LPVOID)wszData, &received);
+    res = HRESULT_FROM_WIN32(reswin32);
+
+    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_UI1, 1, &bound)))
+                        return E_OUTOFMEMORY;
+                    break;
+                }
+
+                res = SafeArrayAccessData(V_UNION(pVar, parray), &pArrayElements);
+                if (FAILED(res))
+                {
+                    TRACE(" <- %lx\n", res);
+                    return res;
+                }
+                CopyMemory(pArrayElements, wszData, received);
+                res = SafeArrayUnaccessData(V_UNION(pVar, parray));
+                TRACE(" <- %lx\n", res);
+                return res;
+            }
+        }
+        FIXME("Variant type %x not supported for regtype %lx\n", V_VT(pVar), type);
+        return E_FAIL;
+    }
+
+    TRACE("<- %lx\n", res);
+    return res;
+}
+
+static HRESULT WINAPI DEVENUM_IPropertyBag_Write(
+    LPPROPERTYBAG iface,
+    LPCOLESTR pszPropName,
+    VARIANT* pVar)
+{
+    ICOM_THIS(RegPropBagImpl, iface);
+    LPVOID lpData = NULL;
+    DWORD cbData = 0;
+    DWORD dwType = 0;
+    HRESULT res = S_OK;
+
+    TRACE("(%p)->(%s, %p)\n", This, debugstr_w(pszPropName), pVar);
+
+    switch (V_VT(pVar))
+    {
+    case VT_BSTR:
+        TRACE("writing %s\n", debugstr_w(V_UNION(pVar, bstrVal)));
+        lpData = (LPVOID)V_UNION(pVar, bstrVal);
+        dwType = REG_SZ;
+        cbData = (lstrlenW(V_UNION(pVar, bstrVal)) + 1) * sizeof(WCHAR);
+        break;
+    case VT_I4:
+    case VT_UI4:
+        lpData = (LPVOID)V_UNION(pVar, ulVal);
+        dwType = REG_DWORD;
+        cbData = sizeof(DWORD);
+        break;
+    case VT_ARRAY | VT_UI1:
+    {
+        LONG lUbound = 0;
+        LONG lLbound = 0;
+        dwType = REG_BINARY;
+        res = SafeArrayGetLBound(V_UNION(pVar, parray), 1, &lLbound);
+        res = SafeArrayGetUBound(V_UNION(pVar, parray), 1, &lUbound);
+        cbData = (lUbound - lLbound + 1) /* * sizeof(BYTE)*/;
+        TRACE("cbData: %ld\n", cbData);
+        res = SafeArrayAccessData(V_UNION(pVar, parray), &lpData);
+        break;
+    }
+    default:
+        FIXME("Variant type %d not handled\n", V_VT(pVar));
+        return E_FAIL;
+    }
+
+    if (RegSetValueExW(This->hkey,
+                       pszPropName, 0,
+                       dwType, lpData, cbData) != ERROR_SUCCESS)
+        res = E_FAIL;
+
+    if (V_VT(pVar) & VT_ARRAY)
+        res = SafeArrayUnaccessData(V_UNION(pVar, parray));
+
+    return res;
+}
+
+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;
+    }
+
+    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);
+    FIXME("(%p)->(%p)\n", This, pClassID);
+
+    if (pClassID == NULL)
+        return E_POINTER;
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsDirty(LPMONIKER iface)
+{
+    FIXME("()\n");
+
+    return S_FALSE;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Load(LPMONIKER iface, IStream* pStm)
+{
+    FIXME("(%p)\n", pStm);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Save(LPMONIKER iface, IStream* pStm, BOOL fClearDirty)
+{
+    FIXME("(%p, %s)\n", pStm, fClearDirty ? "true" : "false");
+
+    return STG_E_CANTSAVE;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetSizeMax(
+    LPMONIKER iface,
+    ULARGE_INTEGER* pcbSize)
+{
+    FIXME("(%p)\n", pcbSize);
+
+    ZeroMemory(pcbSize, sizeof(*pcbSize));
+
+    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;
+    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);
+                CoTaskMemFree(V_UNION(&var, bstrVal));
+            }
+            if (SUCCEEDED(res))
+            {
+                res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IUnknown,(void**)&pObj);
+            }
+    }
+
+    if (pObj!=NULL)
+    {
+        /* get the requested interface from the loaded class */
+        res= IUnknown_QueryInterface(pObj,riidResult,ppvResult);
+    }
+
+    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 = 1;
+        *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)
+{
+    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)
+{
+    FIXME("(%p, %s, %p): stub\n", pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite);
+
+    /* FIXME: use CreateGenericComposite? */
+    *ppmkComposite = NULL;
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Enum(
+    LPMONIKER iface,
+    BOOL fForward,
+    IEnumMoniker** ppenumMoniker)
+{
+    FIXME("(%s, %p): stub\n", fForward ? "true" : "false", ppenumMoniker);
+
+    *ppenumMoniker = NULL;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsEqual(
+    LPMONIKER iface,
+    IMoniker* pmkOtherMoniker)
+{
+    FIXME("(%p)\n", pmkOtherMoniker);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Hash(
+    LPMONIKER iface,
+    DWORD* pdwHash)
+{
+    TRACE("(%p)\n", pdwHash);
+
+    *pdwHash = 0;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsRunning(
+    LPMONIKER iface,
+    IBindCtx* pbc,
+    IMoniker* pmkToLeft,
+    IMoniker* pmkNewlyRunning)
+{
+    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)
+{
+    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)
+{
+    TRACE("(%p)\n", ppmk);
+
+    *ppmk = NULL;
+
+    return MK_E_NOINVERSE;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_CommonPrefixWith(
+    LPMONIKER iface,
+    IMoniker* pmkOtherMoniker,
+    IMoniker** ppmkPrefix)
+{
+    TRACE("(%p, %p)\n", pmkOtherMoniker, ppmkPrefix);
+
+    *ppmkPrefix = NULL;
+
+    return MK_E_NOPREFIX;
+}
+
+static HRESULT WINAPI DEVENUM_IMediaCatMoniker_RelativePathTo(
+    LPMONIKER iface,
+    IMoniker* pmkOther,
+    IMoniker** ppmkRelPath)
+{
+    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)
+{
+    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;
+
+    /* FIXME: should this be the weird stuff we have to parse in IParseDisplayName? */
+    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)
+{
+    FIXME("(%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)
+{
+    TRACE("(%p)\n", pdwMksys);
+
+    return S_FALSE;
+}
+
+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
+};
+
+MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct()
+{
+    MediaCatMoniker * pMoniker = NULL;
+    pMoniker = CoTaskMemAlloc(sizeof(MediaCatMoniker));
+    if (!pMoniker)
+        return NULL;
+
+    pMoniker->lpVtbl = &IMoniker_Vtbl;
+    pMoniker->ref = 0;
+    pMoniker->hkey = NULL;
+
+    DEVENUM_IMediaCatMoniker_AddRef((LPMONIKER)pMoniker);
+
+    return pMoniker;
+}
+
+/**********************************************************************
+ * 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 InterlockedIncrement(&This->ref);
+}
+
+/**********************************************************************
+ * DEVENUM_IEnumMoniker_Release (also IUnknown)
+ */
+static ULONG WINAPI DEVENUM_IEnumMoniker_Release(LPENUMMONIKER iface)
+{
+    ICOM_THIS(EnumMonikerImpl, iface);
+
+    TRACE("\n");
+
+    if (!InterlockedDecrement(&This->ref))
+    {
+        RegCloseKey(This->hkey);
+        CoTaskMemFree(This);
+        return 0;
+    }
+    return This->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 = DEVENUM_IMediaCatMoniker_Construct();
+        if (!pMoniker)
+            return E_OUTOFMEMORY;
+
+        if (RegOpenKeyW(This->hkey, buffer, &pMoniker->hkey) != ERROR_SUCCESS)
+        {
+            DEVENUM_IMediaCatMoniker_Release((LPMONIKER)pMoniker);
+            break;
+        }
+        rgelt[fetched] = (LPMONIKER)pMoniker;
+        fetched++;
+    }
+
+    This->index += fetched;
+
+    TRACE("-- fetched %ld\n", 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)
+{
+    FIXME("(%p): stub\n", ppenum);
+
+    return E_NOTIMPL;
+}
+
+/**********************************************************************
+ * 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
+};
diff -u -N -r -x *~ -x .#* -x CVS -x Makefile wine/dlls/devenum03/parsedisplayname.c wine/dlls/devenum/parsedisplayname.c
--- wine/dlls/devenum03/parsedisplayname.c	Thu Jan  1 01:00:00 1970
+++ wine/dlls/devenum/parsedisplayname.c	Mon Jun 30 00:33:45 2003
@@ -0,0 +1,177 @@
+/*
+ *	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
+ *
+ * NOTES ON THIS FILE:
+ * - Implements IParseDisplayName interface which creates a moniker
+ *   from a string in a special format
+ */
+#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;
+}
+
+/**********************************************************************
+ * DEVENUM_IParseDisplayName_ParseDisplayName
+ *
+ *  Creates a moniker referenced to by the display string argument
+ *
+ * POSSIBLE BUGS:
+ *  Might not handle more complicated strings properly (ie not in
+ *  "@device:sw:{CLSID1}\{CLSID2}" format
+ */
+static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(
+    LPPARSEDISPLAYNAME iface,
+    IBindCtx *pbc,
+    LPOLESTR pszDisplayName,
+    ULONG *pchEaten,
+    IMoniker **ppmkOut)
+{
+    LPOLESTR pszBetween = NULL;
+    LPOLESTR pszClass = 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;
+
+    /* size = pszBetween - pszDisplayName - 1 (for '\\' after CLSID)
+     * + 1 (for NULL character)
+     */
+    pszClass = CoTaskMemAlloc((int)(pszBetween - pszDisplayName) * sizeof(WCHAR));
+    if (!pszClass)
+        return E_OUTOFMEMORY;
+
+    strncpyW(pszClass, pszDisplayName, (int)(pszBetween - pszDisplayName) - 1);
+    pszClass[(int)(pszBetween - pszDisplayName) - 1] = 0;
+
+    TRACE("Device CLSID: %s\n", debugstr_w(pszClass));
+
+    res = CLSIDFromString(pszClass, &clsidDevice);
+
+    if (SUCCEEDED(res))
+    {
+        res = DEVENUM_ICreateDevEnum_CreateClassEnumerator((ICreateDevEnum *)&DEVENUM_CreateDevEnum, &clsidDevice, &pEm, 0);
+    }
+
+    if (SUCCEEDED(res))
+    {
+        pMoniker = DEVENUM_IMediaCatMoniker_Construct();
+        if (pMoniker)
+        {
+            if (RegCreateKeyW(((EnumMonikerImpl *)pEm)->hkey,
+                               pszBetween,
+                               &pMoniker->hkey) == ERROR_SUCCESS)
+                *ppmkOut = (LPMONIKER)pMoniker;
+            else
+            {
+                IMoniker_Release((LPMONIKER)pMoniker);
+                res = MK_E_NOOBJECT;
+            }
+        }
+    }
+
+    if (pEm)
+        IEnumMoniker_Release(pEm);
+
+    if (pszClass)
+        CoTaskMemFree(pszClass);
+
+    TRACE("-- returning: %lx\n", res);
+    return res;
+}
+
+/**********************************************************************
+ * IParseDisplayName_Vtbl
+ */
+static ICOM_VTABLE(IParseDisplayName) IParseDisplayName_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    DEVENUM_IParseDisplayName_QueryInterface,
+    DEVENUM_IParseDisplayName_AddRef,
+    DEVENUM_IParseDisplayName_Release,
+    DEVENUM_IParseDisplayName_ParseDisplayName
+};
+
+/* The one instance of this class */
+ParseDisplayNameImpl DEVENUM_ParseDisplayName = { &IParseDisplayName_Vtbl, 0 };

[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux