Signed-off-by: Nikolay Sivov <nsivov(a)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, ®_type, NULL, &size) != ERROR_SUCCESS)
+ if (RegQueryValueExW(hfilter, typeW, NULL, ®_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, ®_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, ®_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, ®_type, NULL, &size) && reg_type == REG_DWORD)
+ RegQueryValueExW(hmft, nameW, NULL, ®_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