Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/devenum/tests/devenum.c | 109 +++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 61 deletions(-)
diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index 5a41183..575aebd 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -30,57 +30,56 @@
static const WCHAR friendly_name[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; static const WCHAR fcc_handlerW[] = {'F','c','c','H','a','n','d','l','e','r',0}; +static const WCHAR clsidW[] = {'C','L','S','I','D',0}; static const WCHAR mrleW[] = {'m','r','l','e',0};
-struct category -{ - const char * name; - const GUID * clsid; -}; - -static struct category am_categories[] = -{ - { "Legacy AM Filter category", &CLSID_LegacyAmFilterCategory }, - { "Audio renderer category", &CLSID_AudioRendererCategory }, - { "Midi renderer category", &CLSID_MidiRendererCategory }, - { "Audio input device category", &CLSID_AudioInputDeviceCategory }, - { "Video input device category", &CLSID_VideoInputDeviceCategory }, - { "Audio compressor category", &CLSID_AudioCompressorCategory }, - { "Video compressor category", &CLSID_VideoCompressorCategory } -}; - static void test_devenum(IBindCtx *bind_ctx) { - HRESULT res; + IEnumMoniker *enum_cat, *enum_moniker; ICreateDevEnum* create_devenum; - IEnumMoniker* enum_moniker = NULL; + IPropertyBag *prop_bag; + IMoniker *moniker; BOOL have_mrle = FALSE; - int i; + GUID cat_guid, clsid; + VARIANT var; + HRESULT hr;
- res = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, + hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (LPVOID*)&create_devenum); - if (res != S_OK) { - skip("Cannot create SystemDeviceEnum object (%x)\n", res); - return; - } + ok(hr == S_OK, "Failed to create devenum: %#x\n", hr);
- for (i = 0; i < (sizeof(am_categories) / sizeof(struct category)); i++) + hr = ICreateDevEnum_CreateClassEnumerator(create_devenum, &CLSID_ActiveMovieCategories, &enum_cat, 0); + ok(hr == S_OK, "Failed to enum categories: %#x\n", hr); + + while (IEnumMoniker_Next(enum_cat, 1, &moniker, NULL) == S_OK) { + hr = IMoniker_BindToStorage(moniker, bind_ctx, NULL, &IID_IPropertyBag, (void **)&prop_bag); + ok(hr == S_OK, "IMoniker_BindToStorage failed: %#x\n", hr); + + VariantInit(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == S_OK, "Failed to read FriendlyName: %#x\n", hr); + if (winetest_debug > 1) - trace("%s:\n", am_categories[i].name); + trace("%s:\n", wine_dbgstr_w(V_BSTR(&var))); + + VariantClear(&var); + hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL); + ok(hr == S_OK, "Failed to read CLSID: %#x\n", hr); + + hr = CLSIDFromString(V_BSTR(&var), &cat_guid); + ok(hr == S_OK, "got %#x\n", hr); + + IPropertyBag_Release(prop_bag); + IMoniker_Release(moniker); + + hr = ICreateDevEnum_CreateClassEnumerator(create_devenum, &cat_guid, &enum_moniker, 0); + ok(SUCCEEDED(hr), "Failed to enum devices: %#x\n", hr);
- res = ICreateDevEnum_CreateClassEnumerator(create_devenum, am_categories[i].clsid, &enum_moniker, 0); - ok(SUCCEEDED(res), "Cannot create enum moniker (res = %x)\n", res); - if (res == S_OK) + if (hr == S_OK) { - IMoniker* moniker; while (IEnumMoniker_Next(enum_moniker, 1, &moniker, NULL) == S_OK) { - IPropertyBag* prop_bag = NULL; - VARIANT var; - HRESULT hr; - CLSID clsid = {0}; - hr = IMoniker_GetClassID(moniker, NULL); ok(hr == E_INVALIDARG, "IMoniker_GetClassID should failed %x\n", hr);
@@ -93,36 +92,24 @@ static void test_devenum(IBindCtx *bind_ctx) hr = IMoniker_BindToStorage(moniker, bind_ctx, NULL, &IID_IPropertyBag, (LPVOID*)&prop_bag); ok(hr == S_OK, "IMoniker_BindToStorage failed with error %x\n", hr);
- if (SUCCEEDED(hr)) - { - hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); - ok((hr == S_OK) || broken(hr == 0x80070002), "IPropertyBag_Read failed with error %x\n", hr); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == S_OK, "IPropertyBag_Read failed: %#x\n", hr);
- if (SUCCEEDED(hr)) - { - if (winetest_debug > 1) - trace(" %s\n", wine_dbgstr_w(V_BSTR(&var))); - VariantClear(&var); - } - else - { - trace(" ???\n"); - } + if (winetest_debug > 1) + trace(" %s\n", wine_dbgstr_w(V_BSTR(&var)));
- if (IsEqualGUID(&CLSID_VideoCompressorCategory, am_categories[i].clsid)) { - /* Test well known compressor to ensure that we really enumerate codecs */ - hr = IPropertyBag_Read(prop_bag, fcc_handlerW, &var, NULL); - if (SUCCEEDED(hr)) { - ok(V_VT(&var) == VT_BSTR, "V_VT(var) = %d\n", V_VT(&var)); - if(!lstrcmpW(V_BSTR(&var), mrleW)) - have_mrle = TRUE; - VariantClear(&var); - } + if (IsEqualGUID(&CLSID_VideoCompressorCategory, &cat_guid)) { + /* Test well known compressor to ensure that we really enumerate codecs */ + hr = IPropertyBag_Read(prop_bag, fcc_handlerW, &var, NULL); + if (SUCCEEDED(hr)) { + ok(V_VT(&var) == VT_BSTR, "V_VT(var) = %d\n", V_VT(&var)); + if(!lstrcmpW(V_BSTR(&var), mrleW)) + have_mrle = TRUE; + VariantClear(&var); } }
- if (prop_bag) - IPropertyBag_Release(prop_bag); + IPropertyBag_Release(prop_bag); IMoniker_Release(moniker); } IEnumMoniker_Release(enum_moniker);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/devenum/tests/devenum.c | 74 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-)
diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index 575aebd..79189f3 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -211,7 +211,78 @@ static void test_moniker_isequal(void) return; }
-/* CLSID_CDeviceMoniker */ +static BOOL find_moniker(const GUID *class, IMoniker *needle) +{ + ICreateDevEnum *devenum; + IEnumMoniker *enum_mon; + IMoniker *mon; + BOOL found = FALSE; + + CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (void **)&devenum); + ICreateDevEnum_CreateClassEnumerator(devenum, class, &enum_mon, 0); + while (!found && IEnumMoniker_Next(enum_mon, 1, &mon, NULL) == S_OK) + { + if (IMoniker_IsEqual(mon, needle) == S_OK) + found = TRUE; + + IMoniker_Release(mon); + } + + IEnumMoniker_Release(enum_mon); + ICreateDevEnum_Release(devenum); + return found; +} + +DEFINE_GUID(CLSID_TestFilter, 0xdeadbeef,0xcf51,0x43e6,0xb6,0xc5,0x29,0x9e,0xa8,0xb6,0xb5,0x91); + +static void test_register_filter(void) +{ + static const WCHAR name[] = {'d','e','v','e','n','u','m',' ','t','e','s','t',0}; + IFilterMapper2 *mapper2; + IMoniker *mon = NULL; + REGFILTER2 rgf2 = {0}; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2, (void **)&mapper2); + ok(hr == S_OK, "Failed to create FilterMapper2: %#x\n", hr); + + rgf2.dwVersion = 2; + rgf2.dwMerit = MERIT_UNLIKELY; + S2(U(rgf2)).cPins2 = 0; + + hr = IFilterMapper2_RegisterFilter(mapper2, &CLSID_TestFilter, name, &mon, NULL, NULL, &rgf2); + if (hr == E_ACCESSDENIED) + { + skip("Not enough permissions to register filters\n"); + IFilterMapper2_Release(mapper2); + return; + } + ok(hr == S_OK, "RegisterFilter failed: %#x\n", hr); + + ok(find_moniker(&CLSID_LegacyAmFilterCategory, mon), "filter should be registered\n"); + + hr = IFilterMapper2_UnregisterFilter(mapper2, NULL, NULL, &CLSID_TestFilter); + ok(hr == S_OK, "UnregisterFilter failed: %#x\n", hr); + + ok(!find_moniker(&CLSID_LegacyAmFilterCategory, mon), "filter should not be registered\n"); + IMoniker_Release(mon); + + mon = NULL; + hr = IFilterMapper2_RegisterFilter(mapper2, &CLSID_TestFilter, name, &mon, &CLSID_AudioRendererCategory, NULL, &rgf2); + ok(hr == S_OK, "RegisterFilter failed: %#x\n", hr); + + ok(find_moniker(&CLSID_AudioRendererCategory, mon), "filter should be registered\n"); + + hr = IFilterMapper2_UnregisterFilter(mapper2, &CLSID_AudioRendererCategory, NULL, &CLSID_TestFilter); +todo_wine + ok(hr == S_OK, "UnregisterFilter failed: %#x\n", hr); + +todo_wine + ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "filter should not be registered\n"); + IMoniker_Release(mon); + + IFilterMapper2_Release(mapper2); +}
START_TEST(devenum) { @@ -231,6 +302,7 @@ START_TEST(devenum) }
test_moniker_isequal(); + test_register_filter();
CoUninitialize(); }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- A devenum device comes in one of four types: DirectShow filter, DMO, audio or video codec, or PNP device. Each of these is identified in a slightly different way.
* A DirectShow filter (sw) is identified by a subkey under the CLSID key. They're normally registered through IFilterMapper2:RegisterFilter. devenum doesn't touch these keys, but rather just reads from them; it translates every key/value pair directly into an IPropertyBag property.
* An audio or video codec (cm) is identified by a subkey under the HKCU\Software\Microsoft\ActiveMovie\devenum key. This key is populated by devenum from a variety of sources, including the "legacy" HKCR\Filters key and the Drivers32 key. After being populated, it's read in the same way as the DirectShow filters above.
* A DMO (dmo) is identified by its CLSID and its category GUID, in that order. These aren't read in the same way as the above; rather, the key/value pairs are translated from the DMO storage format into the devenum format.
* A PNP device (pnp) is identified by a path in the global namespace, i.e. beginning with '\?'. devenum read these from the registry at the path CurrentControlSet\Control\DeviceClasses{category guid}##?#Root#SYSTEM#0000#{category guid}, and the properties for the IPropertyBag are given by the subkey "Device Parameters".
Previously, the code treated filters as "normal" and codecs as "special", and assumed the difference lay in which category a device was registered under. As the tests show, however, devenum will enumerate all of the available device types for any given category.
v2: fix test failures.
dlls/devenum/createdevenum.c | 134 ++++++------------------------------- dlls/devenum/devenum_private.h | 23 ++++--- dlls/devenum/mediacatenum.c | 100 +++++++++++++++------------ dlls/devenum/parsedisplayname.c | 42 ++++++++---- dlls/devenum/tests/devenum.c | 145 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 267 insertions(+), 177 deletions(-)
diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c index 17d9850..7cfdbff 100644 --- a/dlls/devenum/createdevenum.c +++ b/dlls/devenum/createdevenum.c @@ -38,13 +38,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(devenum);
extern HINSTANCE DEVENUM_hInstance;
-const WCHAR wszInstanceKeyName[] ={'\','I','n','s','t','a','n','c','e',0}; - static const WCHAR wszRegSeparator[] = {'\', 0 }; -static 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 const WCHAR wszFilterKeyName[] = {'F','i','l','t','e','r',0}; static const WCHAR wszMeritName[] = {'M','e','r','i','t',0}; static const WCHAR wszPins[] = {'P','i','n','s',0}; @@ -58,7 +52,7 @@ static const WCHAR wszWaveInID[] = {'W','a','v','e','I','n','I','D',0}; static const WCHAR wszWaveOutID[] = {'W','a','v','e','O','u','t','I','D',0};
static ULONG WINAPI DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum * iface); -static HRESULT DEVENUM_CreateSpecialCategories(void); +static HRESULT register_codecs(void);
/********************************************************************** * DEVENUM_ICreateDevEnum_QueryInterface (also IUnknown) @@ -108,63 +102,6 @@ static ULONG WINAPI DEVENUM_ICreateDevEnum_Release(ICreateDevEnum * iface) return 1; /* non-heap based object */ }
-static BOOL IsSpecialCategory(const CLSID *clsid) -{ - return IsEqualGUID(clsid, &CLSID_AudioRendererCategory) || - IsEqualGUID(clsid, &CLSID_AudioInputDeviceCategory) || - IsEqualGUID(clsid, &CLSID_VideoInputDeviceCategory) || - IsEqualGUID(clsid, &CLSID_VideoCompressorCategory) || - IsEqualGUID(clsid, &CLSID_MidiRendererCategory); -} - -HRESULT DEVENUM_GetCategoryKey(REFCLSID clsidDeviceClass, HKEY *pBaseKey, WCHAR *wszRegKeyName, UINT maxLen) -{ - if (IsSpecialCategory(clsidDeviceClass)) - { - *pBaseKey = HKEY_CURRENT_USER; - strcpyW(wszRegKeyName, wszActiveMovieKey); - - if (!StringFromGUID2(clsidDeviceClass, wszRegKeyName + strlenW(wszRegKeyName), maxLen - strlenW(wszRegKeyName))) - return E_OUTOFMEMORY; - } - else - { - *pBaseKey = HKEY_CLASSES_ROOT; - strcpyW(wszRegKeyName, clsid_keyname); - strcatW(wszRegKeyName, wszRegSeparator); - - if (!StringFromGUID2(clsidDeviceClass, wszRegKeyName + CLSID_STR_LEN, maxLen - CLSID_STR_LEN)) - return E_OUTOFMEMORY; - - strcatW(wszRegKeyName, wszInstanceKeyName); - } - - return S_OK; -} - -static HKEY open_category_key(const CLSID *clsid) -{ - WCHAR key_name[sizeof(wszInstanceKeyName)/sizeof(WCHAR) + CHARS_IN_GUID-1 + 6 /* strlen("CLSID") */], *ptr; - HKEY ret; - - strcpyW(key_name, clsid_keyname); - ptr = key_name + strlenW(key_name); - *ptr++ = '\'; - - if (!StringFromGUID2(clsid, ptr, CHARS_IN_GUID)) - return NULL; - - ptr += strlenW(ptr); - strcpyW(ptr, wszInstanceKeyName); - - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, key_name, 0, KEY_READ, &ret) != ERROR_SUCCESS) { - WARN("Could not open %s\n", debugstr_w(key_name)); - return NULL; - } - - return ret; -} - static HKEY open_special_category_key(const CLSID *clsid, BOOL create) { WCHAR key_name[sizeof(wszActiveMovieKey)/sizeof(WCHAR) + CHARS_IN_GUID-1]; @@ -400,14 +337,13 @@ static HRESULT DEVENUM_RegisterLegacyAmFilters(void) { WCHAR wszFilterSubkeyName[64]; DWORD cName = sizeof(wszFilterSubkeyName) / sizeof(WCHAR); - HKEY hkeyCategoryBaseKey; WCHAR wszRegKey[MAX_PATH]; HKEY hkeyInstance = NULL;
if (RegEnumKeyExW(hkeyFilter, i, wszFilterSubkeyName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
- hr = DEVENUM_GetCategoryKey(&CLSID_LegacyAmFilterCategory, &hkeyCategoryBaseKey, wszRegKey, MAX_PATH); - if (FAILED(hr)) continue; + strcpyW(wszRegKey, wszActiveMovieKey); + StringFromGUID2(&CLSID_LegacyAmFilterCategory, wszRegKey + strlenW(wszRegKey), CHARS_IN_GUID);
strcatW(wszRegKey, wszRegSeparator); strcatW(wszRegKey, wszFilterSubkeyName); @@ -512,9 +448,6 @@ static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator( IEnumMoniker **ppEnumMoniker, DWORD dwFlags) { - HKEY hkey, special_hkey = NULL; - HRESULT hr; - TRACE("(%p)->(%s, %p, %x)\n", iface, debugstr_guid(clsidDeviceClass), ppEnumMoniker, dwFlags);
if (!ppEnumMoniker) @@ -522,34 +455,10 @@ static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator(
*ppEnumMoniker = NULL;
- if (IsEqualGUID(clsidDeviceClass, &CLSID_LegacyAmFilterCategory)) - { - DEVENUM_RegisterLegacyAmFilters(); - } - - if (IsSpecialCategory(clsidDeviceClass)) - { - hr = DEVENUM_CreateSpecialCategories(); - if (FAILED(hr)) - return hr; - - special_hkey = open_special_category_key(clsidDeviceClass, FALSE); - if (!special_hkey) - { - ERR("Couldn't open registry key for special device: %s\n", - debugstr_guid(clsidDeviceClass)); - return S_FALSE; - } - } + register_codecs(); + DEVENUM_RegisterLegacyAmFilters();
- hkey = open_category_key(clsidDeviceClass); - if (!hkey && !special_hkey) - { - FIXME("Category %s not found\n", debugstr_guid(clsidDeviceClass)); - return S_FALSE; - } - - return DEVENUM_IEnumMoniker_Construct(hkey, special_hkey, ppEnumMoniker); + return create_EnumMoniker(clsidDeviceClass, ppEnumMoniker); }
/********************************************************************** @@ -644,22 +553,17 @@ static const WCHAR DEVENUM_populate_handle_nameW[] = 'D','e','v','e','n','u','m','_', 'P','o','p','u','l','a','t','e',0};
-/********************************************************************** - * DEVENUM_CreateSpecialCategories (INTERNAL) - * - * Creates the keys in the registry for the dynamic categories - */ -static HRESULT DEVENUM_CreateSpecialCategories(void) +static HRESULT register_codecs(void) { HRESULT res; WCHAR szDSoundNameFormat[MAX_PATH + 1]; WCHAR szDSoundName[MAX_PATH + 1]; + WCHAR class[CHARS_IN_GUID]; DWORD iDefaultDevice = -1; UINT numDevs; IFilterMapper2 * pMapper = NULL; REGFILTER2 rf2; REGFILTERPINS2 rfp2; - WCHAR path[MAX_PATH]; HKEY basekey;
if (DEVENUM_populate_handle) @@ -680,16 +584,18 @@ static HRESULT DEVENUM_CreateSpecialCategories(void) /* Since devices can change between session, for example because you just plugged in a webcam * or switched from pulseaudio to alsa, delete all old devices first */ - if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_AudioRendererCategory, &basekey, path, MAX_PATH))) - RegDeleteTreeW(basekey, path); - if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_AudioInputDeviceCategory, &basekey, path, MAX_PATH))) - RegDeleteTreeW(basekey, path); - if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_VideoInputDeviceCategory, &basekey, path, MAX_PATH))) - RegDeleteTreeW(basekey, path); - if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_MidiRendererCategory, &basekey, path, MAX_PATH))) - RegDeleteTreeW(basekey, path); - if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_VideoCompressorCategory, &basekey, path, MAX_PATH))) - RegDeleteTreeW(basekey, path); + RegOpenKeyW(HKEY_CURRENT_USER, wszActiveMovieKey, &basekey); + StringFromGUID2(&CLSID_AudioRendererCategory, class, CHARS_IN_GUID); + RegDeleteTreeW(basekey, class); + StringFromGUID2(&CLSID_AudioInputDeviceCategory, class, CHARS_IN_GUID); + RegDeleteTreeW(basekey, class); + StringFromGUID2(&CLSID_VideoInputDeviceCategory, class, CHARS_IN_GUID); + RegDeleteTreeW(basekey, class); + StringFromGUID2(&CLSID_MidiRendererCategory, class, CHARS_IN_GUID); + RegDeleteTreeW(basekey, class); + StringFromGUID2(&CLSID_VideoCompressorCategory, class, CHARS_IN_GUID); + RegDeleteTreeW(basekey, class); + RegCloseKey(basekey);
rf2.dwVersion = 2; rf2.dwMerit = MERIT_PREFERRED; diff --git a/dlls/devenum/devenum_private.h b/dlls/devenum/devenum_private.h index 347aebb..bcc5085 100644 --- a/dlls/devenum/devenum_private.h +++ b/dlls/devenum/devenum_private.h @@ -60,6 +60,12 @@ typedef struct IClassFactory IClassFactory_iface; } ClassFactoryImpl;
+enum device_type +{ + DEVICE_FILTER, + DEVICE_CODEC, +}; + typedef struct { IMoniker IMoniker_iface; @@ -68,23 +74,24 @@ typedef struct } MediaCatMoniker;
MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void) DECLSPEC_HIDDEN; -HRESULT DEVENUM_IEnumMoniker_Construct(HKEY hkey, HKEY special_hkey, IEnumMoniker ** ppEnumMoniker) DECLSPEC_HIDDEN; +HRESULT create_EnumMoniker(REFCLSID class, IEnumMoniker **enum_mon) DECLSPEC_HIDDEN;
extern ClassFactoryImpl DEVENUM_ClassFactory DECLSPEC_HIDDEN; extern ICreateDevEnum DEVENUM_CreateDevEnum DECLSPEC_HIDDEN; extern IParseDisplayName DEVENUM_ParseDisplayName DECLSPEC_HIDDEN;
/********************************************************************** - * Private helper function to get AM filter category key location - */ -HRESULT DEVENUM_GetCategoryKey(REFCLSID clsidDeviceClass, HKEY *pBaseKey, WCHAR *wszRegKeyName, UINT maxLen) DECLSPEC_HIDDEN; - -/********************************************************************** * Global string constant declarations */ + +static const WCHAR clsidW[] = {'C','L','S','I','D','\',0}; +static const WCHAR instanceW[] = {'\','I','n','s','t','a','n','c','e',0}; +static 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}; + extern const WCHAR clsid_keyname[6] DECLSPEC_HIDDEN; -extern const WCHAR wszInstanceKeyName[] DECLSPEC_HIDDEN; -#define CLSID_STR_LEN (sizeof(clsid_keyname) / sizeof(WCHAR))
/********************************************************************** * Resource IDs diff --git a/dlls/devenum/mediacatenum.c b/dlls/devenum/mediacatenum.c index 4edc4e9..583ca7d 100644 --- a/dlls/devenum/mediacatenum.c +++ b/dlls/devenum/mediacatenum.c @@ -34,10 +34,10 @@ typedef struct { IEnumMoniker IEnumMoniker_iface; LONG ref; - DWORD index; - DWORD subkey_cnt; - HKEY hkey; - HKEY special_hkey; + HKEY sw_key; + DWORD sw_index; + HKEY cm_key; + DWORD cm_index; } EnumMonikerImpl;
typedef struct @@ -748,9 +748,8 @@ static ULONG WINAPI DEVENUM_IEnumMoniker_Release(IEnumMoniker *iface)
if (!ref) { - if(This->special_hkey) - RegCloseKey(This->special_hkey); - RegCloseKey(This->hkey); + RegCloseKey(This->sw_key); + RegCloseKey(This->cm_key); CoTaskMemFree(This); DEVENUM_UnlockModule(); return 0; @@ -766,37 +765,42 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, LONG res; ULONG fetched = 0; MediaCatMoniker * pMoniker; + HKEY hkey;
TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched);
while (fetched < celt) { - if(This->index+fetched < This->subkey_cnt) - res = RegEnumKeyW(This->hkey, This->index+fetched, buffer, sizeof(buffer) / sizeof(WCHAR)); - else if(This->special_hkey) - res = RegEnumKeyW(This->special_hkey, This->index+fetched-This->subkey_cnt, buffer, sizeof(buffer) / sizeof(WCHAR)); - else - break; - if (res != ERROR_SUCCESS) + /* FIXME: try PNP devices and DMOs first */ + + /* try DirectShow filters */ + if (!(res = RegEnumKeyW(This->sw_key, This->sw_index, buffer, sizeof(buffer)/sizeof(WCHAR)))) { - break; + This->sw_index++; + if ((res = RegOpenKeyExW(This->sw_key, buffer, 0, KEY_QUERY_VALUE, &hkey))) + break; } + /* then try codecs */ + else if (!(res = RegEnumKeyW(This->cm_key, This->cm_index, buffer, sizeof(buffer)/sizeof(WCHAR)))) + { + This->cm_index++; + + if ((res = RegOpenKeyExW(This->cm_key, buffer, 0, KEY_QUERY_VALUE, &hkey))) + break; + } + else + break; + pMoniker = DEVENUM_IMediaCatMoniker_Construct(); if (!pMoniker) return E_OUTOFMEMORY;
- if (RegOpenKeyW(This->index+fetched < This->subkey_cnt ? This->hkey : This->special_hkey, - buffer, &pMoniker->hkey) != ERROR_SUCCESS) - { - IMoniker_Release(&pMoniker->IMoniker_iface); - break; - } + pMoniker->hkey = hkey; + rgelt[fetched] = &pMoniker->IMoniker_iface; fetched++; }
- This->index += fetched; - TRACE("-- fetched %d\n", fetched);
if (pceltFetched) @@ -811,21 +815,26 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, static HRESULT WINAPI DEVENUM_IEnumMoniker_Skip(IEnumMoniker *iface, ULONG celt) { EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); - DWORD special_subkeys = 0;
TRACE("(%p)->(%d)\n", iface, celt);
- /* Before incrementing, check if there are any more values to run through. - Some programs use the Skip() function to get the number of devices */ - if(This->special_hkey) - RegQueryInfoKeyW(This->special_hkey, NULL, NULL, NULL, &special_subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - - if((This->index + celt) >= This->subkey_cnt + special_subkeys) + while (celt--) { - return S_FALSE; - } + /* FIXME: try PNP devices and DMOs first */
- This->index += celt; + /* try DirectShow filters */ + if (RegEnumKeyW(This->sw_key, This->sw_index, NULL, 0) != ERROR_NO_MORE_ITEMS) + { + This->sw_index++; + } + /* then try codecs */ + else if (RegEnumKeyW(This->cm_key, This->cm_index, NULL, 0) != ERROR_NO_MORE_ITEMS) + { + This->cm_index++; + } + else + return S_FALSE; + }
return S_OK; } @@ -836,7 +845,8 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Reset(IEnumMoniker *iface)
TRACE("(%p)->()\n", iface);
- This->index = 0; + This->sw_index = 0; + This->cm_index = 0;
return S_OK; } @@ -862,23 +872,31 @@ static const IEnumMonikerVtbl IEnumMoniker_Vtbl = DEVENUM_IEnumMoniker_Clone };
-HRESULT DEVENUM_IEnumMoniker_Construct(HKEY hkey, HKEY special_hkey, IEnumMoniker ** ppEnumMoniker) +HRESULT create_EnumMoniker(REFCLSID class, IEnumMoniker **ppEnumMoniker) { EnumMonikerImpl * pEnumMoniker = CoTaskMemAlloc(sizeof(EnumMonikerImpl)); + WCHAR buffer[78]; + if (!pEnumMoniker) return E_OUTOFMEMORY;
pEnumMoniker->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl; pEnumMoniker->ref = 1; - pEnumMoniker->index = 0; - pEnumMoniker->hkey = hkey; - pEnumMoniker->special_hkey = special_hkey; + pEnumMoniker->sw_index = 0; + pEnumMoniker->cm_index = 0;
- *ppEnumMoniker = &pEnumMoniker->IEnumMoniker_iface; + strcpyW(buffer, clsidW); + StringFromGUID2(class, buffer + strlenW(buffer), CHARS_IN_GUID); + strcatW(buffer, instanceW); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &pEnumMoniker->sw_key)) + pEnumMoniker->sw_key = NULL;
- if(RegQueryInfoKeyW(pEnumMoniker->hkey, NULL, NULL, NULL, &pEnumMoniker->subkey_cnt, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) - pEnumMoniker->subkey_cnt = 0; + strcpyW(buffer, wszActiveMovieKey); + StringFromGUID2(class, buffer + strlenW(buffer), CHARS_IN_GUID); + if (RegOpenKeyExW(HKEY_CURRENT_USER, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &pEnumMoniker->cm_key)) + pEnumMoniker->cm_key = NULL;
+ *ppEnumMoniker = &pEnumMoniker->IEnumMoniker_iface;
DEVENUM_LockModule();
diff --git a/dlls/devenum/parsedisplayname.c b/dlls/devenum/parsedisplayname.c index 77ea1ec..b5a3951 100644 --- a/dlls/devenum/parsedisplayname.c +++ b/dlls/devenum/parsedisplayname.c @@ -82,10 +82,12 @@ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayNa LPOLESTR pszClass = NULL; MediaCatMoniker * pMoniker = NULL; CLSID clsidDevice; - HRESULT res = S_OK; + HRESULT hr = S_OK; WCHAR wszRegKeyName[MAX_PATH]; + enum device_type type; HKEY hbasekey; int classlen; + LONG res; static const WCHAR wszRegSeparator[] = {'\', 0 };
TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(pszDisplayName), pchEaten, ppmkOut); @@ -94,6 +96,25 @@ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayNa if (pchEaten) *pchEaten = strlenW(pszDisplayName);
+ pszDisplayName = strchrW(pszDisplayName, ':') + 1; + if (pszDisplayName[0] == 's' && pszDisplayName[1] == 'w' && pszDisplayName[2] == ':') + { + type = DEVICE_FILTER; + if ((res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsidW, 0, 0, &hbasekey))) + return HRESULT_FROM_WIN32(res); + } + else if (pszDisplayName[0] == 'c' && pszDisplayName[1] == 'm' && pszDisplayName[2] == ':') + { + type = DEVICE_CODEC; + if ((res = RegOpenKeyExW(HKEY_CURRENT_USER, wszActiveMovieKey, 0, 0, &hbasekey))) + return HRESULT_FROM_WIN32(res); + } + else + { + FIXME("unhandled device type %s\n", debugstr_w(pszDisplayName+1)); + return MK_E_SYNTAX; + } + pszDisplayName = strchrW(pszDisplayName, '{'); pszBetween = strchrW(pszDisplayName, '}') + 2;
@@ -110,35 +131,32 @@ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayNa
TRACE("Device CLSID: %s\n", debugstr_w(pszClass));
- res = CLSIDFromString(pszClass, &clsidDevice); + hr = CLSIDFromString(pszClass, &clsidDevice);
- if (SUCCEEDED(res)) - { - res = DEVENUM_GetCategoryKey(&clsidDevice, &hbasekey, wszRegKeyName, MAX_PATH); - } - - if (SUCCEEDED(res)) + if (SUCCEEDED(hr)) { pMoniker = DEVENUM_IMediaCatMoniker_Construct(); if (pMoniker) { + strcpyW(wszRegKeyName, pszClass); + if (type == DEVICE_FILTER) + strcatW(wszRegKeyName, instanceW); strcatW(wszRegKeyName, wszRegSeparator); strcatW(wszRegKeyName, pszBetween); - if (RegCreateKeyW(hbasekey, wszRegKeyName, &pMoniker->hkey) == ERROR_SUCCESS) *ppmkOut = &pMoniker->IMoniker_iface; else { IMoniker_Release(&pMoniker->IMoniker_iface); - res = MK_E_NOOBJECT; + hr = MK_E_NOOBJECT; } } }
CoTaskMemFree(pszClass);
- TRACE("-- returning: %x\n", res); - return res; + TRACE("-- returning: %x\n", hr); + return hr; }
/********************************************************************** diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index 79189f3..c53f909 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -274,16 +274,155 @@ static void test_register_filter(void) ok(find_moniker(&CLSID_AudioRendererCategory, mon), "filter should be registered\n");
hr = IFilterMapper2_UnregisterFilter(mapper2, &CLSID_AudioRendererCategory, NULL, &CLSID_TestFilter); -todo_wine ok(hr == S_OK, "UnregisterFilter failed: %#x\n", hr);
-todo_wine ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "filter should not be registered\n"); IMoniker_Release(mon);
IFilterMapper2_Release(mapper2); }
+static IMoniker *check_display_name_(int line, IParseDisplayName *parser, WCHAR *buffer) +{ + IMoniker *mon; + ULONG eaten; + HRESULT hr; + WCHAR *str; + + hr = IParseDisplayName_ParseDisplayName(parser, NULL, buffer, &eaten, &mon); + ok_(__FILE__, line)(hr == S_OK, "ParseDisplayName failed: %#x\n", hr); + + hr = IMoniker_GetDisplayName(mon, NULL, NULL, &str); +todo_wine { + ok_(__FILE__, line)(hr == S_OK, "GetDisplayName failed: %#x\n", hr); + ok_(__FILE__, line)(!lstrcmpW(str, buffer), "got %s\n", wine_dbgstr_w(str)); +} + + CoTaskMemFree(str); + + return mon; +} +#define check_display_name(parser, buffer) check_display_name_(__LINE__, parser, buffer) + +static void test_directshow_filter(void) +{ + static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':','s','w',':',0}; + static const WCHAR instanceW[] = {'\','I','n','s','t','a','n','c','e',0}; + static const WCHAR clsidW[] = {'C','L','S','I','D','\',0}; + static WCHAR testW[] = {'\','t','e','s','t',0}; + IParseDisplayName *parser; + IPropertyBag *prop_bag; + IMoniker *mon; + WCHAR buffer[200]; + LRESULT res; + VARIANT var; + HRESULT hr; + + /* Test ParseDisplayName and GetDisplayName */ + 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); + StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID); + lstrcatW(buffer, testW); + mon = check_display_name(parser, buffer); + + /* Test writing and reading from the property bag */ + ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "filter should not be registered\n"); + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + ok(hr == S_OK, "BindToStorage failed: %#x\n", hr); + + VariantInit(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got %#x\n", hr); + + /* writing causes the key to be created */ + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(testW); + hr = IPropertyBag_Write(prop_bag, friendly_name, &var); + if (hr != E_ACCESSDENIED) + { + ok(hr == S_OK, "Write failed: %#x\n", hr); + + ok(find_moniker(&CLSID_AudioRendererCategory, mon), "filter should be registered\n"); + + VariantClear(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == S_OK, "Read failed: %#x\n", hr); + ok(!lstrcmpW(V_BSTR(&var), testW), "got %s\n", wine_dbgstr_w(V_BSTR(&var))); + + IMoniker_Release(mon); + + /* devenum doesn't give us a way to unregister—we have to do that manually */ + lstrcpyW(buffer, clsidW); + StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID); + lstrcatW(buffer, instanceW); + lstrcatW(buffer, testW); + res = RegDeleteKeyW(HKEY_CLASSES_ROOT, buffer); + ok(!res, "RegDeleteKey failed: %lu\n", res); + } + + VariantClear(&var); + IPropertyBag_Release(prop_bag); + IParseDisplayName_Release(parser); +} + +static void test_codec(void) +{ + static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':','c','m',':',0}; + static WCHAR testW[] = {'\','t','e','s','t',0}; + IParseDisplayName *parser; + IPropertyBag *prop_bag; + IMoniker *mon; + WCHAR buffer[200]; + VARIANT var; + HRESULT hr; + + /* Test ParseDisplayName and GetDisplayName */ + 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); + StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID); + lstrcatW(buffer, testW); + mon = check_display_name(parser, buffer); + + /* Test writing and reading from the property bag */ + ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "codec should not be registered\n"); + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + ok(hr == S_OK, "BindToStorage failed: %#x\n", hr); + + VariantInit(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got %#x\n", hr); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(testW); + hr = IPropertyBag_Write(prop_bag, friendly_name, &var); + ok(hr == S_OK, "Write failed: %#x\n", hr); + + VariantClear(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == S_OK, "Read failed: %#x\n", hr); + ok(!lstrcmpW(V_BSTR(&var), testW), "got %s\n", wine_dbgstr_w(V_BSTR(&var))); + + /* unlike DirectShow filters, these are automatically generated, so + * enumerating them will destroy the key */ +todo_wine + ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "codec should not be registered\n"); + + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); +todo_wine + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got %#x\n", hr); + + IPropertyBag_Release(prop_bag); + IMoniker_Release(mon); + + IParseDisplayName_Release(parser); +} + START_TEST(devenum) { IBindCtx *bind_ctx = NULL; @@ -303,6 +442,8 @@ START_TEST(devenum)
test_moniker_isequal(); test_register_filter(); + test_directshow_filter(); + test_codec();
CoUninitialize(); }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/devenum/devenum_private.h | 5 +++ dlls/devenum/mediacatenum.c | 3 ++ dlls/devenum/parsedisplayname.c | 96 +++++++++++++++++++---------------------- dlls/devenum/tests/devenum.c | 37 ++++++++++++++++ 4 files changed, 90 insertions(+), 51 deletions(-)
diff --git a/dlls/devenum/devenum_private.h b/dlls/devenum/devenum_private.h index bcc5085..9a0b5ad 100644 --- a/dlls/devenum/devenum_private.h +++ b/dlls/devenum/devenum_private.h @@ -71,6 +71,10 @@ typedef struct IMoniker IMoniker_iface; LONG ref; HKEY hkey; + CLSID class; + BOOL has_class; + enum device_type type; + WCHAR *name; } MediaCatMoniker;
MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void) DECLSPEC_HIDDEN; @@ -84,6 +88,7 @@ extern IParseDisplayName DEVENUM_ParseDisplayName DECLSPEC_HIDDEN; * Global string constant declarations */
+static const WCHAR backslashW[] = {'\',0}; static const WCHAR clsidW[] = {'C','L','S','I','D','\',0}; static const WCHAR instanceW[] = {'\','I','n','s','t','a','n','c','e',0}; static const WCHAR wszActiveMovieKey[] = {'S','o','f','t','w','a','r','e','\', diff --git a/dlls/devenum/mediacatenum.c b/dlls/devenum/mediacatenum.c index 583ca7d..0f38a0e 100644 --- a/dlls/devenum/mediacatenum.c +++ b/dlls/devenum/mediacatenum.c @@ -345,6 +345,7 @@ static ULONG WINAPI DEVENUM_IMediaCatMoniker_Release(IMoniker *iface)
if (ref == 0) { RegCloseKey(This->hkey); + CoTaskMemFree(This->name); CoTaskMemFree(This); DEVENUM_UnlockModule(); } @@ -695,6 +696,8 @@ MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void) pMoniker->IMoniker_iface.lpVtbl = &IMoniker_Vtbl; pMoniker->ref = 0; pMoniker->hkey = NULL; + pMoniker->has_class = FALSE; + pMoniker->name = NULL;
DEVENUM_IMediaCatMoniker_AddRef(&pMoniker->IMoniker_iface);
diff --git a/dlls/devenum/parsedisplayname.c b/dlls/devenum/parsedisplayname.c index b5a3951..2875a8c 100644 --- a/dlls/devenum/parsedisplayname.c +++ b/dlls/devenum/parsedisplayname.c @@ -76,87 +76,81 @@ static ULONG WINAPI DEVENUM_IParseDisplayName_Release(IParseDisplayName *iface) * not in "@device:sw:{CLSID1}<filter name or CLSID>" format */ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayName *iface, - IBindCtx *pbc, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut) + IBindCtx *pbc, LPOLESTR name, ULONG *eaten, IMoniker **ret) { - LPOLESTR pszBetween = NULL; - LPOLESTR pszClass = NULL; - MediaCatMoniker * pMoniker = NULL; - CLSID clsidDevice; - HRESULT hr = S_OK; - WCHAR wszRegKeyName[MAX_PATH]; + WCHAR buffer[MAX_PATH]; enum device_type type; + MediaCatMoniker *mon; HKEY hbasekey; - int classlen; - LONG res; - static const WCHAR wszRegSeparator[] = {'\', 0 }; + CLSID class; + LRESULT res;
- TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(pszDisplayName), pchEaten, ppmkOut); + TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(name), eaten, ret);
- *ppmkOut = NULL; - if (pchEaten) - *pchEaten = strlenW(pszDisplayName); + *ret = NULL; + if (eaten) + *eaten = strlenW(name);
- pszDisplayName = strchrW(pszDisplayName, ':') + 1; - if (pszDisplayName[0] == 's' && pszDisplayName[1] == 'w' && pszDisplayName[2] == ':') + name = strchrW(name, ':') + 1; + + if (name[0] == 's' && name[1] == 'w' && name[2] == ':') { type = DEVICE_FILTER; if ((res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsidW, 0, 0, &hbasekey))) return HRESULT_FROM_WIN32(res); + name += 3; } - else if (pszDisplayName[0] == 'c' && pszDisplayName[1] == 'm' && pszDisplayName[2] == ':') + else if (name[0] == 'c' && name[1] == 'm' && name[2] == ':') { type = DEVICE_CODEC; if ((res = RegOpenKeyExW(HKEY_CURRENT_USER, wszActiveMovieKey, 0, 0, &hbasekey))) return HRESULT_FROM_WIN32(res); + name += 3; } else { - FIXME("unhandled device type %s\n", debugstr_w(pszDisplayName+1)); + FIXME("unhandled device type %s\n", debugstr_w(name)); return MK_E_SYNTAX; }
- pszDisplayName = strchrW(pszDisplayName, '{'); - pszBetween = strchrW(pszDisplayName, '}') + 2; - - /* size = pszBetween - pszDisplayName - 1 (for '\' after CLSID) - * + 1 (for NULL character) - */ - classlen = (int)(pszBetween - pszDisplayName - 1); - pszClass = CoTaskMemAlloc((classlen + 1) * sizeof(WCHAR)); - if (!pszClass) + if (!(mon = DEVENUM_IMediaCatMoniker_Construct())) return E_OUTOFMEMORY;
- memcpy(pszClass, pszDisplayName, classlen * sizeof(WCHAR)); - pszClass[classlen] = 0; + lstrcpynW(buffer, name, CHARS_IN_GUID); + if (CLSIDFromString(buffer, &class) == S_OK) + { + mon->has_class = TRUE; + mon->class = class; + name += CHARS_IN_GUID; + }
- TRACE("Device CLSID: %s\n", debugstr_w(pszClass)); + mon->type = type;
- hr = CLSIDFromString(pszClass, &clsidDevice); + if (!(mon->name = CoTaskMemAlloc((strlenW(name) + 1) * sizeof(WCHAR)))) + { + IMoniker_Release(&mon->IMoniker_iface); + return E_OUTOFMEMORY; + } + strcpyW(mon->name, name);
- if (SUCCEEDED(hr)) + buffer[0] = 0; + if (mon->has_class) { - pMoniker = DEVENUM_IMediaCatMoniker_Construct(); - if (pMoniker) - { - strcpyW(wszRegKeyName, pszClass); - if (type == DEVICE_FILTER) - strcatW(wszRegKeyName, instanceW); - strcatW(wszRegKeyName, wszRegSeparator); - strcatW(wszRegKeyName, pszBetween); - if (RegCreateKeyW(hbasekey, wszRegKeyName, &pMoniker->hkey) == ERROR_SUCCESS) - *ppmkOut = &pMoniker->IMoniker_iface; - else - { - IMoniker_Release(&pMoniker->IMoniker_iface); - hr = MK_E_NOOBJECT; - } - } + StringFromGUID2(&mon->class, buffer, CHARS_IN_GUID); + if (mon->type == DEVICE_FILTER) + strcatW(buffer, instanceW); + strcatW(buffer, backslashW); } + strcatW(buffer, mon->name);
- CoTaskMemFree(pszClass); + if (RegCreateKeyW(hbasekey, buffer, &mon->hkey)) + { + IMoniker_Release(&mon->IMoniker_iface); + return MK_E_NOOBJECT; + } + *ret = &mon->IMoniker_iface;
- TRACE("-- returning: %x\n", hr); - return hr; + return S_OK; }
/********************************************************************** diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index c53f909..fe8cb2e 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -365,6 +365,43 @@ static void test_directshow_filter(void)
VariantClear(&var); IPropertyBag_Release(prop_bag); + + /* name can be anything */ + + lstrcpyW(buffer, deviceW); + lstrcatW(buffer, testW+1); + mon = check_display_name(parser, buffer); + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + ok(hr == S_OK, "BindToStorage failed: %#x\n", hr); + + VariantClear(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got %#x\n", hr); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(testW); + hr = IPropertyBag_Write(prop_bag, friendly_name, &var); + if (hr != E_ACCESSDENIED) + { + ok(hr == S_OK, "Write failed: %#x\n", hr); + + VariantClear(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == S_OK, "Read failed: %#x\n", hr); + ok(!lstrcmpW(V_BSTR(&var), testW), "got %s\n", wine_dbgstr_w(V_BSTR(&var))); + + IMoniker_Release(mon); + + /* vista+ stores it inside the Instance key */ + RegDeleteKeyA(HKEY_CLASSES_ROOT, "CLSID\test\Instance"); + + res = RegDeleteKeyA(HKEY_CLASSES_ROOT, "CLSID\test"); + ok(!res, "RegDeleteKey failed: %lu\n", res); + } + + VariantClear(&var); + IPropertyBag_Release(prop_bag); IParseDisplayName_Release(parser); }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/devenum/devenum_private.h | 1 + dlls/devenum/mediacatenum.c | 51 ++++++++++++++++++++++++++++++++---------- dlls/devenum/tests/devenum.c | 4 ++-- 3 files changed, 42 insertions(+), 14 deletions(-)
diff --git a/dlls/devenum/devenum_private.h b/dlls/devenum/devenum_private.h index 9a0b5ad..83d0ce3 100644 --- a/dlls/devenum/devenum_private.h +++ b/dlls/devenum/devenum_private.h @@ -95,6 +95,7 @@ static 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 const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':',0};
extern const WCHAR clsid_keyname[6] DECLSPEC_HIDDEN;
diff --git a/dlls/devenum/mediacatenum.c b/dlls/devenum/mediacatenum.c index 0f38a0e..0d4e01e 100644 --- a/dlls/devenum/mediacatenum.c +++ b/dlls/devenum/mediacatenum.c @@ -33,6 +33,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(devenum); typedef struct { IEnumMoniker IEnumMoniker_iface; + CLSID class; LONG ref; HKEY sw_key; DWORD sw_index; @@ -621,24 +622,35 @@ 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 wszBuffer[MAX_PATH]; - static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; - DWORD received = sizeof(wszBuffer); + WCHAR *buffer;
TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, ppszDisplayName);
*ppszDisplayName = NULL;
- /* FIXME: should this be the weird stuff we have to parse in IParseDisplayName? */ - if (RegQueryValueExW(This->hkey, wszFriendlyName, NULL, NULL, (LPBYTE)wszBuffer, &received) == ERROR_SUCCESS) + 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) { - *ppszDisplayName = CoTaskMemAlloc(received); - strcpyW(*ppszDisplayName, wszBuffer); - return S_OK; + StringFromGUID2(&This->class, buffer + strlenW(buffer), CHARS_IN_GUID); + strcatW(buffer, backslashW); } + strcatW(buffer, This->name);
- return E_FAIL; + *ppszDisplayName = buffer; + return S_OK; }
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, @@ -782,6 +794,11 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, This->sw_index++; if ((res = RegOpenKeyExW(This->sw_key, buffer, 0, KEY_QUERY_VALUE, &hkey))) break; + + if (!(pMoniker = DEVENUM_IMediaCatMoniker_Construct())) + return E_OUTOFMEMORY; + + pMoniker->type = DEVICE_FILTER; } /* then try codecs */ else if (!(res = RegEnumKeyW(This->cm_key, This->cm_index, buffer, sizeof(buffer)/sizeof(WCHAR)))) @@ -790,14 +807,23 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt,
if ((res = RegOpenKeyExW(This->cm_key, buffer, 0, KEY_QUERY_VALUE, &hkey))) break; + + if (!(pMoniker = DEVENUM_IMediaCatMoniker_Construct())) + return E_OUTOFMEMORY; + + pMoniker->type = DEVICE_CODEC; } else break;
- pMoniker = DEVENUM_IMediaCatMoniker_Construct(); - if (!pMoniker) + 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; pMoniker->hkey = hkey;
rgelt[fetched] = &pMoniker->IMoniker_iface; @@ -887,6 +913,7 @@ HRESULT create_EnumMoniker(REFCLSID class, IEnumMoniker **ppEnumMoniker) pEnumMoniker->ref = 1; pEnumMoniker->sw_index = 0; pEnumMoniker->cm_index = 0; + pEnumMoniker->class = *class;
strcpyW(buffer, clsidW); StringFromGUID2(class, buffer + strlenW(buffer), CHARS_IN_GUID); diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index fe8cb2e..0437b6b 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -293,10 +293,8 @@ static IMoniker *check_display_name_(int line, IParseDisplayName *parser, WCHAR ok_(__FILE__, line)(hr == S_OK, "ParseDisplayName failed: %#x\n", hr);
hr = IMoniker_GetDisplayName(mon, NULL, NULL, &str); -todo_wine { ok_(__FILE__, line)(hr == S_OK, "GetDisplayName failed: %#x\n", hr); ok_(__FILE__, line)(!lstrcmpW(str, buffer), "got %s\n", wine_dbgstr_w(str)); -}
CoTaskMemFree(str);
@@ -328,6 +326,7 @@ static void test_directshow_filter(void) mon = check_display_name(parser, buffer);
/* Test writing and reading from the property bag */ +todo_wine ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "filter should not be registered\n");
hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); @@ -426,6 +425,7 @@ static void test_codec(void) mon = check_display_name(parser, buffer);
/* Test writing and reading from the property bag */ +todo_wine ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "codec should not be registered\n");
hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/devenum/devenum_private.h | 1 - dlls/devenum/mediacatenum.c | 65 ++++++++++++++++++++++++++++++----------- dlls/devenum/parsedisplayname.c | 21 ------------- dlls/devenum/tests/devenum.c | 2 -- 4 files changed, 48 insertions(+), 41 deletions(-)
diff --git a/dlls/devenum/devenum_private.h b/dlls/devenum/devenum_private.h index 83d0ce3..a483062 100644 --- a/dlls/devenum/devenum_private.h +++ b/dlls/devenum/devenum_private.h @@ -70,7 +70,6 @@ typedef struct { IMoniker IMoniker_iface; LONG ref; - HKEY hkey; CLSID class; BOOL has_class; enum device_type type; diff --git a/dlls/devenum/mediacatenum.c b/dlls/devenum/mediacatenum.c index 0d4e01e..b0cdc6c 100644 --- a/dlls/devenum/mediacatenum.c +++ b/dlls/devenum/mediacatenum.c @@ -45,7 +45,8 @@ typedef struct { IPropertyBag IPropertyBag_iface; LONG ref; - HKEY hkey; + enum device_type type; + WCHAR path[MAX_PATH]; } RegPropBagImpl;
@@ -101,7 +102,6 @@ static ULONG WINAPI DEVENUM_IPropertyBag_Release(LPPROPERTYBAG iface)
ref = InterlockedDecrement(&This->ref); if (ref == 0) { - RegCloseKey(This->hkey); CoTaskMemFree(This); DEVENUM_UnlockModule(); } @@ -119,22 +119,32 @@ static HRESULT WINAPI DEVENUM_IPropertyBag_Read( DWORD type = 0; RegPropBagImpl *This = impl_from_IPropertyBag(iface); HRESULT res = S_OK; - LONG reswin32; + LONG reswin32 = ERROR_SUCCESS; + HKEY hkey;
TRACE("(%p)->(%s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog);
if (!pszPropName || !pVar) return E_POINTER;
- reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, NULL, NULL, &received); + if (This->type == DEVICE_FILTER) + reswin32 = RegOpenKeyW(HKEY_CLASSES_ROOT, This->path, &hkey); + else if (This->type == DEVICE_CODEC) + reswin32 = RegOpenKeyW(HKEY_CURRENT_USER, This->path, &hkey); res = HRESULT_FROM_WIN32(reswin32);
if (SUCCEEDED(res)) { + reswin32 = RegQueryValueExW(hkey, pszPropName, NULL, NULL, NULL, &received); + res = HRESULT_FROM_WIN32(reswin32); + } + + if (SUCCEEDED(res)) + { pData = HeapAlloc(GetProcessHeap(), 0, received);
/* work around a GCC bug that occurs here unless we use the reswin32 variable as well */ - reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, &type, pData, &received); + reswin32 = RegQueryValueExW(hkey, pszPropName, NULL, &type, pData, &received); res = HRESULT_FROM_WIN32(reswin32); }
@@ -215,6 +225,8 @@ static HRESULT WINAPI DEVENUM_IPropertyBag_Read(
HeapFree(GetProcessHeap(), 0, pData);
+ RegCloseKey(hkey); + TRACE("<- %x\n", res); return res; } @@ -229,6 +241,8 @@ static HRESULT WINAPI DEVENUM_IPropertyBag_Write( DWORD cbData = 0; DWORD dwType = 0; HRESULT res = S_OK; + LONG lres = ERROR_SUCCESS; + HKEY hkey;
TRACE("(%p)->(%s, %p)\n", This, debugstr_w(pszPropName), pVar);
@@ -265,10 +279,18 @@ static HRESULT WINAPI DEVENUM_IPropertyBag_Write( return E_FAIL; }
- if (RegSetValueExW(This->hkey, - pszPropName, 0, - dwType, lpData, cbData) != ERROR_SUCCESS) - res = E_FAIL; + if (This->type == DEVICE_FILTER) + lres = RegCreateKeyW(HKEY_CLASSES_ROOT, This->path, &hkey); + else if (This->type == DEVICE_CODEC) + lres = RegCreateKeyW(HKEY_CURRENT_USER, This->path, &hkey); + res = HRESULT_FROM_WIN32(lres); + + if (SUCCEEDED(res)) + { + lres = RegSetValueExW(hkey, pszPropName, 0, dwType, lpData, cbData); + res = HRESULT_FROM_WIN32(lres); + RegCloseKey(hkey); + }
if (V_VT(pVar) & VT_ARRAY) res = SafeArrayUnaccessData(V_ARRAY(pVar)); @@ -285,14 +307,28 @@ static const IPropertyBagVtbl IPropertyBag_Vtbl = DEVENUM_IPropertyBag_Write };
-static HRESULT DEVENUM_IPropertyBag_Construct(HANDLE hkey, IPropertyBag **ppBag) +static HRESULT create_PropertyBag(MediaCatMoniker *mon, IPropertyBag **ppBag) { RegPropBagImpl * rpb = CoTaskMemAlloc(sizeof(RegPropBagImpl)); if (!rpb) return E_OUTOFMEMORY; rpb->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl; rpb->ref = 1; - rpb->hkey = hkey; + 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) + { + StringFromGUID2(&mon->class, rpb->path + strlenW(rpb->path), CHARS_IN_GUID); + if (rpb->type == DEVICE_FILTER) + strcatW(rpb->path, instanceW); + strcatW(rpb->path, backslashW); + } + strcatW(rpb->path, mon->name); + *ppBag = &rpb->IPropertyBag_iface; DEVENUM_LockModule(); return S_OK; @@ -345,7 +381,6 @@ static ULONG WINAPI DEVENUM_IMediaCatMoniker_Release(IMoniker *iface) TRACE("(%p) ref=%d\n", This, ref);
if (ref == 0) { - RegCloseKey(This->hkey); CoTaskMemFree(This->name); CoTaskMemFree(This); DEVENUM_UnlockModule(); @@ -487,9 +522,7 @@ static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToStorage(IMoniker *iface, IB
if (IsEqualGUID(riid, &IID_IPropertyBag)) { - HANDLE hkey; - DuplicateHandle(GetCurrentProcess(), This->hkey, GetCurrentProcess(), &hkey, 0, 0, DUPLICATE_SAME_ACCESS); - return DEVENUM_IPropertyBag_Construct(hkey, (IPropertyBag**)ppvObj); + return create_PropertyBag(This, (IPropertyBag**)ppvObj); }
return MK_E_NOSTORAGE; @@ -707,7 +740,6 @@ MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void)
pMoniker->IMoniker_iface.lpVtbl = &IMoniker_Vtbl; pMoniker->ref = 0; - pMoniker->hkey = NULL; pMoniker->has_class = FALSE; pMoniker->name = NULL;
@@ -824,7 +856,6 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, strcpyW(pMoniker->name, buffer); pMoniker->has_class = TRUE; pMoniker->class = This->class; - pMoniker->hkey = hkey;
rgelt[fetched] = &pMoniker->IMoniker_iface; fetched++; diff --git a/dlls/devenum/parsedisplayname.c b/dlls/devenum/parsedisplayname.c index 2875a8c..0f3ef3b 100644 --- a/dlls/devenum/parsedisplayname.c +++ b/dlls/devenum/parsedisplayname.c @@ -81,9 +81,7 @@ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayNa WCHAR buffer[MAX_PATH]; enum device_type type; MediaCatMoniker *mon; - HKEY hbasekey; CLSID class; - LRESULT res;
TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(name), eaten, ret);
@@ -96,15 +94,11 @@ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayNa if (name[0] == 's' && name[1] == 'w' && name[2] == ':') { type = DEVICE_FILTER; - if ((res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsidW, 0, 0, &hbasekey))) - return HRESULT_FROM_WIN32(res); name += 3; } else if (name[0] == 'c' && name[1] == 'm' && name[2] == ':') { type = DEVICE_CODEC; - if ((res = RegOpenKeyExW(HKEY_CURRENT_USER, wszActiveMovieKey, 0, 0, &hbasekey))) - return HRESULT_FROM_WIN32(res); name += 3; } else @@ -133,21 +127,6 @@ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayNa } strcpyW(mon->name, name);
- buffer[0] = 0; - if (mon->has_class) - { - StringFromGUID2(&mon->class, buffer, CHARS_IN_GUID); - if (mon->type == DEVICE_FILTER) - strcatW(buffer, instanceW); - strcatW(buffer, backslashW); - } - strcatW(buffer, mon->name); - - if (RegCreateKeyW(hbasekey, buffer, &mon->hkey)) - { - IMoniker_Release(&mon->IMoniker_iface); - return MK_E_NOOBJECT; - } *ret = &mon->IMoniker_iface;
return S_OK; diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index 0437b6b..7e3270f 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -326,7 +326,6 @@ static void test_directshow_filter(void) mon = check_display_name(parser, buffer);
/* Test writing and reading from the property bag */ -todo_wine ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "filter should not be registered\n");
hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); @@ -425,7 +424,6 @@ static void test_codec(void) mon = check_display_name(parser, buffer);
/* Test writing and reading from the property bag */ -todo_wine ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "codec should not be registered\n");
hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);