[PATCH 1/5] mfplat: Implement MFTEnumEx().

Nikolay Sivov nsivov at codeweavers.com
Tue Mar 3 03:22:42 CST 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfplat/main.c         | 457 ++++++++++++++++++++++++++++++-------
 dlls/mfplat/mfplat.spec    |   1 +
 dlls/mfplat/tests/mfplat.c |  17 +-
 include/mfapi.h            |   2 +
 4 files changed, 391 insertions(+), 86 deletions(-)

diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index ef0db5a276..45cddd42cc 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -85,7 +85,7 @@ static CRITICAL_SECTION local_handlers_section = { NULL, -1, 0, 0, 0, 0 };
 static struct list local_scheme_handlers = LIST_INIT(local_scheme_handlers);
 static struct list local_bytestream_handlers = LIST_INIT(local_bytestream_handlers);
 
-struct local_mft
+struct mft_registration
 {
     struct list entry;
     IClassFactory *factory;
@@ -107,6 +107,7 @@ struct transform_activate
 {
     struct attributes attributes;
     IMFActivate IMFActivate_iface;
+    IClassFactory *factory;
 };
 
 struct system_clock
@@ -194,6 +195,8 @@ static ULONG WINAPI transform_activate_Release(IMFActivate *iface)
     if (!refcount)
     {
         clear_attributes_object(&activate->attributes);
+        if (activate->factory)
+            IClassFactory_Release(activate->factory);
         heap_free(activate);
     }
 
@@ -537,13 +540,11 @@ static const IMFActivateVtbl transform_activate_vtbl =
     transform_activate_DetachObject,
 };
 
-HRESULT WINAPI MFCreateTransformActivate(IMFActivate **activate)
+static HRESULT create_transform_activate(IClassFactory *factory, IMFActivate **activate)
 {
     struct transform_activate *object;
     HRESULT hr;
 
-    TRACE("%p.\n", activate);
-
     object = heap_alloc_zero(sizeof(*object));
     if (!object)
         return E_OUTOFMEMORY;
@@ -555,12 +556,22 @@ HRESULT WINAPI MFCreateTransformActivate(IMFActivate **activate)
     }
 
     object->IMFActivate_iface.lpVtbl = &transform_activate_vtbl;
+    object->factory = factory;
+    if (object->factory)
+        IClassFactory_AddRef(object->factory);
 
     *activate = &object->IMFActivate_iface;
 
     return S_OK;
 }
 
+HRESULT WINAPI MFCreateTransformActivate(IMFActivate **activate)
+{
+    TRACE("%p.\n", activate);
+
+    return create_transform_activate(NULL, activate);
+}
+
 static const WCHAR transform_keyW[] = {'M','e','d','i','a','F','o','u','n','d','a','t','i','o','n','\\',
                                  'T','r','a','n','s','f','o','r','m','s',0};
 static const WCHAR categories_keyW[] = {'M','e','d','i','a','F','o','u','n','d','a','t','i','o','n','\\',
@@ -648,7 +659,7 @@ static BOOL GUIDFromString(LPCWSTR s, GUID *id)
         id->Data4[(i-19)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
     }
 
-    if (!s[37]) return TRUE;
+    if (!s[36]) return TRUE;
     return FALSE;
 }
 
@@ -774,7 +785,7 @@ HRESULT WINAPI MFTRegister(CLSID clsid, GUID category, LPWSTR name, UINT32 flags
     return hr;
 }
 
-static void release_local_mft(struct local_mft *mft)
+static void release_mft_registration(struct mft_registration *mft)
 {
     if (mft->factory)
         IClassFactory_Release(mft->factory);
@@ -788,7 +799,7 @@ static HRESULT mft_register_local(IClassFactory *factory, REFCLSID clsid, REFGUI
         UINT32 input_count, const MFT_REGISTER_TYPE_INFO *input_types, UINT32 output_count,
         const MFT_REGISTER_TYPE_INFO *output_types)
 {
-    struct local_mft *mft, *cur, *unreg_mft = NULL;
+    struct mft_registration *mft, *cur, *unreg_mft = NULL;
     HRESULT hr;
 
     if (!factory && !clsid)
@@ -807,7 +818,7 @@ static HRESULT mft_register_local(IClassFactory *factory, REFCLSID clsid, REFGUI
     if (clsid)
         mft->clsid = *clsid;
     mft->category = *category;
-    mft->flags = flags;
+    mft->flags = flags | MFT_ENUM_FLAG_LOCALMFT;
     if (FAILED(hr = heap_strdupW(name, &mft->name)))
         goto failed;
 
@@ -835,7 +846,7 @@ static HRESULT mft_register_local(IClassFactory *factory, REFCLSID clsid, REFGUI
 
     EnterCriticalSection(&local_mfts_section);
 
-    LIST_FOR_EACH_ENTRY(cur, &local_mfts, struct local_mft, entry)
+    LIST_FOR_EACH_ENTRY(cur, &local_mfts, struct mft_registration, entry)
     {
         if (cur->factory == factory)
         {
@@ -849,11 +860,11 @@ static HRESULT mft_register_local(IClassFactory *factory, REFCLSID clsid, REFGUI
     LeaveCriticalSection(&local_mfts_section);
 
     if (unreg_mft)
-        release_local_mft(unreg_mft);
+        release_mft_registration(unreg_mft);
 
 failed:
     if (FAILED(hr))
-        release_local_mft(mft);
+        release_mft_registration(mft);
 
     return hr;
 }
@@ -880,7 +891,7 @@ HRESULT WINAPI MFTRegisterLocalByCLSID(REFCLSID clsid, REFGUID category, LPCWSTR
 
 static HRESULT mft_unregister_local(IClassFactory *factory, REFCLSID clsid)
 {
-    struct local_mft *cur, *cur2;
+    struct mft_registration *cur, *cur2;
     BOOL unregister_all = !factory && !clsid;
     struct list unreg;
 
@@ -888,7 +899,7 @@ static HRESULT mft_unregister_local(IClassFactory *factory, REFCLSID clsid)
 
     EnterCriticalSection(&local_mfts_section);
 
-    LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &local_mfts, struct local_mft, entry)
+    LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &local_mfts, struct mft_registration, entry)
     {
         if (!unregister_all)
         {
@@ -911,10 +922,10 @@ static HRESULT mft_unregister_local(IClassFactory *factory, REFCLSID clsid)
     if (!unregister_all && list_empty(&unreg))
         return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
 
-    LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &unreg, struct local_mft, entry)
+    LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &unreg, struct mft_registration, entry)
     {
         list_remove(&cur->entry);
-        release_local_mft(cur);
+        release_mft_registration(cur);
     }
 
     return S_OK;
@@ -945,135 +956,411 @@ MFTIME WINAPI MFGetSystemTime(void)
     return mf;
 }
 
-static BOOL match_type(const WCHAR *clsid_str, const WCHAR *type_str, MFT_REGISTER_TYPE_INFO *type)
+static BOOL mft_is_type_info_match(struct mft_registration *mft, const GUID *category, UINT32 flags,
+        IMFPluginControl *plugin_control, const MFT_REGISTER_TYPE_INFO *input_type,
+        const MFT_REGISTER_TYPE_INFO *output_type)
+{
+    BOOL matching = TRUE;
+    DWORD model;
+    int i;
+
+    if (!IsEqualGUID(category, &mft->category))
+        return FALSE;
+
+    /* Default model is synchronous. */
+    model = mft->flags & (MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_HARDWARE);
+    if (!model)
+        model = MFT_ENUM_FLAG_SYNCMFT;
+    if (!(model & flags & (MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_HARDWARE)))
+        return FALSE;
+
+    /* These flags should be explicitly enabled. */
+    if (mft->flags & ~flags & (MFT_ENUM_FLAG_FIELDOFUSE | MFT_ENUM_FLAG_TRANSCODE_ONLY))
+        return FALSE;
+
+    if (flags & MFT_ENUM_FLAG_SORTANDFILTER && !mft->factory && plugin_control
+            && IMFPluginControl_IsDisabled(plugin_control, MF_Plugin_Type_MFT, &mft->clsid) == S_OK)
+    {
+        return FALSE;
+    }
+
+    if (input_type)
+    {
+        for (i = 0, matching = FALSE; input_type && i < mft->input_types_count; ++i)
+        {
+            if (!memcmp(&mft->input_types[i], input_type, sizeof(*input_type)))
+            {
+                matching = TRUE;
+                break;
+            }
+        }
+    }
+
+    if (output_type && matching)
+    {
+        for (i = 0, matching = FALSE; i < mft->output_types_count; ++i)
+        {
+            if (!memcmp(&mft->output_types[i], output_type, sizeof(*output_type)))
+            {
+                matching = TRUE;
+                break;
+            }
+        }
+    }
+
+    return matching;
+}
+
+static void mft_get_reg_type_info(const WCHAR *clsidW, const WCHAR *typeW, MFT_REGISTER_TYPE_INFO **type,
+        UINT32 *count)
 {
     HKEY htransform, hfilter;
     DWORD reg_type, size;
-    LONG ret = FALSE;
-    MFT_REGISTER_TYPE_INFO *info = NULL;
-    int i;
+
+    *type = NULL;
+    *count = 0;
 
     if (RegOpenKeyW(HKEY_CLASSES_ROOT, transform_keyW, &htransform))
-        return FALSE;
+        return;
 
-    if (RegOpenKeyW(htransform, clsid_str, &hfilter))
+    if (RegOpenKeyW(htransform, clsidW, &hfilter))
     {
         RegCloseKey(htransform);
-        return FALSE;
+        return;
     }
 
-    if (RegQueryValueExW(hfilter, type_str, NULL, &reg_type, NULL, &size) != ERROR_SUCCESS)
+    if (RegQueryValueExW(hfilter, typeW, NULL, &reg_type, NULL, &size))
         goto out;
 
     if (reg_type != REG_BINARY)
         goto out;
 
-    if (!size || size % (sizeof(MFT_REGISTER_TYPE_INFO)) != 0)
+    if (!size || size % sizeof(**type))
         goto out;
 
-    info = HeapAlloc(GetProcessHeap(), 0, size);
-    if (!info)
+    if (!(*type = heap_alloc(size)))
         goto out;
 
-    if (RegQueryValueExW(hfilter, type_str, NULL, &reg_type, (LPBYTE)info, &size) != ERROR_SUCCESS)
-        goto out;
+    *count = size / sizeof(**type);
 
-    for (i = 0; i < size / sizeof(MFT_REGISTER_TYPE_INFO); i++)
+    if (RegQueryValueExW(hfilter, typeW, NULL, &reg_type, (BYTE *)*type, &size))
     {
-        if (IsEqualGUID(&info[i].guidMajorType, &type->guidMajorType) &&
-            IsEqualGUID(&info[i].guidSubtype,   &type->guidSubtype))
-        {
-            ret = TRUE;
-            break;
-        }
+        heap_free(*type);
+        *type = NULL;
+        *count = 0;
     }
 
 out:
-    HeapFree(GetProcessHeap(), 0, info);
     RegCloseKey(hfilter);
     RegCloseKey(htransform);
-    return ret;
 }
 
-/***********************************************************************
- *      MFTEnum (mfplat.@)
- */
-HRESULT WINAPI MFTEnum(GUID category, UINT32 flags, MFT_REGISTER_TYPE_INFO *input_type,
-                       MFT_REGISTER_TYPE_INFO *output_type, IMFAttributes *attributes,
-                       CLSID **pclsids, UINT32 *pcount)
+static void mft_get_reg_flags(const WCHAR *clsidW, const WCHAR *nameW, DWORD *flags)
 {
-    WCHAR buffer[64], clsid_str[MAX_PATH] = {0};
-    HKEY hcategory, hlist;
-    DWORD index = 0;
-    DWORD size = MAX_PATH;
-    CLSID *clsids = NULL;
-    UINT32 count = 0;
-    LONG ret;
+    DWORD ret, reg_type, size;
+    HKEY hroot, hmft;
 
-    TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_guid(&category), flags, input_type,
-                                            output_type, attributes, pclsids, pcount);
+    *flags = 0;
 
-    if (!pclsids || !pcount)
-        return E_INVALIDARG;
+    if (RegOpenKeyW(HKEY_CLASSES_ROOT, transform_keyW, &hroot))
+        return;
+
+    ret = RegOpenKeyW(hroot, clsidW, &hmft);
+    RegCloseKey(hroot);
+    if (ret)
+        return;
+
+    reg_type = 0;
+    if (!RegQueryValueExW(hmft, nameW, NULL, &reg_type, NULL, &size) && reg_type == REG_DWORD)
+        RegQueryValueExW(hmft, nameW, NULL, &reg_type, (BYTE *)flags, &size);
+
+    RegCloseKey(hmft);
+}
+
+static HRESULT mft_collect_machine_reg(struct list *mfts, const GUID *category, UINT32 flags,
+        IMFPluginControl *plugin_control, const MFT_REGISTER_TYPE_INFO *input_type,
+        const MFT_REGISTER_TYPE_INFO *output_type)
+{
+    struct mft_registration mft, *cur;
+    HKEY hcategory, hlist;
+    WCHAR clsidW[64];
+    DWORD ret, size;
+    int index = 0;
 
     if (RegOpenKeyW(HKEY_CLASSES_ROOT, categories_keyW, &hcategory))
         return E_FAIL;
 
-    GUIDToString(buffer, &category);
-
-    ret = RegOpenKeyW(hcategory, buffer, &hlist);
+    GUIDToString(clsidW, category);
+    ret = RegOpenKeyW(hcategory, clsidW, &hlist);
     RegCloseKey(hcategory);
-    if (ret) return E_FAIL;
+    if (ret)
+        return E_FAIL;
 
-    while (RegEnumKeyExW(hlist, index, clsid_str, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
+    size = ARRAY_SIZE(clsidW);
+    while (!RegEnumKeyExW(hlist, index, clsidW, &size, NULL, NULL, NULL, NULL))
     {
-        GUID clsid;
-        void *tmp;
-
-        if (!GUIDFromString(clsid_str, &clsid))
+        memset(&mft, 0, sizeof(mft));
+        mft.category = *category;
+        if (!GUIDFromString(clsidW, &mft.clsid))
             goto next;
 
-        if (output_type && !match_type(clsid_str, outputtypesW, output_type))
-            goto next;
+        mft_get_reg_flags(clsidW, mftflagsW, &mft.flags);
 
-        if (input_type && !match_type(clsid_str, inputtypesW, input_type))
-            goto next;
+        if (output_type)
+            mft_get_reg_type_info(clsidW, outputtypesW, &mft.output_types, &mft.output_types_count);
+
+        if (input_type)
+            mft_get_reg_type_info(clsidW, inputtypesW, &mft.input_types, &mft.input_types_count);
 
-        tmp = CoTaskMemRealloc(clsids, (count + 1) * sizeof(GUID));
-        if (!tmp)
+        if (!mft_is_type_info_match(&mft, category, flags, plugin_control, input_type, output_type))
         {
-            CoTaskMemFree(clsids);
-            RegCloseKey(hlist);
-            return E_OUTOFMEMORY;
+            heap_free(mft.input_types);
+            heap_free(mft.output_types);
+            goto next;
         }
 
-        clsids = tmp;
-        clsids[count++] = clsid;
+        cur = heap_alloc(sizeof(*cur));
+        /* Reuse allocated type arrays. */
+        *cur = mft;
+        list_add_tail(mfts, &cur->entry);
 
     next:
-        size = MAX_PATH;
+        size = ARRAY_SIZE(clsidW);
         index++;
     }
 
-    *pclsids = clsids;
-    *pcount = count;
-
-    RegCloseKey(hlist);
     return S_OK;
 }
 
+static BOOL mft_is_preferred(IMFPluginControl *plugin_control, const CLSID *clsid)
+{
+    CLSID preferred;
+    WCHAR *selector;
+    int index = 0;
+
+    while (SUCCEEDED(IMFPluginControl_GetPreferredClsidByIndex(plugin_control, MF_Plugin_Type_MFT, index++, &selector,
+            &preferred)))
+    {
+        CoTaskMemFree(selector);
+
+        if (IsEqualGUID(&preferred, clsid))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+static HRESULT mft_enum(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INFO *input_type,
+        const MFT_REGISTER_TYPE_INFO *output_type, IMFAttributes *attributes, IMFActivate ***activate, UINT32 *count)
+{
+    IMFPluginControl *plugin_control = NULL;
+    struct list mfts, mfts_sorted, *result = &mfts;
+    struct mft_registration *mft, *mft2;
+    unsigned int obj_count;
+    HRESULT hr;
+
+    *count = 0;
+    *activate = NULL;
+
+    if (!flags)
+        flags = MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_LOCALMFT | MFT_ENUM_FLAG_SORTANDFILTER;
+
+    /* Synchronous processing is default. */
+    if (!(flags & (MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_HARDWARE)))
+        flags |= MFT_ENUM_FLAG_SYNCMFT;
+
+    if (FAILED(hr = MFGetPluginControl(&plugin_control)))
+    {
+        WARN("Failed to get plugin control instance, hr %#x.\n", hr);
+        return hr;
+    }
+
+    list_init(&mfts);
+
+    /* Collect from registry */
+    mft_collect_machine_reg(&mfts, &category, flags, plugin_control, input_type, output_type);
+
+    /* Collect locally registered ones. */
+    if (flags & MFT_ENUM_FLAG_LOCALMFT)
+    {
+        struct mft_registration *local;
+
+        EnterCriticalSection(&local_mfts_section);
+
+        LIST_FOR_EACH_ENTRY(local, &local_mfts, struct mft_registration, entry)
+        {
+            if (mft_is_type_info_match(local, &category, flags, plugin_control, input_type, output_type))
+            {
+                mft = heap_alloc_zero(sizeof(*mft));
+
+                mft->clsid = local->clsid;
+                mft->factory = local->factory;
+                if (mft->factory)
+                    IClassFactory_AddRef(mft->factory);
+                mft->flags = local->flags;
+
+                list_add_tail(&mfts, &mft->entry);
+            }
+        }
+
+        LeaveCriticalSection(&local_mfts_section);
+    }
+
+    list_init(&mfts_sorted);
+
+    if (flags & MFT_ENUM_FLAG_SORTANDFILTER)
+    {
+        /* Local registrations. */
+        LIST_FOR_EACH_ENTRY_SAFE(mft, mft2, &mfts, struct mft_registration, entry)
+        {
+            if (mft->flags & MFT_ENUM_FLAG_LOCALMFT)
+            {
+                list_remove(&mft->entry);
+                list_add_tail(&mfts_sorted, &mft->entry);
+            }
+        }
+
+        /* FIXME: Sort by merit value, for the ones that got it. Currently not handled. */
+
+        /* Preferred transforms. */
+        LIST_FOR_EACH_ENTRY_SAFE(mft, mft2, &mfts, struct mft_registration, entry)
+        {
+            if (!mft->factory && mft_is_preferred(plugin_control, &mft->clsid))
+            {
+                list_remove(&mft->entry);
+                list_add_tail(&mfts_sorted, &mft->entry);
+            }
+        }
+
+        /* Append the rest. */
+        LIST_FOR_EACH_ENTRY_SAFE(mft, mft2, &mfts, struct mft_registration, entry)
+        {
+            list_remove(&mft->entry);
+            list_add_tail(&mfts_sorted, &mft->entry);
+        }
+
+        result = &mfts;
+    }
+
+    IMFPluginControl_Release(plugin_control);
+
+    /* Create activation objects from CLSID/IClassFactory. */
+
+    obj_count = list_count(result);
+
+    if (obj_count)
+    {
+        if (!(*activate = CoTaskMemAlloc(obj_count * sizeof(**activate))))
+            hr = E_OUTOFMEMORY;
+
+        obj_count = 0;
+
+        LIST_FOR_EACH_ENTRY_SAFE(mft, mft2, result, struct mft_registration, entry)
+        {
+            IMFActivate *mft_activate;
+
+            if (*activate)
+            {
+                if (SUCCEEDED(create_transform_activate(mft->factory, &mft_activate)))
+                {
+                    (*activate)[obj_count] = mft_activate;
+
+                    /* FIXME: set some attributes */
+
+                    obj_count++;
+                }
+            }
+
+            list_remove(&mft->entry);
+            release_mft_registration(mft);
+        }
+    }
+
+    if (!obj_count)
+    {
+        CoTaskMemFree(*activate);
+        *activate = NULL;
+    }
+    *count = obj_count;
+
+    return hr;
+}
+
+/***********************************************************************
+ *      MFTEnum (mfplat.@)
+ */
+HRESULT WINAPI MFTEnum(GUID category, UINT32 flags, MFT_REGISTER_TYPE_INFO *input_type,
+        MFT_REGISTER_TYPE_INFO *output_type, IMFAttributes *attributes, CLSID **clsids, UINT32 *count)
+{
+    struct mft_registration *mft, *mft2;
+    unsigned int mft_count;
+    struct list mfts;
+    HRESULT hr;
+
+    TRACE("%s, %#x, %p, %p, %p, %p, %p.\n", debugstr_guid(&category), flags, input_type, output_type, attributes,
+            clsids, count);
+
+    if (!clsids || !count)
+        return E_INVALIDARG;
+
+    *count = 0;
+
+    list_init(&mfts);
+
+    if (FAILED(hr = mft_collect_machine_reg(&mfts, &category, MFT_ENUM_FLAG_SYNCMFT, NULL, input_type, output_type)))
+        return hr;
+
+    mft_count = list_count(&mfts);
+
+    if (mft_count)
+    {
+        if (!(*clsids = CoTaskMemAlloc(mft_count * sizeof(**clsids))))
+            hr = E_OUTOFMEMORY;
+
+        mft_count = 0;
+        LIST_FOR_EACH_ENTRY_SAFE(mft, mft2, &mfts, struct mft_registration, entry)
+        {
+            if (*clsids)
+                (*clsids)[mft_count++] = mft->clsid;
+            list_remove(&mft->entry);
+            release_mft_registration(mft);
+        }
+    }
+
+    if (!mft_count)
+    {
+        CoTaskMemFree(*clsids);
+        *clsids = NULL;
+    }
+    *count = mft_count;
+
+    return hr;
+}
+
 /***********************************************************************
  *      MFTEnumEx (mfplat.@)
  */
 HRESULT WINAPI MFTEnumEx(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INFO *input_type,
-                         const MFT_REGISTER_TYPE_INFO *output_type, IMFActivate ***activate,
-                         UINT32 *pcount)
+        const MFT_REGISTER_TYPE_INFO *output_type, IMFActivate ***activate, UINT32 *count)
 {
-    FIXME("(%s, %x, %p, %p, %p, %p): stub\n", debugstr_guid(&category), flags, input_type,
-                                              output_type, activate, pcount);
+    TRACE("%s, %#x, %p, %p, %p, %p.\n", debugstr_guid(&category), flags, input_type, output_type, activate, count);
 
-    *pcount = 0;
-    return S_OK;
+    return mft_enum(category, flags, input_type, output_type, NULL, activate, count);
+}
+
+/***********************************************************************
+ *      MFTEnum2 (mfplat.@)
+ */
+HRESULT WINAPI MFTEnum2(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INFO *input_type,
+        const MFT_REGISTER_TYPE_INFO *output_type, IMFAttributes *attributes, IMFActivate ***activate, UINT32 *count)
+{
+    TRACE("%s, %#x, %p, %p, %p, %p, %p.\n", debugstr_guid(&category), flags, input_type, output_type, attributes,
+            activate, count);
+
+    if (attributes)
+        FIXME("Ignoring attributes.\n");
+
+    return mft_enum(category, flags, input_type, output_type, attributes, activate, count);
 }
 
 /***********************************************************************
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec
index 85e28792c6..7e3bd4571c 100644
--- a/dlls/mfplat/mfplat.spec
+++ b/dlls/mfplat/mfplat.spec
@@ -144,6 +144,7 @@
 @ stdcall MFStartup(long long)
 @ stub MFStreamDescriptorProtectMediaType
 @ stdcall MFTEnum(int128 long ptr ptr ptr ptr ptr)
+@ stdcall MFTEnum2(int128 long ptr ptr ptr ptr ptr)
 @ stdcall MFTEnumEx(int128 long ptr ptr ptr ptr)
 @ stub MFTGetInfo
 @ stdcall MFTRegister(int128 int128 wstr long long ptr long ptr ptr)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 896cd93a46..a93bbfe7f1 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -89,6 +89,8 @@ static HRESULT (WINAPI *pMFTRegisterLocalByCLSID)(REFCLSID clsid, REFGUID catego
 static HRESULT (WINAPI *pMFTUnregisterLocal)(IClassFactory *factory);
 static HRESULT (WINAPI *pMFTUnregisterLocalByCLSID)(CLSID clsid);
 static HRESULT (WINAPI *pMFAllocateWorkQueueEx)(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue);
+static HRESULT (WINAPI *pMFTEnumEx)(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INFO *input_type,
+        const MFT_REGISTER_TYPE_INFO *output_type, IMFActivate ***activate, UINT32 *count);
 
 static const WCHAR fileschemeW[] = L"file://";
 
@@ -659,13 +661,14 @@ static void init_functions(void)
     X(MFCreateDXGIDeviceManager);
     X(MFCreateSourceResolver);
     X(MFCreateMFByteStreamOnStream);
+    X(MFCreateTransformActivate);
     X(MFHeapAlloc);
     X(MFHeapFree);
     X(MFPutWaitingWorkItem);
     X(MFRegisterLocalByteStreamHandler);
     X(MFRegisterLocalSchemeHandler);
     X(MFRemovePeriodicCallback);
-    X(MFCreateTransformActivate);
+    X(MFTEnumEx);
     X(MFTRegisterLocal);
     X(MFTRegisterLocalByCLSID);
     X(MFTUnregisterLocal);
@@ -4055,6 +4058,8 @@ static void test_MFTRegisterLocal(void)
 {
     IClassFactory test_factory = { &test_mft_factory_vtbl };
     MFT_REGISTER_TYPE_INFO input_types[1];
+    IMFActivate **activate;
+    UINT32 count, count2;
     HRESULT hr;
 
     if (!pMFTRegisterLocal)
@@ -4071,9 +4076,19 @@ static void test_MFTRegisterLocal(void)
     hr = pMFTRegisterLocal(&test_factory, &MFT_CATEGORY_OTHER, L"Local MFT name", 0, 1, input_types, 0, NULL);
     ok(hr == S_OK, "Failed to register MFT, hr %#x.\n", hr);
 
+    hr = pMFTEnumEx(MFT_CATEGORY_OTHER, MFT_ENUM_FLAG_LOCALMFT, NULL, NULL, &activate, &count);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(count > 0, "Unexpected count %u.\n", count);
+    CoTaskMemFree(activate);
+
     hr = pMFTUnregisterLocal(&test_factory);
     ok(hr == S_OK, "Failed to unregister MFT, hr %#x.\n", hr);
 
+    hr = pMFTEnumEx(MFT_CATEGORY_OTHER, MFT_ENUM_FLAG_LOCALMFT, NULL, NULL, &activate, &count2);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(count2 < count, "Unexpected count %u.\n", count2);
+    CoTaskMemFree(activate);
+
     hr = pMFTUnregisterLocal(&test_factory);
     ok(hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Unexpected hr %#x.\n", hr);
 
diff --git a/include/mfapi.h b/include/mfapi.h
index 910b45e68f..4d5ad5ad15 100644
--- a/include/mfapi.h
+++ b/include/mfapi.h
@@ -422,6 +422,8 @@ HRESULT WINAPI MFGetTimerPeriodicity(DWORD *periodicity);
 HRESULT WINAPI MFTEnum(GUID category, UINT32 flags, MFT_REGISTER_TYPE_INFO *input_type,
                        MFT_REGISTER_TYPE_INFO *output_type, IMFAttributes *attributes,
                        CLSID **pclsids, UINT32 *pcount);
+HRESULT WINAPI MFTEnum2(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INFO *input_type,
+        const MFT_REGISTER_TYPE_INFO *output_type, IMFAttributes *attributes, IMFActivate ***activate, UINT32 *count);
 HRESULT WINAPI MFTEnumEx(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INFO *input_type,
                          const MFT_REGISTER_TYPE_INFO *output_type, IMFActivate ***activate,
                          UINT32 *pcount);
-- 
2.25.1




More information about the wine-devel mailing list