Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/devenum/Makefile.in | 2 +- dlls/devenum/devenum_private.h | 10 ++++- dlls/devenum/mediacatenum.c | 99 ++++++++++++++++++++++++++++++----------- dlls/devenum/parsedisplayname.c | 52 ++++++++++++++++------ dlls/devenum/tests/Makefile.in | 2 +- dlls/devenum/tests/devenum.c | 64 ++++++++++++++++++++++++++ 6 files changed, 186 insertions(+), 43 deletions(-)
diff --git a/dlls/devenum/Makefile.in b/dlls/devenum/Makefile.in index 8f81f93..ae138b6 100644 --- a/dlls/devenum/Makefile.in +++ b/dlls/devenum/Makefile.in @@ -1,5 +1,5 @@ MODULE = devenum.dll -IMPORTS = strmiids uuid ole32 oleaut32 avicap32 winmm user32 advapi32 dsound +IMPORTS = strmiids uuid ole32 oleaut32 avicap32 winmm user32 advapi32 dsound msdmo DELAYIMPORTS = msvfw32
C_SRCS = \ diff --git a/dlls/devenum/devenum_private.h b/dlls/devenum/devenum_private.h index d4e1141..df0080d 100644 --- a/dlls/devenum/devenum_private.h +++ b/dlls/devenum/devenum_private.h @@ -64,6 +64,7 @@ enum device_type { DEVICE_FILTER, DEVICE_CODEC, + DEVICE_DMO, };
typedef struct @@ -73,7 +74,11 @@ typedef struct CLSID class; BOOL has_class; enum device_type type; - WCHAR *name; + union + { + WCHAR *name; /* for filters and codecs */ + CLSID clsid; /* for DMOs */ + }; } MediaCatMoniker;
MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void) DECLSPEC_HIDDEN; @@ -95,5 +100,8 @@ static const WCHAR wszActiveMovieKey[] = {'S','o','f','t','w','a','r','e','\', 'A','c','t','i','v','e','M','o','v','i','e','\', 'd','e','v','e','n','u','m','\',0}; static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':',0}; +static const WCHAR dmoW[] = {'d','m','o',':',0}; +static const WCHAR swW[] = {'s','w',':',0}; +static const WCHAR cmW[] = {'c','m',':',0};
extern const WCHAR clsid_keyname[6] DECLSPEC_HIDDEN; diff --git a/dlls/devenum/mediacatenum.c b/dlls/devenum/mediacatenum.c index a76c7be..c0efae0 100644 --- a/dlls/devenum/mediacatenum.c +++ b/dlls/devenum/mediacatenum.c @@ -25,6 +25,7 @@ #include "devenum_private.h" #include "oleauto.h" #include "ocidl.h" +#include "dmoreg.h"
#include "wine/debug.h"
@@ -46,7 +47,11 @@ typedef struct IPropertyBag IPropertyBag_iface; LONG ref; enum device_type type; - WCHAR path[MAX_PATH]; + union + { + WCHAR path[MAX_PATH]; /* for filters and codecs */ + CLSID clsid; /* for DMOs */ + }; } RegPropBagImpl;
@@ -114,12 +119,14 @@ static HRESULT WINAPI DEVENUM_IPropertyBag_Read( VARIANT* pVar, IErrorLog* pErrorLog) { + static const WCHAR FriendlyNameW[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; LPVOID pData = NULL; DWORD received; DWORD type = 0; RegPropBagImpl *This = impl_from_IPropertyBag(iface); HRESULT res = S_OK; LONG reswin32 = ERROR_SUCCESS; + WCHAR name[80]; HKEY hkey;
TRACE("(%p)->(%s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog); @@ -127,6 +134,21 @@ static HRESULT WINAPI DEVENUM_IPropertyBag_Read( if (!pszPropName || !pVar) return E_POINTER;
+ if (This->type == DEVICE_DMO) + { + if (!strcmpW(pszPropName, FriendlyNameW)) + { + res = DMOGetName(&This->clsid, name); + if (SUCCEEDED(res)) + { + V_VT(pVar) = VT_BSTR; + V_BSTR(pVar) = SysAllocString(name); + } + return res; + } + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } + if (This->type == DEVICE_FILTER) reswin32 = RegOpenKeyW(HKEY_CLASSES_ROOT, This->path, &hkey); else if (This->type == DEVICE_CODEC) @@ -246,6 +268,9 @@ static HRESULT WINAPI DEVENUM_IPropertyBag_Write(
TRACE("(%p)->(%s, %p)\n", This, debugstr_w(pszPropName), pVar);
+ if (This->type == DEVICE_DMO) + return E_ACCESSDENIED; + switch (V_VT(pVar)) { case VT_BSTR: @@ -316,18 +341,29 @@ static HRESULT create_PropertyBag(MediaCatMoniker *mon, IPropertyBag **ppBag) rpb->ref = 1; rpb->type = mon->type;
- if (rpb->type == DEVICE_FILTER) - strcpyW(rpb->path, clsidW); - else if (rpb->type == DEVICE_CODEC) - strcpyW(rpb->path, wszActiveMovieKey); - if (mon->has_class) + if (rpb->type == DEVICE_DMO) + rpb->clsid = mon->clsid; + else if (rpb->type == DEVICE_FILTER) { - StringFromGUID2(&mon->class, rpb->path + strlenW(rpb->path), CHARS_IN_GUID); - if (rpb->type == DEVICE_FILTER) + strcpyW(rpb->path, clsidW); + if (mon->has_class) + { + StringFromGUID2(&mon->class, rpb->path + strlenW(rpb->path), CHARS_IN_GUID); strcatW(rpb->path, instanceW); - strcatW(rpb->path, backslashW); + strcatW(rpb->path, backslashW); + } + strcatW(rpb->path, mon->name); + } + else if (rpb->type == DEVICE_CODEC) + { + strcpyW(rpb->path, wszActiveMovieKey); + if (mon->has_class) + { + StringFromGUID2(&mon->class, rpb->path + strlenW(rpb->path), CHARS_IN_GUID); + strcatW(rpb->path, backslashW); + } + strcatW(rpb->path, mon->name); } - strcatW(rpb->path, mon->name);
*ppBag = &rpb->IPropertyBag_iface; DEVENUM_LockModule(); @@ -658,8 +694,6 @@ static HRESULT WINAPI DEVENUM_IMediaCatMoniker_RelativePathTo(IMoniker *iface, I static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName) { - static const WCHAR swW[] = {'s','w',':',0}; - static const WCHAR cmW[] = {'c','m',':',0}; MediaCatMoniker *This = impl_from_IMoniker(iface); WCHAR *buffer;
@@ -667,23 +701,36 @@ static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetDisplayName(IMoniker *iface, I
*ppszDisplayName = NULL;
- buffer = CoTaskMemAlloc((strlenW(deviceW) + 4 + (This->has_class ? CHARS_IN_GUID : 0) - + strlenW(This->name) + 1) * sizeof(WCHAR)); - if (!buffer) - return E_OUTOFMEMORY; - - strcpyW(buffer, deviceW); - if (This->type == DEVICE_FILTER) - strcatW(buffer, swW); - else if (This->type == DEVICE_CODEC) - strcatW(buffer, cmW); - - if (This->has_class) + if (This->type == DEVICE_DMO) { + buffer = CoTaskMemAlloc((strlenW(deviceW) + strlenW(dmoW) + + 2 * CHARS_IN_GUID + 1) * sizeof(WCHAR)); + if (!buffer) return E_OUTOFMEMORY; + + strcpyW(buffer, deviceW); + strcatW(buffer, dmoW); + StringFromGUID2(&This->clsid, buffer + strlenW(buffer), CHARS_IN_GUID); StringFromGUID2(&This->class, buffer + strlenW(buffer), CHARS_IN_GUID); - strcatW(buffer, backslashW); } - strcatW(buffer, This->name); + else + { + buffer = CoTaskMemAlloc((strlenW(deviceW) + 3 + (This->has_class ? CHARS_IN_GUID : 0) + + strlenW(This->name) + 1) * sizeof(WCHAR)); + if (!buffer) return E_OUTOFMEMORY; + + strcpyW(buffer, deviceW); + if (This->type == DEVICE_FILTER) + strcatW(buffer, swW); + else if (This->type == DEVICE_CODEC) + strcatW(buffer, cmW); + + if (This->has_class) + { + StringFromGUID2(&This->class, buffer + strlenW(buffer), CHARS_IN_GUID); + strcatW(buffer, backslashW); + } + strcatW(buffer, This->name); + }
*ppszDisplayName = buffer; return S_OK; diff --git a/dlls/devenum/parsedisplayname.c b/dlls/devenum/parsedisplayname.c index 0f3ef3b..2992af0 100644 --- a/dlls/devenum/parsedisplayname.c +++ b/dlls/devenum/parsedisplayname.c @@ -91,16 +91,21 @@ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayNa
name = strchrW(name, ':') + 1;
- if (name[0] == 's' && name[1] == 'w' && name[2] == ':') + if (!strncmpW(name, swW, 3)) { type = DEVICE_FILTER; name += 3; } - else if (name[0] == 'c' && name[1] == 'm' && name[2] == ':') + else if (!strncmpW(name, cmW, 3)) { type = DEVICE_CODEC; name += 3; } + else if (!strncmpW(name, dmoW, 4)) + { + type = DEVICE_DMO; + name += 4; + } else { FIXME("unhandled device type %s\n", debugstr_w(name)); @@ -110,23 +115,42 @@ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayNa if (!(mon = DEVENUM_IMediaCatMoniker_Construct())) return E_OUTOFMEMORY;
- lstrcpynW(buffer, name, CHARS_IN_GUID); - if (CLSIDFromString(buffer, &class) == S_OK) + if (type == DEVICE_DMO) { - mon->has_class = TRUE; - mon->class = class; - name += CHARS_IN_GUID; + lstrcpynW(buffer, name, CHARS_IN_GUID); + if (FAILED(CLSIDFromString(buffer, &mon->clsid))) + { + IMoniker_Release(&mon->IMoniker_iface); + return MK_E_SYNTAX; + } + + lstrcpynW(buffer, name + CHARS_IN_GUID - 1, CHARS_IN_GUID); + if (FAILED(CLSIDFromString(buffer, &mon->class))) + { + IMoniker_Release(&mon->IMoniker_iface); + return MK_E_SYNTAX; + } + } + else + { + lstrcpynW(buffer, name, CHARS_IN_GUID); + if (CLSIDFromString(buffer, &class) == S_OK) + { + mon->has_class = TRUE; + mon->class = class; + name += CHARS_IN_GUID; + } + + if (!(mon->name = CoTaskMemAlloc((strlenW(name) + 1) * sizeof(WCHAR)))) + { + IMoniker_Release(&mon->IMoniker_iface); + return E_OUTOFMEMORY; + } + strcpyW(mon->name, name); }
mon->type = type;
- if (!(mon->name = CoTaskMemAlloc((strlenW(name) + 1) * sizeof(WCHAR)))) - { - IMoniker_Release(&mon->IMoniker_iface); - return E_OUTOFMEMORY; - } - strcpyW(mon->name, name); - *ret = &mon->IMoniker_iface;
return S_OK; diff --git a/dlls/devenum/tests/Makefile.in b/dlls/devenum/tests/Makefile.in index b268adf..2d6ec2d 100644 --- a/dlls/devenum/tests/Makefile.in +++ b/dlls/devenum/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = devenum.dll -IMPORTS = advapi32 dsound msvfw32 oleaut32 ole32 winmm +IMPORTS = advapi32 dsound msdmo msvfw32 oleaut32 ole32 winmm
C_SRCS = \ devenum.c diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index 383619c..2f66907 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -32,6 +32,7 @@ #include "dsound.h" #include "mmddk.h" #include "vfw.h" +#include "dmoreg.h"
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
@@ -41,6 +42,7 @@ static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':',0}; static const WCHAR clsidW[] = {'C','L','S','I','D',0}; static const WCHAR waveW[] = {'w','a','v','e',':',0}; static const WCHAR mrleW[] = {'m','r','l','e',0}; +static const WCHAR dmoW[] = {'d','m','o',':',0}; static const WCHAR swW[] = {'s','w',':',0}; static const WCHAR cmW[] = {'c','m',':',0}; static const WCHAR backslashW[] = {'\',0}; @@ -485,6 +487,67 @@ static void test_codec(void) IParseDisplayName_Release(parser); }
+static void test_dmo(void) +{ + static const WCHAR name[] = {'d','e','v','e','n','u','m',' ','t','e','s','t',0}; + IParseDisplayName *parser; + IPropertyBag *prop_bag; + WCHAR buffer[200]; + IMoniker *mon; + VARIANT var; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser); + ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr); + + lstrcpyW(buffer, deviceW); + lstrcatW(buffer, dmoW); + StringFromGUID2(&CLSID_TestFilter, buffer + lstrlenW(buffer), CHARS_IN_GUID); + StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID); + mon = check_display_name(parser, buffer); + + ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "DMO should not be registered\n"); + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + ok(hr == S_OK, "got %#x\n", hr); + + VariantInit(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == E_FAIL, "got %#x\n", hr); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(name); + hr = IPropertyBag_Write(prop_bag, friendly_name, &var); + ok(hr == E_ACCESSDENIED, "Write failed: %#x\n", hr); + + hr = DMORegister(name, &CLSID_TestFilter, &CLSID_AudioRendererCategory, 0, 0, NULL, 0, NULL); + if (hr != E_ACCESSDENIED) + { + ok(hr == S_OK, "got %#x\n", hr); + + VariantClear(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == S_OK, "got %#x\n", hr); + ok(!lstrcmpW(V_BSTR(&var), name), "got %s\n", wine_dbgstr_w(V_BSTR(&var))); + + VariantClear(&var); + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(name); + hr = IPropertyBag_Write(prop_bag, friendly_name, &var); + ok(hr == E_ACCESSDENIED, "Write failed: %#x\n", hr); + + VariantClear(&var); + hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "got %#x\n", hr); + + hr = DMOUnregister(&CLSID_TestFilter, &CLSID_AudioRendererCategory); + ok(hr == S_OK, "got %#x\n", hr); + } + IPropertyBag_Release(prop_bag); + IMoniker_Release(mon); + IParseDisplayName_Release(parser); +} + static void test_legacy_filter(void) { static const WCHAR nameW[] = {'t','e','s','t',0}; @@ -974,6 +1037,7 @@ START_TEST(devenum) test_register_filter(); test_directshow_filter(); test_codec(); + test_dmo();
test_legacy_filter(); hr = DirectSoundEnumerateW(test_dsound, NULL);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/devenum/mediacatenum.c | 57 ++++++++++++++++++++++++++++++++++++-------- dlls/devenum/tests/devenum.c | 2 ++ 2 files changed, 49 insertions(+), 10 deletions(-)
diff --git a/dlls/devenum/mediacatenum.c b/dlls/devenum/mediacatenum.c index c0efae0..c4338a2 100644 --- a/dlls/devenum/mediacatenum.c +++ b/dlls/devenum/mediacatenum.c @@ -36,6 +36,7 @@ typedef struct IEnumMoniker IEnumMoniker_iface; CLSID class; LONG ref; + IEnumDMO *dmo_enum; HKEY sw_key; DWORD sw_index; HKEY cm_key; @@ -845,6 +846,7 @@ static ULONG WINAPI DEVENUM_IEnumMoniker_Release(IEnumMoniker *iface)
if (!ref) { + IEnumDMO_Release(This->dmo_enum); RegCloseKey(This->sw_key); RegCloseKey(This->cm_key); CoTaskMemFree(This); @@ -862,16 +864,31 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, LONG res; ULONG fetched = 0; MediaCatMoniker * pMoniker; + WCHAR *name; + CLSID clsid; + HRESULT hr; HKEY hkey;
TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched);
while (fetched < celt) { - /* FIXME: try PNP devices and DMOs first */ + /* FIXME: try PNP devices first */
+ /* try DMOs */ + if ((hr = IEnumDMO_Next(This->dmo_enum, 1, &clsid, &name, NULL)) == S_OK) + { + if (!(pMoniker = DEVENUM_IMediaCatMoniker_Construct())) + return E_OUTOFMEMORY; + + pMoniker->type = DEVICE_DMO; + pMoniker->clsid = clsid; + + StringFromGUID2(&clsid, buffer, CHARS_IN_GUID); + StringFromGUID2(&This->class, buffer + CHARS_IN_GUID - 1, CHARS_IN_GUID); + } /* try DirectShow filters */ - if (!(res = RegEnumKeyW(This->sw_key, This->sw_index, buffer, sizeof(buffer)/sizeof(WCHAR)))) + else if (!(res = RegEnumKeyW(This->sw_key, This->sw_index, buffer, sizeof(buffer)/sizeof(WCHAR)))) { This->sw_index++; if ((res = RegOpenKeyExW(This->sw_key, buffer, 0, KEY_QUERY_VALUE, &hkey))) @@ -881,6 +898,13 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, return E_OUTOFMEMORY;
pMoniker->type = DEVICE_FILTER; + + if (!(pMoniker->name = CoTaskMemAlloc((strlenW(buffer) + 1) * sizeof(WCHAR)))) + { + IMoniker_Release(&pMoniker->IMoniker_iface); + return E_OUTOFMEMORY; + } + strcpyW(pMoniker->name, buffer); } /* then try codecs */ else if (!(res = RegEnumKeyW(This->cm_key, This->cm_index, buffer, sizeof(buffer)/sizeof(WCHAR)))) @@ -894,16 +918,17 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, return E_OUTOFMEMORY;
pMoniker->type = DEVICE_CODEC; + + if (!(pMoniker->name = CoTaskMemAlloc((strlenW(buffer) + 1) * sizeof(WCHAR)))) + { + IMoniker_Release(&pMoniker->IMoniker_iface); + return E_OUTOFMEMORY; + } + strcpyW(pMoniker->name, buffer); } else break;
- if (!(pMoniker->name = CoTaskMemAlloc((strlenW(buffer) + 1) * sizeof(WCHAR)))) - { - IMoniker_Release(&pMoniker->IMoniker_iface); - return E_OUTOFMEMORY; - } - strcpyW(pMoniker->name, buffer); pMoniker->has_class = TRUE; pMoniker->class = This->class;
@@ -930,10 +955,13 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Skip(IEnumMoniker *iface, ULONG celt)
while (celt--) { - /* FIXME: try PNP devices and DMOs first */ + /* FIXME: try PNP devices first */
+ /* try DMOs */ + if (IEnumDMO_Skip(This->dmo_enum, 1) == S_OK) + ; /* try DirectShow filters */ - if (RegEnumKeyW(This->sw_key, This->sw_index, NULL, 0) != ERROR_NO_MORE_ITEMS) + else if (RegEnumKeyW(This->sw_key, This->sw_index, NULL, 0) != ERROR_NO_MORE_ITEMS) { This->sw_index++; } @@ -955,6 +983,7 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Reset(IEnumMoniker *iface)
TRACE("(%p)->()\n", iface);
+ IEnumDMO_Reset(This->dmo_enum); This->sw_index = 0; This->cm_index = 0;
@@ -986,6 +1015,7 @@ HRESULT create_EnumMoniker(REFCLSID class, IEnumMoniker **ppEnumMoniker) { EnumMonikerImpl * pEnumMoniker = CoTaskMemAlloc(sizeof(EnumMonikerImpl)); WCHAR buffer[78]; + HRESULT hr;
if (!pEnumMoniker) return E_OUTOFMEMORY; @@ -1007,6 +1037,13 @@ HRESULT create_EnumMoniker(REFCLSID class, IEnumMoniker **ppEnumMoniker) if (RegOpenKeyExW(HKEY_CURRENT_USER, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &pEnumMoniker->cm_key)) pEnumMoniker->cm_key = NULL;
+ hr = DMOEnum(class, 0, 0, NULL, 0, NULL, &pEnumMoniker->dmo_enum); + if (FAILED(hr)) + { + IEnumMoniker_Release(&pEnumMoniker->IEnumMoniker_iface); + return hr; + } + *ppEnumMoniker = &pEnumMoniker->IEnumMoniker_iface;
DEVENUM_LockModule(); diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index 2f66907..6d4ce2d 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -525,6 +525,8 @@ static void test_dmo(void) { ok(hr == S_OK, "got %#x\n", hr);
+ ok(find_moniker(&CLSID_AudioRendererCategory, mon), "DMO should be registered\n"); + VariantClear(&var); hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); ok(hr == S_OK, "got %#x\n", hr);