[PATCH 1/2] devenum: Implement parsing and reading DMO monikers.

Zebediah Figura z.figura12 at gmail.com
Sun Jun 24 17:20:29 CDT 2018


Signed-off-by: Zebediah Figura <z.figura12 at 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);
-- 
2.7.4




More information about the wine-devel mailing list