mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 15:20:47 +00:00
devenum: More correctly handle device types.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
a736400eed
commit
f5c531bdd1
|
@ -38,13 +38,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(devenum);
|
||||||
|
|
||||||
extern HINSTANCE DEVENUM_hInstance;
|
extern HINSTANCE DEVENUM_hInstance;
|
||||||
|
|
||||||
const WCHAR wszInstanceKeyName[] ={'\\','I','n','s','t','a','n','c','e',0};
|
|
||||||
|
|
||||||
static const WCHAR wszRegSeparator[] = {'\\', 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 wszFilterKeyName[] = {'F','i','l','t','e','r',0};
|
||||||
static const WCHAR wszMeritName[] = {'M','e','r','i','t',0};
|
static const WCHAR wszMeritName[] = {'M','e','r','i','t',0};
|
||||||
static const WCHAR wszPins[] = {'P','i','n','s',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 const WCHAR wszWaveOutID[] = {'W','a','v','e','O','u','t','I','D',0};
|
||||||
|
|
||||||
static ULONG WINAPI DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum * iface);
|
static ULONG WINAPI DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum * iface);
|
||||||
static HRESULT DEVENUM_CreateSpecialCategories(void);
|
static HRESULT register_codecs(void);
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* DEVENUM_ICreateDevEnum_QueryInterface (also IUnknown)
|
* DEVENUM_ICreateDevEnum_QueryInterface (also IUnknown)
|
||||||
|
@ -108,63 +102,6 @@ static ULONG WINAPI DEVENUM_ICreateDevEnum_Release(ICreateDevEnum * iface)
|
||||||
return 1; /* non-heap based object */
|
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)
|
static HKEY open_special_category_key(const CLSID *clsid, BOOL create)
|
||||||
{
|
{
|
||||||
WCHAR key_name[sizeof(wszActiveMovieKey)/sizeof(WCHAR) + CHARS_IN_GUID-1];
|
WCHAR key_name[sizeof(wszActiveMovieKey)/sizeof(WCHAR) + CHARS_IN_GUID-1];
|
||||||
|
@ -400,14 +337,13 @@ static HRESULT DEVENUM_RegisterLegacyAmFilters(void)
|
||||||
{
|
{
|
||||||
WCHAR wszFilterSubkeyName[64];
|
WCHAR wszFilterSubkeyName[64];
|
||||||
DWORD cName = sizeof(wszFilterSubkeyName) / sizeof(WCHAR);
|
DWORD cName = sizeof(wszFilterSubkeyName) / sizeof(WCHAR);
|
||||||
HKEY hkeyCategoryBaseKey;
|
|
||||||
WCHAR wszRegKey[MAX_PATH];
|
WCHAR wszRegKey[MAX_PATH];
|
||||||
HKEY hkeyInstance = NULL;
|
HKEY hkeyInstance = NULL;
|
||||||
|
|
||||||
if (RegEnumKeyExW(hkeyFilter, i, wszFilterSubkeyName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
|
if (RegEnumKeyExW(hkeyFilter, i, wszFilterSubkeyName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
|
||||||
|
|
||||||
hr = DEVENUM_GetCategoryKey(&CLSID_LegacyAmFilterCategory, &hkeyCategoryBaseKey, wszRegKey, MAX_PATH);
|
strcpyW(wszRegKey, wszActiveMovieKey);
|
||||||
if (FAILED(hr)) continue;
|
StringFromGUID2(&CLSID_LegacyAmFilterCategory, wszRegKey + strlenW(wszRegKey), CHARS_IN_GUID);
|
||||||
|
|
||||||
strcatW(wszRegKey, wszRegSeparator);
|
strcatW(wszRegKey, wszRegSeparator);
|
||||||
strcatW(wszRegKey, wszFilterSubkeyName);
|
strcatW(wszRegKey, wszFilterSubkeyName);
|
||||||
|
@ -512,9 +448,6 @@ static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator(
|
||||||
IEnumMoniker **ppEnumMoniker,
|
IEnumMoniker **ppEnumMoniker,
|
||||||
DWORD dwFlags)
|
DWORD dwFlags)
|
||||||
{
|
{
|
||||||
HKEY hkey, special_hkey = NULL;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
TRACE("(%p)->(%s, %p, %x)\n", iface, debugstr_guid(clsidDeviceClass), ppEnumMoniker, dwFlags);
|
TRACE("(%p)->(%s, %p, %x)\n", iface, debugstr_guid(clsidDeviceClass), ppEnumMoniker, dwFlags);
|
||||||
|
|
||||||
if (!ppEnumMoniker)
|
if (!ppEnumMoniker)
|
||||||
|
@ -522,34 +455,10 @@ static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator(
|
||||||
|
|
||||||
*ppEnumMoniker = NULL;
|
*ppEnumMoniker = NULL;
|
||||||
|
|
||||||
if (IsEqualGUID(clsidDeviceClass, &CLSID_LegacyAmFilterCategory))
|
register_codecs();
|
||||||
{
|
DEVENUM_RegisterLegacyAmFilters();
|
||||||
DEVENUM_RegisterLegacyAmFilters();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsSpecialCategory(clsidDeviceClass))
|
return create_EnumMoniker(clsidDeviceClass, ppEnumMoniker);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
@ -644,22 +553,17 @@ static const WCHAR DEVENUM_populate_handle_nameW[] =
|
||||||
'D','e','v','e','n','u','m','_',
|
'D','e','v','e','n','u','m','_',
|
||||||
'P','o','p','u','l','a','t','e',0};
|
'P','o','p','u','l','a','t','e',0};
|
||||||
|
|
||||||
/**********************************************************************
|
static HRESULT register_codecs(void)
|
||||||
* DEVENUM_CreateSpecialCategories (INTERNAL)
|
|
||||||
*
|
|
||||||
* Creates the keys in the registry for the dynamic categories
|
|
||||||
*/
|
|
||||||
static HRESULT DEVENUM_CreateSpecialCategories(void)
|
|
||||||
{
|
{
|
||||||
HRESULT res;
|
HRESULT res;
|
||||||
WCHAR szDSoundNameFormat[MAX_PATH + 1];
|
WCHAR szDSoundNameFormat[MAX_PATH + 1];
|
||||||
WCHAR szDSoundName[MAX_PATH + 1];
|
WCHAR szDSoundName[MAX_PATH + 1];
|
||||||
|
WCHAR class[CHARS_IN_GUID];
|
||||||
DWORD iDefaultDevice = -1;
|
DWORD iDefaultDevice = -1;
|
||||||
UINT numDevs;
|
UINT numDevs;
|
||||||
IFilterMapper2 * pMapper = NULL;
|
IFilterMapper2 * pMapper = NULL;
|
||||||
REGFILTER2 rf2;
|
REGFILTER2 rf2;
|
||||||
REGFILTERPINS2 rfp2;
|
REGFILTERPINS2 rfp2;
|
||||||
WCHAR path[MAX_PATH];
|
|
||||||
HKEY basekey;
|
HKEY basekey;
|
||||||
|
|
||||||
if (DEVENUM_populate_handle)
|
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
|
/* 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
|
* or switched from pulseaudio to alsa, delete all old devices first
|
||||||
*/
|
*/
|
||||||
if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_AudioRendererCategory, &basekey, path, MAX_PATH)))
|
RegOpenKeyW(HKEY_CURRENT_USER, wszActiveMovieKey, &basekey);
|
||||||
RegDeleteTreeW(basekey, path);
|
StringFromGUID2(&CLSID_AudioRendererCategory, class, CHARS_IN_GUID);
|
||||||
if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_AudioInputDeviceCategory, &basekey, path, MAX_PATH)))
|
RegDeleteTreeW(basekey, class);
|
||||||
RegDeleteTreeW(basekey, path);
|
StringFromGUID2(&CLSID_AudioInputDeviceCategory, class, CHARS_IN_GUID);
|
||||||
if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_VideoInputDeviceCategory, &basekey, path, MAX_PATH)))
|
RegDeleteTreeW(basekey, class);
|
||||||
RegDeleteTreeW(basekey, path);
|
StringFromGUID2(&CLSID_VideoInputDeviceCategory, class, CHARS_IN_GUID);
|
||||||
if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_MidiRendererCategory, &basekey, path, MAX_PATH)))
|
RegDeleteTreeW(basekey, class);
|
||||||
RegDeleteTreeW(basekey, path);
|
StringFromGUID2(&CLSID_MidiRendererCategory, class, CHARS_IN_GUID);
|
||||||
if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_VideoCompressorCategory, &basekey, path, MAX_PATH)))
|
RegDeleteTreeW(basekey, class);
|
||||||
RegDeleteTreeW(basekey, path);
|
StringFromGUID2(&CLSID_VideoCompressorCategory, class, CHARS_IN_GUID);
|
||||||
|
RegDeleteTreeW(basekey, class);
|
||||||
|
RegCloseKey(basekey);
|
||||||
|
|
||||||
rf2.dwVersion = 2;
|
rf2.dwVersion = 2;
|
||||||
rf2.dwMerit = MERIT_PREFERRED;
|
rf2.dwMerit = MERIT_PREFERRED;
|
||||||
|
|
|
@ -60,6 +60,12 @@ typedef struct
|
||||||
IClassFactory IClassFactory_iface;
|
IClassFactory IClassFactory_iface;
|
||||||
} ClassFactoryImpl;
|
} ClassFactoryImpl;
|
||||||
|
|
||||||
|
enum device_type
|
||||||
|
{
|
||||||
|
DEVICE_FILTER,
|
||||||
|
DEVICE_CODEC,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
IMoniker IMoniker_iface;
|
IMoniker IMoniker_iface;
|
||||||
|
@ -68,23 +74,24 @@ typedef struct
|
||||||
} MediaCatMoniker;
|
} MediaCatMoniker;
|
||||||
|
|
||||||
MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void) DECLSPEC_HIDDEN;
|
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 ClassFactoryImpl DEVENUM_ClassFactory DECLSPEC_HIDDEN;
|
||||||
extern ICreateDevEnum DEVENUM_CreateDevEnum DECLSPEC_HIDDEN;
|
extern ICreateDevEnum DEVENUM_CreateDevEnum DECLSPEC_HIDDEN;
|
||||||
extern IParseDisplayName DEVENUM_ParseDisplayName 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
|
* 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 clsid_keyname[6] DECLSPEC_HIDDEN;
|
||||||
extern const WCHAR wszInstanceKeyName[] DECLSPEC_HIDDEN;
|
|
||||||
#define CLSID_STR_LEN (sizeof(clsid_keyname) / sizeof(WCHAR))
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* Resource IDs
|
* Resource IDs
|
||||||
|
|
|
@ -34,10 +34,10 @@ typedef struct
|
||||||
{
|
{
|
||||||
IEnumMoniker IEnumMoniker_iface;
|
IEnumMoniker IEnumMoniker_iface;
|
||||||
LONG ref;
|
LONG ref;
|
||||||
DWORD index;
|
HKEY sw_key;
|
||||||
DWORD subkey_cnt;
|
DWORD sw_index;
|
||||||
HKEY hkey;
|
HKEY cm_key;
|
||||||
HKEY special_hkey;
|
DWORD cm_index;
|
||||||
} EnumMonikerImpl;
|
} EnumMonikerImpl;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -748,9 +748,8 @@ static ULONG WINAPI DEVENUM_IEnumMoniker_Release(IEnumMoniker *iface)
|
||||||
|
|
||||||
if (!ref)
|
if (!ref)
|
||||||
{
|
{
|
||||||
if(This->special_hkey)
|
RegCloseKey(This->sw_key);
|
||||||
RegCloseKey(This->special_hkey);
|
RegCloseKey(This->cm_key);
|
||||||
RegCloseKey(This->hkey);
|
|
||||||
CoTaskMemFree(This);
|
CoTaskMemFree(This);
|
||||||
DEVENUM_UnlockModule();
|
DEVENUM_UnlockModule();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -766,37 +765,42 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt,
|
||||||
LONG res;
|
LONG res;
|
||||||
ULONG fetched = 0;
|
ULONG fetched = 0;
|
||||||
MediaCatMoniker * pMoniker;
|
MediaCatMoniker * pMoniker;
|
||||||
|
HKEY hkey;
|
||||||
|
|
||||||
TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched);
|
TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched);
|
||||||
|
|
||||||
while (fetched < celt)
|
while (fetched < celt)
|
||||||
{
|
{
|
||||||
if(This->index+fetched < This->subkey_cnt)
|
/* FIXME: try PNP devices and DMOs first */
|
||||||
res = RegEnumKeyW(This->hkey, This->index+fetched, buffer, sizeof(buffer) / sizeof(WCHAR));
|
|
||||||
else if(This->special_hkey)
|
/* try DirectShow filters */
|
||||||
res = RegEnumKeyW(This->special_hkey, This->index+fetched-This->subkey_cnt, buffer, sizeof(buffer) / sizeof(WCHAR));
|
if (!(res = RegEnumKeyW(This->sw_key, This->sw_index, buffer, sizeof(buffer)/sizeof(WCHAR))))
|
||||||
|
{
|
||||||
|
This->sw_index++;
|
||||||
|
if ((res = RegOpenKeyExW(This->sw_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
|
||||||
|
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
|
else
|
||||||
break;
|
break;
|
||||||
if (res != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pMoniker = DEVENUM_IMediaCatMoniker_Construct();
|
pMoniker = DEVENUM_IMediaCatMoniker_Construct();
|
||||||
if (!pMoniker)
|
if (!pMoniker)
|
||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
if (RegOpenKeyW(This->index+fetched < This->subkey_cnt ? This->hkey : This->special_hkey,
|
pMoniker->hkey = hkey;
|
||||||
buffer, &pMoniker->hkey) != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
IMoniker_Release(&pMoniker->IMoniker_iface);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rgelt[fetched] = &pMoniker->IMoniker_iface;
|
rgelt[fetched] = &pMoniker->IMoniker_iface;
|
||||||
fetched++;
|
fetched++;
|
||||||
}
|
}
|
||||||
|
|
||||||
This->index += fetched;
|
|
||||||
|
|
||||||
TRACE("-- fetched %d\n", fetched);
|
TRACE("-- fetched %d\n", fetched);
|
||||||
|
|
||||||
if (pceltFetched)
|
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)
|
static HRESULT WINAPI DEVENUM_IEnumMoniker_Skip(IEnumMoniker *iface, ULONG celt)
|
||||||
{
|
{
|
||||||
EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
|
EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
|
||||||
DWORD special_subkeys = 0;
|
|
||||||
|
|
||||||
TRACE("(%p)->(%d)\n", iface, celt);
|
TRACE("(%p)->(%d)\n", iface, celt);
|
||||||
|
|
||||||
/* Before incrementing, check if there are any more values to run through.
|
while (celt--)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
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;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -836,7 +845,8 @@ static HRESULT WINAPI DEVENUM_IEnumMoniker_Reset(IEnumMoniker *iface)
|
||||||
|
|
||||||
TRACE("(%p)->()\n", iface);
|
TRACE("(%p)->()\n", iface);
|
||||||
|
|
||||||
This->index = 0;
|
This->sw_index = 0;
|
||||||
|
This->cm_index = 0;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -862,24 +872,32 @@ static const IEnumMonikerVtbl IEnumMoniker_Vtbl =
|
||||||
DEVENUM_IEnumMoniker_Clone
|
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));
|
EnumMonikerImpl * pEnumMoniker = CoTaskMemAlloc(sizeof(EnumMonikerImpl));
|
||||||
|
WCHAR buffer[78];
|
||||||
|
|
||||||
if (!pEnumMoniker)
|
if (!pEnumMoniker)
|
||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
pEnumMoniker->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl;
|
pEnumMoniker->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl;
|
||||||
pEnumMoniker->ref = 1;
|
pEnumMoniker->ref = 1;
|
||||||
pEnumMoniker->index = 0;
|
pEnumMoniker->sw_index = 0;
|
||||||
pEnumMoniker->hkey = hkey;
|
pEnumMoniker->cm_index = 0;
|
||||||
pEnumMoniker->special_hkey = special_hkey;
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
*ppEnumMoniker = &pEnumMoniker->IEnumMoniker_iface;
|
||||||
|
|
||||||
if(RegQueryInfoKeyW(pEnumMoniker->hkey, NULL, NULL, NULL, &pEnumMoniker->subkey_cnt, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
|
||||||
pEnumMoniker->subkey_cnt = 0;
|
|
||||||
|
|
||||||
|
|
||||||
DEVENUM_LockModule();
|
DEVENUM_LockModule();
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
|
@ -82,10 +82,12 @@ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayNa
|
||||||
LPOLESTR pszClass = NULL;
|
LPOLESTR pszClass = NULL;
|
||||||
MediaCatMoniker * pMoniker = NULL;
|
MediaCatMoniker * pMoniker = NULL;
|
||||||
CLSID clsidDevice;
|
CLSID clsidDevice;
|
||||||
HRESULT res = S_OK;
|
HRESULT hr = S_OK;
|
||||||
WCHAR wszRegKeyName[MAX_PATH];
|
WCHAR wszRegKeyName[MAX_PATH];
|
||||||
|
enum device_type type;
|
||||||
HKEY hbasekey;
|
HKEY hbasekey;
|
||||||
int classlen;
|
int classlen;
|
||||||
|
LONG res;
|
||||||
static const WCHAR wszRegSeparator[] = {'\\', 0 };
|
static const WCHAR wszRegSeparator[] = {'\\', 0 };
|
||||||
|
|
||||||
TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
|
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)
|
if (pchEaten)
|
||||||
*pchEaten = strlenW(pszDisplayName);
|
*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, '{');
|
pszDisplayName = strchrW(pszDisplayName, '{');
|
||||||
pszBetween = strchrW(pszDisplayName, '}') + 2;
|
pszBetween = strchrW(pszDisplayName, '}') + 2;
|
||||||
|
|
||||||
|
@ -110,35 +131,32 @@ static HRESULT WINAPI DEVENUM_IParseDisplayName_ParseDisplayName(IParseDisplayNa
|
||||||
|
|
||||||
TRACE("Device CLSID: %s\n", debugstr_w(pszClass));
|
TRACE("Device CLSID: %s\n", debugstr_w(pszClass));
|
||||||
|
|
||||||
res = CLSIDFromString(pszClass, &clsidDevice);
|
hr = CLSIDFromString(pszClass, &clsidDevice);
|
||||||
|
|
||||||
if (SUCCEEDED(res))
|
if (SUCCEEDED(hr))
|
||||||
{
|
|
||||||
res = DEVENUM_GetCategoryKey(&clsidDevice, &hbasekey, wszRegKeyName, MAX_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(res))
|
|
||||||
{
|
{
|
||||||
pMoniker = DEVENUM_IMediaCatMoniker_Construct();
|
pMoniker = DEVENUM_IMediaCatMoniker_Construct();
|
||||||
if (pMoniker)
|
if (pMoniker)
|
||||||
{
|
{
|
||||||
|
strcpyW(wszRegKeyName, pszClass);
|
||||||
|
if (type == DEVICE_FILTER)
|
||||||
|
strcatW(wszRegKeyName, instanceW);
|
||||||
strcatW(wszRegKeyName, wszRegSeparator);
|
strcatW(wszRegKeyName, wszRegSeparator);
|
||||||
strcatW(wszRegKeyName, pszBetween);
|
strcatW(wszRegKeyName, pszBetween);
|
||||||
|
|
||||||
if (RegCreateKeyW(hbasekey, wszRegKeyName, &pMoniker->hkey) == ERROR_SUCCESS)
|
if (RegCreateKeyW(hbasekey, wszRegKeyName, &pMoniker->hkey) == ERROR_SUCCESS)
|
||||||
*ppmkOut = &pMoniker->IMoniker_iface;
|
*ppmkOut = &pMoniker->IMoniker_iface;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IMoniker_Release(&pMoniker->IMoniker_iface);
|
IMoniker_Release(&pMoniker->IMoniker_iface);
|
||||||
res = MK_E_NOOBJECT;
|
hr = MK_E_NOOBJECT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CoTaskMemFree(pszClass);
|
CoTaskMemFree(pszClass);
|
||||||
|
|
||||||
TRACE("-- returning: %x\n", res);
|
TRACE("-- returning: %x\n", hr);
|
||||||
return res;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|
|
@ -274,16 +274,155 @@ static void test_register_filter(void)
|
||||||
ok(find_moniker(&CLSID_AudioRendererCategory, mon), "filter should be registered\n");
|
ok(find_moniker(&CLSID_AudioRendererCategory, mon), "filter should be registered\n");
|
||||||
|
|
||||||
hr = IFilterMapper2_UnregisterFilter(mapper2, &CLSID_AudioRendererCategory, NULL, &CLSID_TestFilter);
|
hr = IFilterMapper2_UnregisterFilter(mapper2, &CLSID_AudioRendererCategory, NULL, &CLSID_TestFilter);
|
||||||
todo_wine
|
|
||||||
ok(hr == S_OK, "UnregisterFilter failed: %#x\n", hr);
|
ok(hr == S_OK, "UnregisterFilter failed: %#x\n", hr);
|
||||||
|
|
||||||
todo_wine
|
|
||||||
ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "filter should not be registered\n");
|
ok(!find_moniker(&CLSID_AudioRendererCategory, mon), "filter should not be registered\n");
|
||||||
IMoniker_Release(mon);
|
IMoniker_Release(mon);
|
||||||
|
|
||||||
IFilterMapper2_Release(mapper2);
|
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)
|
START_TEST(devenum)
|
||||||
{
|
{
|
||||||
IBindCtx *bind_ctx = NULL;
|
IBindCtx *bind_ctx = NULL;
|
||||||
|
@ -303,6 +442,8 @@ START_TEST(devenum)
|
||||||
|
|
||||||
test_moniker_isequal();
|
test_moniker_isequal();
|
||||||
test_register_filter();
|
test_register_filter();
|
||||||
|
test_directshow_filter();
|
||||||
|
test_codec();
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue