Implemented DevEnum dll.
diff --git a/dlls/devenum/.cvsignore b/dlls/devenum/.cvsignore index 87dac7f..4305e6e 100644 --- a/dlls/devenum/.cvsignore +++ b/dlls/devenum/.cvsignore
@@ -1,4 +1,5 @@ Makefile devenum.dll.dbg.c +devenum.res devenum.spec.c devenum.spec.def
diff --git a/dlls/devenum/Makefile.in b/dlls/devenum/Makefile.in index 7637bec..faf3c46 100644 --- a/dlls/devenum/Makefile.in +++ b/dlls/devenum/Makefile.in
@@ -3,11 +3,20 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = devenum.dll +IMPORTS = ole32 oleaut32 winmm user32 advapi32 kernel32 +EXTRALIBS = $(LIBUUID) LDDLLFLAGS = @LDDLLFLAGS@ SYMBOLFILE = $(MODULE).tmp.o -C_SRCS = devenum_main.c +C_SRCS = \ + createdevenum.c \ + devenum_main.c \ + factory.c \ + mediacatenum.c \ + parsedisplayname.c + +RC_SRCS = devenum.rc @MAKE_DLL_RULES@
diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c new file mode 100644 index 0000000..c84857c --- /dev/null +++ b/dlls/devenum/createdevenum.c
@@ -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 --git a/dlls/devenum/devenum.rc b/dlls/devenum/devenum.rc new file mode 100644 index 0000000..6317bbb --- /dev/null +++ b/dlls/devenum/devenum.rc
@@ -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 --git a/dlls/devenum/devenum.spec b/dlls/devenum/devenum.spec index e0786db..ffeb5dc 100644 --- a/dlls/devenum/devenum.spec +++ b/dlls/devenum/devenum.spec
@@ -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
diff --git a/dlls/devenum/devenum_main.c b/dlls/devenum/devenum_main.c index d5dfdfe..626f76b 100644 --- a/dlls/devenum/devenum_main.c +++ b/dlls/devenum/devenum_main.c
@@ -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); -/*********************************************************************** - * DllRegisterServer (DEVENUM.@) - */ -HRESULT WINAPI DEVENUM_DllRegisterServer() +DWORD dll_ref = 0; +HINSTANCE DEVENUM_hInstance; + +typedef struct { - FIXME("(): stub\n"); - return 0; + 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; +} + +/*********************************************************************** + * DllCanUnloadNow (DEVENUM.@) + */ +HRESULT WINAPI DEVENUM_DllCanUnloadNow(void) +{ + return dll_ref != 0 ? S_FALSE : S_OK; +} + +/*********************************************************************** + * DllRegisterServer (DEVENUM.@) + */ +HRESULT WINAPI DEVENUM_DllRegisterServer(void) +{ + 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(void) +{ + 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 --git a/dlls/devenum/devenum_private.h b/dlls/devenum/devenum_private.h new file mode 100644 index 0000000..0bd0638 --- /dev/null +++ b/dlls/devenum/devenum_private.h
@@ -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 --git a/dlls/devenum/factory.c b/dlls/devenum/factory.c new file mode 100644 index 0000000..8ac9ceb --- /dev/null +++ b/dlls/devenum/factory.c
@@ -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 --git a/dlls/devenum/mediacatenum.c b/dlls/devenum/mediacatenum.c new file mode 100644 index 0000000..8903b47 --- /dev/null +++ b/dlls/devenum/mediacatenum.c
@@ -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 --git a/dlls/devenum/parsedisplayname.c b/dlls/devenum/parsedisplayname.c new file mode 100644 index 0000000..b5b1c13 --- /dev/null +++ b/dlls/devenum/parsedisplayname.c
@@ -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 };