Commit d38cce8d authored by Robert Shearman's avatar Robert Shearman Committed by Alexandre Julliard

Implemented DevEnum dll.

parent c71301a3
Makefile
devenum.dll.dbg.c
devenum.res
devenum.spec.c
devenum.spec.def
......@@ -3,11 +3,20 @@ TOPOBJDIR = ../..
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@
......
/*
* 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;
}
/*
* 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
@ 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
/*
* 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;
}
/***********************************************************************
* 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;
}
/***********************************************************************
* DllRegisterServer (DEVENUM.@)
* DllUnregisterServer (DEVENUM.@)
*/
HRESULT WINAPI DEVENUM_DllRegisterServer()
HRESULT WINAPI DEVENUM_DllUnregisterServer(void)
{
FIXME("(): stub\n");
return 0;
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;
}
/*
* 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
/*
* 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 };
/*
* 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
};
/*
* 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 };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment