https://git.reactos.org/?p=reactos.git;a=commitdiff;h=5e3341f4bb252ed7127a7439bf6a90e73f0f6295
commit 5e3341f4bb252ed7127a7439bf6a90e73f0f6295 Author: Amine Khaldi <amine.kha...@reactos.org> AuthorDate: Sun May 27 03:56:13 2018 +0100 Commit: Amine Khaldi <amine.kha...@reactos.org> CommitDate: Sun May 27 03:56:13 2018 +0100 [DEVENUM] Sync with Wine Staging 3.9. CORE-14656 --- dll/directx/wine/devenum/CMakeLists.txt | 4 +- dll/directx/wine/devenum/createdevenum.c | 1169 ++++++++++++++------------- dll/directx/wine/devenum/devenum.rc | 12 - dll/directx/wine/devenum/devenum_private.h | 40 +- dll/directx/wine/devenum/fil_data.idl | 47 ++ dll/directx/wine/devenum/mediacatenum.c | 214 +++-- dll/directx/wine/devenum/parsedisplayname.c | 93 +-- media/doc/README.WINE | 2 +- 8 files changed, 859 insertions(+), 722 deletions(-) diff --git a/dll/directx/wine/devenum/CMakeLists.txt b/dll/directx/wine/devenum/CMakeLists.txt index d8af794b86..1f5e7eb321 100644 --- a/dll/directx/wine/devenum/CMakeLists.txt +++ b/dll/directx/wine/devenum/CMakeLists.txt @@ -4,6 +4,7 @@ add_definitions(-D_WIN32_WINNT=0x600 -DWINVER=0x600) add_definitions(-D__WINESRC__) include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine) +add_idl_headers(devenum_fil_data_header fil_data.idl) spec2def(devenum.dll devenum.spec) list(APPEND SOURCE @@ -23,6 +24,7 @@ set_source_files_properties(devenum.rc PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT set_module_type(devenum win32dll UNICODE) target_link_libraries(devenum strmiids uuid wine) add_delay_importlibs(devenum msvfw32) -add_importlibs(devenum advapi32 advapi32_vista ole32 oleaut32 winmm user32 avicap32 msacm32 msvcrt kernel32 ntdll) +add_importlibs(devenum advapi32 advapi32_vista ole32 oleaut32 winmm user32 avicap32 msacm32 dsound msvcrt kernel32 ntdll) +add_dependencies(devenum devenum_fil_data_header) add_pch(devenum precomp.h SOURCE) add_cd_file(TARGET devenum DESTINATION reactos/system32 FOR all) diff --git a/dll/directx/wine/devenum/createdevenum.c b/dll/directx/wine/devenum/createdevenum.c index 002ffbc876..fbde0cb61d 100644 --- a/dll/directx/wine/devenum/createdevenum.c +++ b/dll/directx/wine/devenum/createdevenum.c @@ -29,22 +29,20 @@ #include "devenum_private.h" #include "vfw.h" #include "aviriff.h" +#include "dsound.h" #include "wine/debug.h" #include "wine/unicode.h" +#include "wine/heap.h" #include "mmddk.h" +#include "initguid.h" +#include "fil_data.h" + 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}; @@ -54,11 +52,11 @@ static const WCHAR wszDirection[] = {'D','i','r','e','c','t','i','o','n',0}; static const WCHAR wszIsRendered[] = {'I','s','R','e','n','d','e','r','e','d',0}; static const WCHAR wszTypes[] = {'T','y','p','e','s',0}; static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; -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 wszFilterData[] = {'F','i','l','t','e','r','D','a','t','a',0}; static ULONG WINAPI DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum * iface); -static HRESULT DEVENUM_CreateSpecialCategories(void); +static HRESULT register_codecs(void); +static HRESULT DEVENUM_CreateAMCategoryKey(const CLSID * clsidCategory); /********************************************************************** * DEVENUM_ICreateDevEnum_QueryInterface (also IUnknown) @@ -108,87 +106,37 @@ static ULONG WINAPI DEVENUM_ICreateDevEnum_Release(ICreateDevEnum * iface) return 1; /* non-heap based object */ } -static BOOL IsSpecialCategory(const CLSID *clsid) +static HRESULT register_codec(const CLSID *class, const WCHAR *name, IMoniker **ret) { - return IsEqualGUID(clsid, &CLSID_AudioRendererCategory) || - IsEqualGUID(clsid, &CLSID_AudioInputDeviceCategory) || - IsEqualGUID(clsid, &CLSID_VideoInputDeviceCategory) || - IsEqualGUID(clsid, &CLSID_VideoCompressorCategory) || - IsEqualGUID(clsid, &CLSID_AudioCompressorCategory) || - IsEqualGUID(clsid, &CLSID_MidiRendererCategory); -} + static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':','c','m',':',0}; + IParseDisplayName *parser; + WCHAR *buffer; + ULONG eaten; + HRESULT hr; -HRESULT DEVENUM_GetCategoryKey(REFCLSID clsidDeviceClass, HKEY *pBaseKey, WCHAR *wszRegKeyName, UINT maxLen) -{ - if (IsSpecialCategory(clsidDeviceClass)) - { - *pBaseKey = HKEY_CURRENT_USER; - strcpyW(wszRegKeyName, wszActiveMovieKey); + hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser); + if (FAILED(hr)) + return hr; - if (!StringFromGUID2(clsidDeviceClass, wszRegKeyName + strlenW(wszRegKeyName), maxLen - strlenW(wszRegKeyName))) - return E_OUTOFMEMORY; - } - else + buffer = heap_alloc((strlenW(deviceW) + CHARS_IN_GUID + strlenW(name) + 1) * sizeof(WCHAR)); + if (!buffer) { - *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; + IParseDisplayName_Release(parser); + return E_OUTOFMEMORY; } - return ret; -} - -static HKEY open_special_category_key(const CLSID *clsid, BOOL create) -{ - WCHAR key_name[sizeof(wszActiveMovieKey)/sizeof(WCHAR) + CHARS_IN_GUID-1]; - HKEY ret; - LONG res; - - strcpyW(key_name, wszActiveMovieKey); - if (!StringFromGUID2(clsid, key_name + sizeof(wszActiveMovieKey)/sizeof(WCHAR)-1, CHARS_IN_GUID)) - return NULL; + strcpyW(buffer, deviceW); + StringFromGUID2(class, buffer + strlenW(buffer), CHARS_IN_GUID); + strcatW(buffer, backslashW); + strcatW(buffer, name); - if(create) - res = RegCreateKeyW(HKEY_CURRENT_USER, key_name, &ret); - else - res = RegOpenKeyExW(HKEY_CURRENT_USER, key_name, 0, KEY_READ, &ret); - if (res != ERROR_SUCCESS) { - WARN("Could not open %s\n", debugstr_w(key_name)); - return NULL; - } - - return ret; + hr = IParseDisplayName_ParseDisplayName(parser, NULL, buffer, &eaten, ret); + IParseDisplayName_Release(parser); + heap_free(buffer); + return hr; } -static void DEVENUM_ReadPinTypes(HKEY hkeyPinKey, REGFILTERPINS *rgPin) +static void DEVENUM_ReadPinTypes(HKEY hkeyPinKey, REGFILTERPINS2 *rgPin) { HKEY hkeyTypes = NULL; DWORD dwMajorTypes, i; @@ -285,7 +233,11 @@ static void DEVENUM_ReadPins(HKEY hkeyFilterClass, REGFILTER2 *rgf2) { HKEY hkeyPins = NULL; DWORD dwPinsSubkeys, i; - REGFILTERPINS *rgPins = NULL; + REGFILTERPINS2 *rgPins = NULL; + + rgf2->dwVersion = 2; + rgf2->u.s2.cPins2 = 0; + rgf2->u.s2.rgPins2 = NULL; if (RegOpenKeyExW(hkeyFilterClass, wszPins, 0, KEY_READ, &hkeyPins) != ERROR_SUCCESS) return ; @@ -299,7 +251,7 @@ static void DEVENUM_ReadPins(HKEY hkeyFilterClass, REGFILTER2 *rgf2) if (dwPinsSubkeys) { - rgPins = CoTaskMemAlloc(sizeof(REGFILTERPINS) * dwPinsSubkeys); + rgPins = CoTaskMemAlloc(sizeof(REGFILTERPINS2) * dwPinsSubkeys); if (!rgPins) { RegCloseKey(hkeyPins); @@ -312,82 +264,137 @@ static void DEVENUM_ReadPins(HKEY hkeyFilterClass, REGFILTER2 *rgf2) HKEY hkeyPinKey = NULL; WCHAR wszPinName[MAX_PATH]; DWORD cName = sizeof(wszPinName) / sizeof(WCHAR); - DWORD Type, cbData; - REGFILTERPINS *rgPin = &rgPins[rgf2->u.s1.cPins]; + REGFILTERPINS2 *rgPin = &rgPins[rgf2->u.s2.cPins2]; + DWORD value, size, Type; LONG lRet; - rgPin->strName = NULL; - rgPin->clsConnectsToFilter = &GUID_NULL; - rgPin->strConnectsToPin = NULL; - rgPin->nMediaTypes = 0; - rgPin->lpMediaType = NULL; + memset(rgPin, 0, sizeof(*rgPin)); if (RegEnumKeyExW(hkeyPins, i, wszPinName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue; if (RegOpenKeyExW(hkeyPins, wszPinName, 0, KEY_READ, &hkeyPinKey) != ERROR_SUCCESS) continue; - rgPin->strName = CoTaskMemAlloc((strlenW(wszPinName) + 1) * sizeof(WCHAR)); - if (!rgPin->strName) goto error_cleanup; - - strcpyW(rgPin->strName, wszPinName); - - cbData = sizeof(rgPin->bMany); - lRet = RegQueryValueExW(hkeyPinKey, wszAllowedMany, NULL, &Type, (LPBYTE)&rgPin->bMany, &cbData); + size = sizeof(DWORD); + lRet = RegQueryValueExW(hkeyPinKey, wszAllowedMany, NULL, &Type, (BYTE *)&value, &size); if (lRet != ERROR_SUCCESS || Type != REG_DWORD) goto error_cleanup; + if (value) + rgPin->dwFlags |= REG_PINFLAG_B_MANY; - cbData = sizeof(rgPin->bZero); - lRet = RegQueryValueExW(hkeyPinKey, wszAllowedZero, NULL, &Type, (LPBYTE)&rgPin->bZero, &cbData); + size = sizeof(DWORD); + lRet = RegQueryValueExW(hkeyPinKey, wszAllowedZero, NULL, &Type, (BYTE *)&value, &size); if (lRet != ERROR_SUCCESS || Type != REG_DWORD) goto error_cleanup; + if (value) + rgPin->dwFlags |= REG_PINFLAG_B_ZERO; - cbData = sizeof(rgPin->bOutput); - lRet = RegQueryValueExW(hkeyPinKey, wszDirection, NULL, &Type, (LPBYTE)&rgPin->bOutput, &cbData); + size = sizeof(DWORD); + lRet = RegQueryValueExW(hkeyPinKey, wszDirection, NULL, &Type, (BYTE *)&value, &size); if (lRet != ERROR_SUCCESS || Type != REG_DWORD) goto error_cleanup; + if (value) + rgPin->dwFlags |= REG_PINFLAG_B_OUTPUT; + - cbData = sizeof(rgPin->bRendered); - lRet = RegQueryValueExW(hkeyPinKey, wszIsRendered, NULL, &Type, (LPBYTE)&rgPin->bRendered, &cbData); + size = sizeof(DWORD); + lRet = RegQueryValueExW(hkeyPinKey, wszIsRendered, NULL, &Type, (BYTE *)&value, &size); if (lRet != ERROR_SUCCESS || Type != REG_DWORD) goto error_cleanup; + if (value) + rgPin->dwFlags |= REG_PINFLAG_B_RENDERER; DEVENUM_ReadPinTypes(hkeyPinKey, rgPin); - ++rgf2->u.s1.cPins; + ++rgf2->u.s2.cPins2; continue; error_cleanup: RegCloseKey(hkeyPinKey); - CoTaskMemFree(rgPin->strName); } RegCloseKey(hkeyPins); - if (rgPins && !rgf2->u.s1.cPins) + if (rgPins && !rgf2->u.s2.cPins2) { CoTaskMemFree(rgPins); rgPins = NULL; } - rgf2->u.s1.rgPins = rgPins; + rgf2->u.s2.rgPins2 = rgPins; +} + +static void free_regfilter2(REGFILTER2 *rgf) +{ + if (rgf->u.s2.rgPins2) + { + UINT iPin; + + for (iPin = 0; iPin < rgf->u.s2.cPins2; iPin++) + { + if (rgf->u.s2.rgPins2[iPin].lpMediaType) + { + UINT iType; + + for (iType = 0; iType < rgf->u.s2.rgPins2[iPin].nMediaTypes; iType++) + { + CoTaskMemFree((void *)rgf->u.s2.rgPins2[iPin].lpMediaType[iType].clsMajorType); + CoTaskMemFree((void *)rgf->u.s2.rgPins2[iPin].lpMediaType[iType].clsMinorType); + } + + CoTaskMemFree((void *)rgf->u.s2.rgPins2[iPin].lpMediaType); + } + } + + CoTaskMemFree((void *)rgf->u.s2.rgPins2); + } +} + +static void write_filter_data(IPropertyBag *prop_bag, REGFILTER2 *rgf) +{ + IAMFilterData *fildata; + SAFEARRAYBOUND sabound; + BYTE *data, *array; + VARIANT var; + ULONG size; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IAMFilterData, (void **)&fildata); + if (FAILED(hr)) goto cleanup; + + hr = IAMFilterData_CreateFilterData(fildata, rgf, &data, &size); + if (FAILED(hr)) goto cleanup; + + V_VT(&var) = VT_ARRAY | VT_UI1; + sabound.lLbound = 0; + sabound.cElements = size; + if (!(V_ARRAY(&var) = SafeArrayCreate(VT_UI1, 1, &sabound))) + goto cleanup; + hr = SafeArrayAccessData(V_ARRAY(&var), (void *)&array); + if (FAILED(hr)) goto cleanup; + + memcpy(array, data, size); + hr = SafeArrayUnaccessData(V_ARRAY(&var)); + if (FAILED(hr)) goto cleanup; + + hr = IPropertyBag_Write(prop_bag, wszFilterData, &var); + if (FAILED(hr)) goto cleanup; + +cleanup: + VariantClear(&var); + CoTaskMemFree(data); + IAMFilterData_Release(fildata); } -static HRESULT DEVENUM_RegisterLegacyAmFilters(void) +static void register_legacy_filters(void) { HKEY hkeyFilter = NULL; DWORD dwFilterSubkeys, i; LONG lRet; - IFilterMapper2 *pMapper = NULL; HRESULT hr; - hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, - &IID_IFilterMapper2, (void **) &pMapper); - if (SUCCEEDED(hr)) - { - lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszFilterKeyName, 0, KEY_READ, &hkeyFilter); - hr = HRESULT_FROM_WIN32(lRet); - } + lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszFilterKeyName, 0, KEY_READ, &hkeyFilter); + hr = HRESULT_FROM_WIN32(lRet); if (SUCCEEDED(hr)) { @@ -395,113 +402,487 @@ static HRESULT DEVENUM_RegisterLegacyAmFilters(void) hr = HRESULT_FROM_WIN32(lRet); } + if (SUCCEEDED(hr)) + hr = DEVENUM_CreateAMCategoryKey(&CLSID_LegacyAmFilterCategory); + if (SUCCEEDED(hr)) { for (i = 0; i < dwFilterSubkeys; i++) { WCHAR wszFilterSubkeyName[64]; DWORD cName = sizeof(wszFilterSubkeyName) / sizeof(WCHAR); - HKEY hkeyCategoryBaseKey; + IPropertyBag *prop_bag = NULL; WCHAR wszRegKey[MAX_PATH]; - HKEY hkeyInstance = NULL; + HKEY classkey = NULL; + IMoniker *mon = NULL; + VARIANT var; + REGFILTER2 rgf2; + DWORD Type, len; 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; + TRACE("Registering %s\n", debugstr_w(wszFilterSubkeyName)); - strcatW(wszRegKey, wszRegSeparator); + strcpyW(wszRegKey, clsidW); strcatW(wszRegKey, wszFilterSubkeyName); - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszRegKey, 0, KEY_READ, &hkeyInstance) == ERROR_SUCCESS) + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszRegKey, 0, KEY_READ, &classkey) != ERROR_SUCCESS) + continue; + + hr = register_codec(&CLSID_LegacyAmFilterCategory, wszFilterSubkeyName, &mon); + if (FAILED(hr)) goto cleanup; + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + if (FAILED(hr)) goto cleanup; + + /* write friendly name */ + len = 0; + V_VT(&var) = VT_BSTR; + if (!RegQueryValueExW(classkey, NULL, NULL, &Type, NULL, &len)) { - RegCloseKey(hkeyInstance); + WCHAR *friendlyname = heap_alloc(len); + if (!friendlyname) + goto cleanup; + RegQueryValueExW(classkey, NULL, NULL, &Type, (BYTE *)friendlyname, &len); + V_BSTR(&var) = SysAllocStringLen(friendlyname, len/sizeof(WCHAR)); + heap_free(friendlyname); } else - { - /* Filter is registered the IFilterMapper(1)-way in HKCR\Filter. Needs to be added to - * legacy am filter category. */ - HKEY hkeyFilterClass = NULL; - REGFILTER2 rgf2; - CLSID clsidFilter; - WCHAR wszFilterName[MAX_PATH]; - DWORD Type; - DWORD cbData; - HRESULT res; - IMoniker *pMoniker = NULL; - - TRACE("Registering %s\n", debugstr_w(wszFilterSubkeyName)); - - strcpyW(wszRegKey, clsid_keyname); - strcatW(wszRegKey, wszRegSeparator); - strcatW(wszRegKey, wszFilterSubkeyName); - - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszRegKey, 0, KEY_READ, &hkeyFilterClass) != ERROR_SUCCESS) - continue; - - rgf2.dwVersion = 1; - rgf2.dwMerit = 0; - rgf2.u.s1.cPins = 0; - rgf2.u.s1.rgPins = NULL; - - cbData = sizeof(wszFilterName); - if (RegQueryValueExW(hkeyFilterClass, NULL, NULL, &Type, (LPBYTE)wszFilterName, &cbData) != ERROR_SUCCESS || - Type != REG_SZ) - goto cleanup; + V_BSTR(&var) = SysAllocString(wszFilterSubkeyName); + + if (!V_BSTR(&var)) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, wszFriendlyName, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write clsid */ + V_VT(&var) = VT_BSTR; + if (!(V_BSTR(&var) = SysAllocString(wszFilterSubkeyName))) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write filter data */ + rgf2.dwMerit = MERIT_NORMAL; + + len = sizeof(rgf2.dwMerit); + RegQueryValueExW(classkey, wszMeritName, NULL, &Type, (BYTE *)&rgf2.dwMerit, &len); + + DEVENUM_ReadPins(classkey, &rgf2); + + write_filter_data(prop_bag, &rgf2); + +cleanup: + if (prop_bag) IPropertyBag_Release(prop_bag); + if (mon) IMoniker_Release(mon); + RegCloseKey(classkey); + VariantClear(&var); + free_regfilter2(&rgf2); + } + } - cbData = sizeof(rgf2.dwMerit); - if (RegQueryValueExW(hkeyFilterClass, wszMeritName, NULL, &Type, (LPBYTE)&rgf2.dwMerit, &cbData) != ERROR_SUCCESS || - Type != REG_DWORD) - goto cleanup; + if (hkeyFilter) RegCloseKey(hkeyFilter); +} - DEVENUM_ReadPins(hkeyFilterClass, &rgf2); +static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, const WCHAR *module, void *context) +{ + static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',' ','D','i','r','e','c','t','S','o','u','n','d',' ','D','e','v','i','c','e',0}; + static const WCHAR directsoundW[] = {'D','i','r','e','c','t','S','o','u','n','d',':',' ',0}; + static const WCHAR dsguidW[] = {'D','S','G','u','i','d',0}; + IPropertyBag *prop_bag = NULL; + REGFILTERPINS2 rgpins = {0}; + REGPINTYPES rgtypes = {0}; + REGFILTER2 rgf = {0}; + WCHAR clsid[CHARS_IN_GUID]; + IMoniker *mon = NULL; + VARIANT var; + HRESULT hr; - res = CLSIDFromString(wszFilterSubkeyName, &clsidFilter); - if (FAILED(res)) goto cleanup; + hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory); + if (FAILED(hr)) goto cleanup; - IFilterMapper2_RegisterFilter(pMapper, &clsidFilter, wszFilterName, &pMoniker, NULL, NULL, &rgf2); + V_VT(&var) = VT_BSTR; + if (guid) + { + WCHAR *name = heap_alloc(sizeof(defaultW) + strlenW(desc) * sizeof(WCHAR)); + if (!name) + goto cleanup; + strcpyW(name, directsoundW); + strcatW(name, desc); + + V_BSTR(&var) = SysAllocString(name); + heap_free(name); + } + else + V_BSTR(&var) = SysAllocString(defaultW); + + if (!V_BSTR(&var)) + goto cleanup; + + hr = register_codec(&CLSID_AudioRendererCategory, V_BSTR(&var), &mon); + if (FAILED(hr)) goto cleanup; + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + if (FAILED(hr)) goto cleanup; + + /* write friendly name */ + hr = IPropertyBag_Write(prop_bag, wszFriendlyName, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write clsid */ + V_VT(&var) = VT_BSTR; + StringFromGUID2(&CLSID_DSoundRender, clsid, CHARS_IN_GUID); + if (!(V_BSTR(&var) = SysAllocString(clsid))) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write filter data */ + rgf.dwVersion = 2; + rgf.dwMerit = guid ? MERIT_DO_NOT_USE : MERIT_PREFERRED; + rgf.u.s2.cPins2 = 1; + rgf.u.s2.rgPins2 = &rgpins; + rgpins.dwFlags = REG_PINFLAG_B_RENDERER; + /* FIXME: native registers many more formats */ + rgpins.nMediaTypes = 1; + rgpins.lpMediaType = &rgtypes; + rgtypes.clsMajorType = &MEDIATYPE_Audio; + rgtypes.clsMinorType = &MEDIASUBTYPE_PCM; + + write_filter_data(prop_bag, &rgf); + + /* write DSound guid */ + V_VT(&var) = VT_BSTR; + StringFromGUID2(guid ? guid : &GUID_NULL, clsid, CHARS_IN_GUID); + if (!(V_BSTR(&var) = SysAllocString(clsid))) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, dsguidW, &var); + if (FAILED(hr)) goto cleanup; + +cleanup: + VariantClear(&var); + if (prop_bag) IPropertyBag_Release(prop_bag); + if (mon) IMoniker_Release(mon); - if (pMoniker) - IMoniker_Release(pMoniker); + return TRUE; +} - cleanup: +static void register_waveout_devices(void) +{ + static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',' ','W','a','v','e','O','u','t',' ','D','e','v','i','c','e',0}; + static const WCHAR waveoutidW[] = {'W','a','v','e','O','u','t','I','d',0}; + IPropertyBag *prop_bag = NULL; + REGFILTERPINS2 rgpins = {0}; + REGPINTYPES rgtypes = {0}; + REGFILTER2 rgf = {0}; + WCHAR clsid[CHARS_IN_GUID]; + IMoniker *mon = NULL; + WAVEOUTCAPSW caps; + int i, count; + VARIANT var; + HRESULT hr; - if (hkeyFilterClass) RegCloseKey(hkeyFilterClass); + hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory); + if (FAILED(hr)) return; - if (rgf2.u.s1.rgPins) - { - UINT iPin; + count = waveOutGetNumDevs(); - for (iPin = 0; iPin < rgf2.u.s1.cPins; iPin++) - { - CoTaskMemFree(rgf2.u.s1.rgPins[iPin].strName); + for (i = -1; i < count; i++) + { + waveOutGetDevCapsW(i, &caps, sizeof(caps)); + + V_VT(&var) = VT_BSTR; + + if (i == -1) /* WAVE_MAPPER */ + V_BSTR(&var) = SysAllocString(defaultW); + else + V_BSTR(&var) = SysAllocString(caps.szPname); + if (!(V_BSTR(&var))) + goto cleanup; + + hr = register_codec(&CLSID_AudioRendererCategory, V_BSTR(&var), &mon); + if (FAILED(hr)) goto cleanup; + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + if (FAILED(hr)) goto cleanup; + + /* write friendly name */ + hr = IPropertyBag_Write(prop_bag, wszFriendlyName, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write clsid */ + V_VT(&var) = VT_BSTR; + StringFromGUID2(&CLSID_AudioRender, clsid, CHARS_IN_GUID); + if (!(V_BSTR(&var) = SysAllocString(clsid))) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write filter data */ + rgf.dwVersion = 2; + rgf.dwMerit = MERIT_DO_NOT_USE; + rgf.u.s2.cPins2 = 1; + rgf.u.s2.rgPins2 = &rgpins; + rgpins.dwFlags = REG_PINFLAG_B_RENDERER; + rgpins.nMediaTypes = 1; + rgpins.lpMediaType = &rgtypes; + rgtypes.clsMajorType = &MEDIATYPE_Audio; + rgtypes.clsMinorType = &MEDIASUBTYPE_NULL; + + write_filter_data(prop_bag, &rgf); + + /* write WaveOutId */ + V_VT(&var) = VT_I4; + V_I4(&var) = i; + hr = IPropertyBag_Write(prop_bag, waveoutidW, &var); + if (FAILED(hr)) goto cleanup; + +cleanup: + VariantClear(&var); + if (prop_bag) IPropertyBag_Release(prop_bag); + if (mon) IMoniker_Release(mon); + } +} - if (rgf2.u.s1.rgPins[iPin].lpMediaType) - { - UINT iType; +static void register_wavein_devices(void) +{ + static const WCHAR waveinidW[] = {'W','a','v','e','I','n','I','d',0}; + IPropertyBag *prop_bag = NULL; + REGFILTER2 rgf = {0}; + WCHAR clsid[CHARS_IN_GUID]; + IMoniker *mon = NULL; + WAVEINCAPSW caps; + int i, count; + VARIANT var; + HRESULT hr; - for (iType = 0; iType < rgf2.u.s1.rgPins[iPin].nMediaTypes; iType++) - { - CoTaskMemFree((void*)rgf2.u.s1.rgPins[iPin].lpMediaType[iType].clsMajorType); - CoTaskMemFree((void*)rgf2.u.s1.rgPins[iPin].lpMediaType[iType].clsMinorType); - } + hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory); + if (FAILED(hr)) return; - CoTaskMemFree((void*)rgf2.u.s1.rgPins[iPin].lpMediaType); - } - } + count = waveInGetNumDevs(); - CoTaskMemFree((void*)rgf2.u.s1.rgPins); - } - } - } + for (i = 0; i < count; i++) + { + waveInGetDevCapsW(i, &caps, sizeof(caps)); + + V_VT(&var) = VT_BSTR; + + V_BSTR(&var) = SysAllocString(caps.szPname); + if (!(V_BSTR(&var))) + goto cleanup; + + hr = register_codec(&CLSID_AudioInputDeviceCategory, V_BSTR(&var), &mon); + if (FAILED(hr)) goto cleanup; + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + if (FAILED(hr)) goto cleanup; + + /* write friendly name */ + hr = IPropertyBag_Write(prop_bag, wszFriendlyName, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write clsid */ + V_VT(&var) = VT_BSTR; + StringFromGUID2(&CLSID_AudioRecord, clsid, CHARS_IN_GUID); + if (!(V_BSTR(&var) = SysAllocString(clsid))) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write filter data */ + rgf.dwVersion = 2; + rgf.dwMerit = MERIT_DO_NOT_USE; + + write_filter_data(prop_bag, &rgf); + + /* write WaveInId */ + V_VT(&var) = VT_I4; + V_I4(&var) = i; + hr = IPropertyBag_Write(prop_bag, waveinidW, &var); + if (FAILED(hr)) goto cleanup; + +cleanup: + VariantClear(&var); + if (prop_bag) IPropertyBag_Release(prop_bag); + if (mon) IMoniker_Release(mon); } +} - if (hkeyFilter) RegCloseKey(hkeyFilter); +static void register_midiout_devices(void) +{ + static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',' ','M','i','d','i','O','u','t',' ','D','e','v','i','c','e',0}; + static const WCHAR midioutidW[] = {'M','i','d','i','O','u','t','I','d',0}; + IPropertyBag *prop_bag = NULL; + REGFILTERPINS2 rgpins = {0}; + REGPINTYPES rgtypes = {0}; + REGFILTER2 rgf = {0}; + WCHAR clsid[CHARS_IN_GUID]; + IMoniker *mon = NULL; + MIDIOUTCAPSW caps; + int i, count; + VARIANT var; + HRESULT hr; - if (pMapper) - IFilterMapper2_Release(pMapper); + hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory); + if (FAILED(hr)) return; + + count = midiOutGetNumDevs(); - return S_OK; + for (i = -1; i < count; i++) + { + midiOutGetDevCapsW(i, &caps, sizeof(caps)); + + V_VT(&var) = VT_BSTR; + + if (i == -1) /* MIDI_MAPPER */ + V_BSTR(&var) = SysAllocString(defaultW); + else + V_BSTR(&var) = SysAllocString(caps.szPname); + if (!(V_BSTR(&var))) + goto cleanup; + + hr = register_codec(&CLSID_MidiRendererCategory, V_BSTR(&var), &mon); + if (FAILED(hr)) goto cleanup; + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + if (FAILED(hr)) goto cleanup; + + /* write friendly name */ + hr = IPropertyBag_Write(prop_bag, wszFriendlyName, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write clsid */ + V_VT(&var) = VT_BSTR; + StringFromGUID2(&CLSID_AVIMIDIRender, clsid, CHARS_IN_GUID); + if (!(V_BSTR(&var) = SysAllocString(clsid))) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write filter data */ + rgf.dwVersion = 2; + rgf.dwMerit = (i == -1) ? MERIT_PREFERRED : MERIT_DO_NOT_USE; + rgf.u.s2.cPins2 = 1; + rgf.u.s2.rgPins2 = &rgpins; + rgpins.dwFlags = REG_PINFLAG_B_RENDERER; + rgpins.nMediaTypes = 1; + rgpins.lpMediaType = &rgtypes; + rgtypes.clsMajorType = &MEDIATYPE_Midi; + rgtypes.clsMinorType = &MEDIASUBTYPE_NULL; + + write_filter_data(prop_bag, &rgf); + + /* write MidiOutId */ + V_VT(&var) = VT_I4; + V_I4(&var) = i; + hr = IPropertyBag_Write(prop_bag, midioutidW, &var); + if (FAILED(hr)) goto cleanup; + +cleanup: + VariantClear(&var); + if (prop_bag) IPropertyBag_Release(prop_bag); + if (mon) IMoniker_Release(mon); + } +} + +static void register_vfw_codecs(void) +{ + static const WCHAR fcchandlerW[] = {'F','c','c','H','a','n','d','l','e','r',0}; + REGFILTERPINS2 rgpins[2]; + IPropertyBag *prop_bag = NULL; + REGPINTYPES rgtypes[2]; + REGFILTER2 rgf; + WCHAR clsid[CHARS_IN_GUID]; + IMoniker *mon = NULL; + GUID typeguid; + ICINFO info; + VARIANT var; + HRESULT hr; + int i = 0; + HIC hic; + + hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory); + if (FAILED(hr)) return; + + while (ICInfo(ICTYPE_VIDEO, i++, &info)) + { + WCHAR name[5] = {LOBYTE(LOWORD(info.fccHandler)), HIBYTE(LOWORD(info.fccHandler)), + LOBYTE(HIWORD(info.fccHandler)), HIBYTE(HIWORD(info.fccHandler))}; + + hic = ICOpen(ICTYPE_VIDEO, info.fccHandler, ICMODE_QUERY); + ICGetInfo(hic, &info, sizeof(info)); + ICClose(hic); + + V_VT(&var) = VT_BSTR; + + V_BSTR(&var) = SysAllocString(name); + if (!(V_BSTR(&var))) + goto cleanup; + + hr = register_codec(&CLSID_VideoCompressorCategory, V_BSTR(&var), &mon); + if (FAILED(hr)) goto cleanup; + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + if (FAILED(hr)) goto cleanup; + + /* write WaveInId */ + hr = IPropertyBag_Write(prop_bag, fcchandlerW, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write friendly name */ + V_VT(&var) = VT_BSTR; + if (!(V_BSTR(&var) = SysAllocString(info.szDescription))) + goto cleanup; + + hr = IPropertyBag_Write(prop_bag, wszFriendlyName, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write clsid */ + V_VT(&var) = VT_BSTR; + StringFromGUID2(&CLSID_AVICo, clsid, CHARS_IN_GUID); + if (!(V_BSTR(&var) = SysAllocString(clsid))) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write filter data */ + rgf.dwVersion = 2; + rgf.dwMerit = MERIT_DO_NOT_USE; + rgf.u.s2.cPins2 = 2; + rgf.u.s2.rgPins2 = rgpins; + rgpins[0].dwFlags = 0; + rgpins[0].nMediaTypes = 1; + rgpins[0].lpMediaType = &rgtypes[0]; + rgtypes[0].clsMajorType = &MEDIATYPE_Video; + typeguid = MEDIASUBTYPE_PCM; + typeguid.Data1 = info.fccHandler; + rgtypes[0].clsMinorType = &typeguid; + rgpins[1].dwFlags = REG_PINFLAG_B_OUTPUT; + rgpins[1].nMediaTypes = 1; + rgpins[1].lpMediaType = &rgtypes[1]; + rgtypes[1].clsMajorType = &MEDIATYPE_Video; + rgtypes[1].clsMinorType = &GUID_NULL; + + write_filter_data(prop_bag, &rgf); + +cleanup: + VariantClear(&var); + if (prop_bag) IPropertyBag_Release(prop_bag); + if (mon) IMoniker_Release(mon); + } } /********************************************************************** @@ -513,7 +894,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); @@ -523,34 +903,16 @@ 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; - } - } - - hkey = open_category_key(clsidDeviceClass); - if (!hkey && !special_hkey) - { - FIXME("Category %s not found\n", debugstr_guid(clsidDeviceClass)); - return S_FALSE; - } + register_codecs(); + register_legacy_filters(); + hr = DirectSoundEnumerateW(®ister_dsound_devices, NULL); + if (FAILED(hr)) return hr; + register_waveout_devices(); + register_wavein_devices(); + register_midiout_devices(); + register_vfw_codecs(); - return DEVENUM_IEnumMoniker_Construct(hkey, special_hkey, ppEnumMoniker); + return create_EnumMoniker(clsidDeviceClass, ppEnumMoniker); } /********************************************************************** @@ -601,164 +963,33 @@ static HRESULT DEVENUM_CreateAMCategoryKey(const CLSID * clsidCategory) return res; } -static void register_vfw_codecs(void) -{ - WCHAR avico_clsid_str[CHARS_IN_GUID]; - HKEY basekey, key; - ICINFO icinfo; - DWORD i, res; - - static const WCHAR CLSIDW[] = {'C','L','S','I','D',0}; - static const WCHAR FccHandlerW[] = {'F','c','c','H','a','n','d','l','e','r',0}; - static const WCHAR FriendlyNameW[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; - - StringFromGUID2(&CLSID_AVICo, avico_clsid_str, sizeof(avico_clsid_str)/sizeof(WCHAR)); - - basekey = open_special_category_key(&CLSID_VideoCompressorCategory, TRUE); - if(!basekey) { - ERR("Could not create key\n"); - return; - } - - for(i=0; ICInfo(FCC('v','i','d','c'), i, &icinfo); i++) { - WCHAR fcc_str[5] = {LOBYTE(LOWORD(icinfo.fccHandler)), HIBYTE(LOWORD(icinfo.fccHandler)), - LOBYTE(HIWORD(icinfo.fccHandler)), HIBYTE(HIWORD(icinfo.fccHandler))}; - - res = RegCreateKeyW(basekey, fcc_str, &key); - if(res != ERROR_SUCCESS) - continue; - - RegSetValueExW(key, CLSIDW, 0, REG_SZ, (const BYTE*)avico_clsid_str, sizeof(avico_clsid_str)); - RegSetValueExW(key, FccHandlerW, 0, REG_SZ, (const BYTE*)fcc_str, sizeof(fcc_str)); - RegSetValueExW(key, FriendlyNameW, 0, REG_SZ, (const BYTE*)icinfo.szName, (strlenW(icinfo.szName)+1)*sizeof(WCHAR)); - /* FIXME: Set ClassManagerFlags and FilterData values */ - - RegCloseKey(key); - } - - RegCloseKey(basekey); -} - -static BOOL WINAPI acm_driver_callback(HACMDRIVERID hadid, DWORD_PTR user, DWORD support) -{ - static const WCHAR CLSIDW[] = {'C','L','S','I','D',0}; - static const WCHAR AcmIdW[] = {'A','c','m','I','d',0}; - static const WCHAR FriendlyNameW[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; - static const WCHAR fmtW[] = {'%','u','%','s',0}; - - WCHAR acmwrapper_clsid_str[CHARS_IN_GUID], buffer[MAX_PATH]; - HKEY key, basekey = (HKEY) user; - ACMFORMATTAGDETAILSW format; - ACMDRIVERDETAILSW driver; - HACMDRIVER had; - DWORD i, res; - - StringFromGUID2(&CLSID_ACMWrapper, acmwrapper_clsid_str, sizeof(acmwrapper_clsid_str)/sizeof(WCHAR)); - - driver.cbStruct = sizeof(driver); - if (acmDriverDetailsW(hadid, &driver, 0) != MMSYSERR_NOERROR) - return TRUE; - - if (acmDriverOpen(&had, hadid, 0) != MMSYSERR_NOERROR) - return TRUE; - - for (i = 0; i < driver.cFormatTags; i++) - { - memset(&format, 0, sizeof(format)); - format.cbStruct = sizeof(format); - format.dwFormatTagIndex = i; - - if (acmFormatTagDetailsW(had, &format, ACM_FORMATTAGDETAILSF_INDEX) != MMSYSERR_NOERROR) - continue; - - snprintfW(buffer, sizeof(buffer)/sizeof(WCHAR), fmtW, format.dwFormatTag, format.szFormatTag); - - res = RegCreateKeyW(basekey, buffer, &key); - if (res != ERROR_SUCCESS) continue; - - RegSetValueExW(key, CLSIDW, 0, REG_SZ, (BYTE*)acmwrapper_clsid_str, sizeof(acmwrapper_clsid_str)); - RegSetValueExW(key, AcmIdW, 0, REG_DWORD, (BYTE*)&format.dwFormatTag, sizeof(DWORD)); - RegSetValueExW(key, FriendlyNameW, 0, REG_SZ, (BYTE*)format.szFormatTag, (strlenW(format.szFormatTag)+1)*sizeof(WCHAR)); - /* FIXME: Set FilterData values */ - - RegCloseKey(key); - } - - acmDriverClose(had, 0); - - return TRUE; -} - -static void register_acm_codecs(void) -{ - HKEY basekey; - - basekey = open_special_category_key(&CLSID_AudioCompressorCategory, TRUE); - if (!basekey) - { - ERR("Could not create key\n"); - return; - } - - acmDriverEnum(acm_driver_callback, (DWORD_PTR)basekey, 0); - - RegCloseKey(basekey); -} - -static HANDLE DEVENUM_populate_handle; -static const WCHAR DEVENUM_populate_handle_nameW[] = - {'_','_','W','I','N','E','_', - '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) - return S_OK; - DEVENUM_populate_handle = CreateEventW(NULL, TRUE, FALSE, DEVENUM_populate_handle_nameW); - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - /* Webcams can take some time to scan if the driver is badly written and it enables them, - * so have a 10 s timeout here - */ - if (WaitForSingleObject(DEVENUM_populate_handle, 10000) == WAIT_TIMEOUT) - WARN("Waiting for object timed out\n"); - TRACE("No need to rescan\n"); - return S_OK; - } - TRACE("Scanning for devices\n"); - /* 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); - if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_AudioCompressorCategory, &basekey, path, MAX_PATH))) - RegDeleteTreeW(basekey, path); + RegOpenKeyW(HKEY_CURRENT_USER, wszActiveMovieKey, &basekey); + StringFromGUID2(&CLSID_LegacyAmFilterCategory, class, CHARS_IN_GUID); + RegDeleteTreeW(basekey, class); + 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; @@ -769,12 +1000,6 @@ static HRESULT DEVENUM_CreateSpecialCategories(void) rfp2.lpMedium = NULL; rfp2.clsPinCategory = &IID_NULL; - if (!LoadStringW(DEVENUM_hInstance, IDS_DEVENUM_DS, szDSoundNameFormat, sizeof(szDSoundNameFormat)/sizeof(szDSoundNameFormat[0])-1)) - { - ERR("Couldn't get string resource (GetLastError() is %d)\n", GetLastError()); - return HRESULT_FROM_WIN32(GetLastError()); - } - res = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2, (void **) &pMapper); /* @@ -783,205 +1008,9 @@ static HRESULT DEVENUM_CreateSpecialCategories(void) if (SUCCEEDED(res)) { UINT i; - WAVEOUTCAPSW wocaps; - WAVEINCAPSW wicaps; - MIDIOUTCAPSW mocaps; REGPINTYPES * pTypes; IPropertyBag * pPropBag = NULL; - numDevs = waveOutGetNumDevs(); - - res = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory); - if (FAILED(res)) /* can't register any devices in this category */ - numDevs = 0; - - rfp2.dwFlags = REG_PINFLAG_B_RENDERER; - for (i = 0; i < numDevs; i++) - { - if (waveOutGetDevCapsW(i, &wocaps, sizeof(WAVEOUTCAPSW)) - == MMSYSERR_NOERROR) - { - IMoniker * pMoniker = NULL; - - rfp2.nMediaTypes = 1; - pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES)); - if (!pTypes) - { - IFilterMapper2_Release(pMapper); - return E_OUTOFMEMORY; - } - /* FIXME: Native devenum seems to register a lot more types for - * DSound than we do. Not sure what purpose they serve */ - pTypes[0].clsMajorType = &MEDIATYPE_Audio; - pTypes[0].clsMinorType = &MEDIASUBTYPE_PCM; - - rfp2.lpMediaType = pTypes; - - res = IFilterMapper2_RegisterFilter(pMapper, - &CLSID_AudioRender, - wocaps.szPname, - &pMoniker, - &CLSID_AudioRendererCategory, - wocaps.szPname, - &rf2); - - if (pMoniker) - { - VARIANT var; - - V_VT(&var) = VT_I4; - V_I4(&var) = i; - res = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID)&pPropBag); - if (SUCCEEDED(res)) - res = IPropertyBag_Write(pPropBag, wszWaveOutID, &var); - else - pPropBag = NULL; - - V_VT(&var) = VT_LPWSTR; - V_BSTR(&var) = wocaps.szPname; - if (SUCCEEDED(res)) - res = IPropertyBag_Write(pPropBag, wszFriendlyName, &var); - if (pPropBag) - IPropertyBag_Release(pPropBag); - IMoniker_Release(pMoniker); - pMoniker = NULL; - } - - wsprintfW(szDSoundName, szDSoundNameFormat, wocaps.szPname); - res = IFilterMapper2_RegisterFilter(pMapper, - &CLSID_DSoundRender, - szDSoundName, - &pMoniker, - &CLSID_AudioRendererCategory, - szDSoundName, - &rf2); - - /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */ - - if (pMoniker) - IMoniker_Release(pMoniker); - - if (i == iDefaultDevice) - { - FIXME("Default device\n"); - } - - CoTaskMemFree(pTypes); - } - } - - numDevs = waveInGetNumDevs(); - - res = DEVENUM_CreateAMCategoryKey(&CLSID_AudioInputDeviceCategory); - if (FAILED(res)) /* can't register any devices in this category */ - numDevs = 0; - - rfp2.dwFlags = REG_PINFLAG_B_OUTPUT; - for (i = 0; i < numDevs; i++) - { - if (waveInGetDevCapsW(i, &wicaps, sizeof(WAVEINCAPSW)) - == MMSYSERR_NOERROR) - { - IMoniker * pMoniker = NULL; - - rfp2.nMediaTypes = 1; - pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES)); - if (!pTypes) - { - IFilterMapper2_Release(pMapper); - return E_OUTOFMEMORY; - } - - /* FIXME: Not sure if these are correct */ - pTypes[0].clsMajorType = &MEDIATYPE_Audio; - pTypes[0].clsMinorType = &MEDIASUBTYPE_PCM; - - rfp2.lpMediaType = pTypes; - - res = IFilterMapper2_RegisterFilter(pMapper, - &CLSID_AudioRecord, - wicaps.szPname, - &pMoniker, - &CLSID_AudioInputDeviceCategory, - wicaps.szPname, - &rf2); - - - if (pMoniker) { - VARIANT var; - - V_VT(&var) = VT_I4; - V_I4(&var) = i; - res = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID)&pPropBag); - if (SUCCEEDED(res)) - res = IPropertyBag_Write(pPropBag, wszWaveInID, &var); - else - pPropBag = NULL; - - V_VT(&var) = VT_LPWSTR; - V_BSTR(&var) = wicaps.szPname; - if (SUCCEEDED(res)) - res = IPropertyBag_Write(pPropBag, wszFriendlyName, &var); - - if (pPropBag) - IPropertyBag_Release(pPropBag); - IMoniker_Release(pMoniker); - } - - CoTaskMemFree(pTypes); - } - } - - numDevs = midiOutGetNumDevs(); - - res = DEVENUM_CreateAMCategoryKey(&CLSID_MidiRendererCategory); - if (FAILED(res)) /* can't register any devices in this category */ - numDevs = 0; - - rfp2.dwFlags = REG_PINFLAG_B_RENDERER; - for (i = 0; i < numDevs; i++) - { - if (midiOutGetDevCapsW(i, &mocaps, sizeof(MIDIOUTCAPSW)) - == MMSYSERR_NOERROR) - { - IMoniker * pMoniker = NULL; - - rfp2.nMediaTypes = 1; - pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES)); - if (!pTypes) - { - IFilterMapper2_Release(pMapper); - return E_OUTOFMEMORY; - } - - /* FIXME: Not sure if these are correct */ - pTypes[0].clsMajorType = &MEDIATYPE_Midi; - pTypes[0].clsMinorType = &MEDIASUBTYPE_None; - - rfp2.lpMediaType = pTypes; - - res = IFilterMapper2_RegisterFilter(pMapper, - &CLSID_AVIMIDIRender, - mocaps.szPname, - &pMoniker, - &CLSID_MidiRendererCategory, - mocaps.szPname, - &rf2); - - /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */ - /* Native version sets MidiOutId */ - - if (pMoniker) - IMoniker_Release(pMoniker); - - if (i == iDefaultDevice) - { - FIXME("Default device\n"); - } - - CoTaskMemFree(pTypes); - } - } res = DEVENUM_CreateAMCategoryKey(&CLSID_VideoInputDeviceCategory); if (SUCCEEDED(res)) for (i = 0; i < 10; i++) @@ -1039,9 +1068,5 @@ static HRESULT DEVENUM_CreateSpecialCategories(void) if (pMapper) IFilterMapper2_Release(pMapper); - register_vfw_codecs(); - register_acm_codecs(); - - SetEvent(DEVENUM_populate_handle); return res; } diff --git a/dll/directx/wine/devenum/devenum.rc b/dll/directx/wine/devenum/devenum.rc index 294d41ff23..1cc74a4394 100644 --- a/dll/directx/wine/devenum/devenum.rc +++ b/dll/directx/wine/devenum/devenum.rc @@ -23,18 +23,6 @@ #include "winnls.h" #include "devenum_private.h" -#pragma makedep po - -LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT - -STRINGTABLE -{ - IDS_DEVENUM_DSDEFAULT "Default DirectSound" - IDS_DEVENUM_DS "DirectSound: %s" - IDS_DEVENUM_WODEFAULT "Default WaveOut Device" - IDS_DEVENUM_MIDEFAULT "Default MidiOut Device" -} - LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL #define WINE_FILEDESCRIPTION_STR "Wine Device Enumerator Library" diff --git a/dll/directx/wine/devenum/devenum_private.h b/dll/directx/wine/devenum/devenum_private.h index 72c285d422..005f0b56e6 100644 --- a/dll/directx/wine/devenum/devenum_private.h +++ b/dll/directx/wine/devenum/devenum_private.h @@ -62,38 +62,40 @@ typedef struct IClassFactory IClassFactory_iface; } ClassFactoryImpl; +enum device_type +{ + DEVICE_FILTER, + DEVICE_CODEC, +}; + 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; -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 */ -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 - */ -#define IDS_DEVENUM_DSDEFAULT 7 -#define IDS_DEVENUM_DS 8 -#define IDS_DEVENUM_WODEFAULT 9 -#define IDS_DEVENUM_MIDEFAULT 10 -#define IDS_DEVENUM_KSDEFAULT 11 -#define IDS_DEVENUM_KS 12 +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','\\', + '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/dll/directx/wine/devenum/fil_data.idl b/dll/directx/wine/devenum/fil_data.idl new file mode 100644 index 0000000000..7e37a755d9 --- /dev/null +++ b/dll/directx/wine/devenum/fil_data.idl @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Vitaliy Margolen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma makedep header + +import "objidl.idl"; +import "strmif.idl"; +import "unknwn.idl"; + + +/***************************************************************************** + * IAMFilterData interface + */ +[ + object, + uuid(97f7c4d4-547b-4a5f-8332-536430ad2e4d), + pointer_default(unique) +] +interface IAMFilterData : IUnknown +{ + typedef [unique] IAMFilterData *LPIAMFILTERDATA; + + HRESULT ParseFilterData( + [in] BYTE * rgbFilterData, + [in] ULONG cb, + [out] BYTE ** prgbRegFilter2); + + HRESULT CreateFilterData( + [in] REGFILTER2 * prf2, + [out] BYTE ** prgbFilterData, + [out] ULONG * pcb); +} diff --git a/dll/directx/wine/devenum/mediacatenum.c b/dll/directx/wine/devenum/mediacatenum.c index 4edc4e9622..a76c7bebfb 100644 --- a/dll/directx/wine/devenum/mediacatenum.c +++ b/dll/directx/wine/devenum/mediacatenum.c @@ -33,18 +33,20 @@ WINE_DEFAULT_DEBUG_CHANNEL(devenum); typedef struct { IEnumMoniker IEnumMoniker_iface; + CLSID class; 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 { IPropertyBag IPropertyBag_iface; LONG ref; - HKEY hkey; + enum device_type type; + WCHAR path[MAX_PATH]; } RegPropBagImpl; @@ -100,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(); } @@ -118,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); } @@ -214,6 +225,8 @@ static HRESULT WINAPI DEVENUM_IPropertyBag_Read( HeapFree(GetProcessHeap(), 0, pData); + RegCloseKey(hkey); + TRACE("<- %x\n", res); return res; } @@ -228,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); @@ -264,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)); @@ -284,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; @@ -344,7 +381,7 @@ 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(); } @@ -407,6 +444,9 @@ static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToObject(IMoniker *iface, IBi TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riidResult), ppvResult); + if (!ppvResult) + return E_POINTER; + VariantInit(&var); *ppvResult = NULL; @@ -485,9 +525,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; @@ -620,24 +658,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, @@ -694,7 +743,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); @@ -748,9 +798,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 +815,55 @@ 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; + + if (!(pMoniker = DEVENUM_IMediaCatMoniker_Construct())) + return E_OUTOFMEMORY; + + pMoniker->type = DEVICE_FILTER; } - pMoniker = DEVENUM_IMediaCatMoniker_Construct(); - if (!pMoniker) - return E_OUTOFMEMORY; + /* 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; - if (RegOpenKeyW(This->index+fetched < This->subkey_cnt ? This->hkey : This->special_hkey, - buffer, &pMoniker->hkey) != ERROR_SUCCESS) + if (!(pMoniker = DEVENUM_IMediaCatMoniker_Construct())) + return E_OUTOFMEMORY; + + pMoniker->type = DEVICE_CODEC; + } + else + break; + + if (!(pMoniker->name = CoTaskMemAlloc((strlenW(buffer) + 1) * sizeof(WCHAR)))) { IMoniker_Release(&pMoniker->IMoniker_iface); - break; + return E_OUTOFMEMORY; } + strcpyW(pMoniker->name, buffer); + pMoniker->has_class = TRUE; + pMoniker->class = This->class; + rgelt[fetched] = &pMoniker->IMoniker_iface; fetched++; } - This->index += fetched; - TRACE("-- fetched %d\n", fetched); if (pceltFetched) @@ -811,21 +878,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 +908,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 +935,32 @@ 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; + pEnumMoniker->class = *class; - *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/dll/directx/wine/devenum/parsedisplayname.c b/dll/directx/wine/devenum/parsedisplayname.c index 77ea1ecdcb..0f3ef3be5a 100644 --- a/dll/directx/wine/devenum/parsedisplayname.c +++ b/dll/directx/wine/devenum/parsedisplayname.c @@ -76,69 +76,60 @@ 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 res = S_OK; - WCHAR wszRegKeyName[MAX_PATH]; - HKEY hbasekey; - int classlen; - static const WCHAR wszRegSeparator[] = {'\\', 0 }; - - TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(pszDisplayName), pchEaten, ppmkOut); - - *ppmkOut = NULL; - if (pchEaten) - *pchEaten = strlenW(pszDisplayName); - - 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) - return E_OUTOFMEMORY; + WCHAR buffer[MAX_PATH]; + enum device_type type; + MediaCatMoniker *mon; + CLSID class; + + TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(name), eaten, ret); + + *ret = NULL; + if (eaten) + *eaten = strlenW(name); - memcpy(pszClass, pszDisplayName, classlen * sizeof(WCHAR)); - pszClass[classlen] = 0; + name = strchrW(name, ':') + 1; - TRACE("Device CLSID: %s\n", debugstr_w(pszClass)); + if (name[0] == 's' && name[1] == 'w' && name[2] == ':') + { + type = DEVICE_FILTER; + name += 3; + } + else if (name[0] == 'c' && name[1] == 'm' && name[2] == ':') + { + type = DEVICE_CODEC; + name += 3; + } + else + { + FIXME("unhandled device type %s\n", debugstr_w(name)); + return MK_E_SYNTAX; + } - res = CLSIDFromString(pszClass, &clsidDevice); + if (!(mon = DEVENUM_IMediaCatMoniker_Construct())) + return E_OUTOFMEMORY; - if (SUCCEEDED(res)) + lstrcpynW(buffer, name, CHARS_IN_GUID); + if (CLSIDFromString(buffer, &class) == S_OK) { - res = DEVENUM_GetCategoryKey(&clsidDevice, &hbasekey, wszRegKeyName, MAX_PATH); + mon->has_class = TRUE; + mon->class = class; + name += CHARS_IN_GUID; } - if (SUCCEEDED(res)) + mon->type = type; + + if (!(mon->name = CoTaskMemAlloc((strlenW(name) + 1) * sizeof(WCHAR)))) { - pMoniker = DEVENUM_IMediaCatMoniker_Construct(); - if (pMoniker) - { - 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; - } - } + IMoniker_Release(&mon->IMoniker_iface); + return E_OUTOFMEMORY; } + strcpyW(mon->name, name); - CoTaskMemFree(pszClass); + *ret = &mon->IMoniker_iface; - TRACE("-- returning: %x\n", res); - return res; + return S_OK; } /********************************************************************** diff --git a/media/doc/README.WINE b/media/doc/README.WINE index 477bb4d3e3..a5b6b1865a 100644 --- a/media/doc/README.WINE +++ b/media/doc/README.WINE @@ -29,7 +29,7 @@ reactos/dll/directx/wine/d3drm # Synced to WineStaging-3.9 reactos/dll/directx/wine/d3dx9_24 => 43 # Synced to WineStaging-3.9 reactos/dll/directx/wine/d3dxof # Synced to WineStaging-3.3 reactos/dll/directx/wine/ddraw # Synced to WineStaging-3.9 -reactos/dll/directx/wine/devenum # Synced to WineStaging-3.3 +reactos/dll/directx/wine/devenum # Synced to WineStaging-3.9 reactos/dll/directx/wine/dinput # Synced to WineStaging-3.3 reactos/dll/directx/wine/dinput8 # Synced to WineStaging-3.3 reactos/dll/directx/wine/dmusic # Synced to WineStaging-3.3