| /* | |
| * Copyright 2009 Vincent Povirk for CodeWeavers | |
| * | |
| * 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 | |
| */ | |
| #include "config.h" | |
| #include <stdarg.h> | |
| #define COBJMACROS | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winreg.h" | |
| #include "objbase.h" | |
| #include "wincodec.h" | |
| #include "wincodecs_private.h" | |
| #include "wine/debug.h" | |
| #include "wine/unicode.h" | |
| #include "wine/list.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); | |
| static WCHAR const pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0}; | |
| typedef struct { | |
| const IWICBitmapDecoderInfoVtbl *lpIWICBitmapDecoderInfoVtbl; | |
| LONG ref; | |
| HKEY classkey; | |
| CLSID clsid; | |
| } BitmapDecoderInfo; | |
| static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *iface, REFIID iid, | |
| void **ppv) | |
| { | |
| BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface; | |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); | |
| if (!ppv) return E_INVALIDARG; | |
| if (IsEqualIID(&IID_IUnknown, iid) || | |
| IsEqualIID(&IID_IWICComponentInfo, iid) || | |
| IsEqualIID(&IID_IWICBitmapCodecInfo, iid) || | |
| IsEqualIID(&IID_IWICBitmapDecoderInfo ,iid)) | |
| { | |
| *ppv = This; | |
| } | |
| else | |
| { | |
| *ppv = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface) | |
| { | |
| BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface; | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) refcount=%u\n", iface, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI BitmapDecoderInfo_Release(IWICBitmapDecoderInfo *iface) | |
| { | |
| BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface; | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p) refcount=%u\n", iface, ref); | |
| if (ref == 0) | |
| { | |
| RegCloseKey(This->classkey); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetComponentType(IWICBitmapDecoderInfo *iface, | |
| WICComponentType *pType) | |
| { | |
| TRACE("(%p,%p)\n", iface, pType); | |
| *pType = WICDecoder; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetCLSID(IWICBitmapDecoderInfo *iface, CLSID *pclsid) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pclsid); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetSigningStatus(IWICBitmapDecoderInfo *iface, DWORD *pStatus) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pStatus); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetAuthor(IWICBitmapDecoderInfo *iface, UINT cchAuthor, | |
| WCHAR *wzAuthor, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetVendorGUID(IWICBitmapDecoderInfo *iface, GUID *pguidVendor) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pguidVendor); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetVersion(IWICBitmapDecoderInfo *iface, UINT cchVersion, | |
| WCHAR *wzVersion, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetSpecVersion(IWICBitmapDecoderInfo *iface, UINT cchSpecVersion, | |
| WCHAR *wzSpecVersion, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetFriendlyName(IWICBitmapDecoderInfo *iface, UINT cchFriendlyName, | |
| WCHAR *wzFriendlyName, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetContainerFormat(IWICBitmapDecoderInfo *iface, | |
| GUID *pguidContainerFormat) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pguidContainerFormat); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetPixelFormats(IWICBitmapDecoderInfo *iface, | |
| UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetColorManagementVersion(IWICBitmapDecoderInfo *iface, | |
| UINT cchColorManagementVersion, WCHAR *wzColorManagementVersion, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchColorManagementVersion, wzColorManagementVersion, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetDeviceManufacturer(IWICBitmapDecoderInfo *iface, | |
| UINT cchDeviceManufacturer, WCHAR *wzDeviceManufacturer, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceManufacturer, wzDeviceManufacturer, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetDeviceModels(IWICBitmapDecoderInfo *iface, | |
| UINT cchDeviceModels, WCHAR *wzDeviceModels, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceModels, wzDeviceModels, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetMimeTypes(IWICBitmapDecoderInfo *iface, | |
| UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchMimeTypes, wzMimeTypes, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetFileExtensions(IWICBitmapDecoderInfo *iface, | |
| UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchFileExtensions, wzFileExtensions, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_DoesSupportAnimation(IWICBitmapDecoderInfo *iface, | |
| BOOL *pfSupportAnimation) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pfSupportAnimation); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_DoesSupportChromaKey(IWICBitmapDecoderInfo *iface, | |
| BOOL *pfSupportChromaKey) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pfSupportChromaKey); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_DoesSupportLossless(IWICBitmapDecoderInfo *iface, | |
| BOOL *pfSupportLossless) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pfSupportLossless); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_DoesSupportMultiframe(IWICBitmapDecoderInfo *iface, | |
| BOOL *pfSupportMultiframe) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pfSupportMultiframe); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_MatchesMimeType(IWICBitmapDecoderInfo *iface, | |
| LPCWSTR wzMimeType, BOOL *pfMatches) | |
| { | |
| FIXME("(%p,%s,%p): stub\n", iface, debugstr_w(wzMimeType), pfMatches); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_GetPatterns(IWICBitmapDecoderInfo *iface, | |
| UINT cbSizePatterns, WICBitmapPattern *pPatterns, UINT *pcPatterns, UINT *pcbPatternsActual) | |
| { | |
| BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface; | |
| UINT pattern_count=0, patterns_size=0; | |
| WCHAR subkeyname[11]; | |
| LONG res; | |
| HKEY patternskey, patternkey; | |
| static const WCHAR uintformatW[] = {'%','u',0}; | |
| static const WCHAR patternsW[] = {'P','a','t','t','e','r','n','s',0}; | |
| static const WCHAR positionW[] = {'P','o','s','i','t','i','o','n',0}; | |
| static const WCHAR lengthW[] = {'L','e','n','g','t','h',0}; | |
| static const WCHAR patternW[] = {'P','a','t','t','e','r','n',0}; | |
| static const WCHAR maskW[] = {'M','a','s','k',0}; | |
| static const WCHAR endofstreamW[] = {'E','n','d','O','f','S','t','r','e','a','m',0}; | |
| HRESULT hr=S_OK; | |
| UINT i; | |
| BYTE *bPatterns=(BYTE*)pPatterns; | |
| DWORD length, valuesize; | |
| TRACE("(%p,%i,%p,%p,%p)\n", iface, cbSizePatterns, pPatterns, pcPatterns, pcbPatternsActual); | |
| res = RegOpenKeyExW(This->classkey, patternsW, 0, KEY_READ, &patternskey); | |
| if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res); | |
| res = RegQueryInfoKeyW(patternskey, NULL, NULL, NULL, &pattern_count, NULL, NULL, NULL, NULL, NULL, NULL, NULL); | |
| if (res == ERROR_SUCCESS) | |
| { | |
| patterns_size = pattern_count * sizeof(WICBitmapPattern); | |
| for (i=0; i<pattern_count; i++) | |
| { | |
| snprintfW(subkeyname, 11, uintformatW, i); | |
| res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey); | |
| if (res == ERROR_SUCCESS) | |
| { | |
| valuesize = sizeof(ULONG); | |
| res = RegGetValueW(patternkey, NULL, lengthW, RRF_RT_DWORD, NULL, | |
| &length, &valuesize); | |
| patterns_size += length*2; | |
| if ((cbSizePatterns >= patterns_size) && (res == ERROR_SUCCESS)) | |
| { | |
| pPatterns[i].Length = length; | |
| pPatterns[i].EndOfStream = 0; | |
| valuesize = sizeof(BOOL); | |
| RegGetValueW(patternkey, NULL, endofstreamW, RRF_RT_DWORD, NULL, | |
| &pPatterns[i].EndOfStream, &valuesize); | |
| pPatterns[i].Position.QuadPart = 0; | |
| valuesize = sizeof(ULARGE_INTEGER); | |
| res = RegGetValueW(patternkey, NULL, positionW, RRF_RT_DWORD|RRF_RT_QWORD, NULL, | |
| &pPatterns[i].Position, &valuesize); | |
| if (res == ERROR_SUCCESS) | |
| { | |
| pPatterns[i].Pattern = bPatterns+patterns_size-length*2; | |
| valuesize = length; | |
| res = RegGetValueW(patternkey, NULL, patternW, RRF_RT_REG_BINARY, NULL, | |
| pPatterns[i].Pattern, &valuesize); | |
| } | |
| if (res == ERROR_SUCCESS) | |
| { | |
| pPatterns[i].Mask = bPatterns+patterns_size-length; | |
| valuesize = length; | |
| res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL, | |
| pPatterns[i].Mask, &valuesize); | |
| } | |
| } | |
| RegCloseKey(patternkey); | |
| } | |
| if (res != ERROR_SUCCESS) | |
| { | |
| hr = HRESULT_FROM_WIN32(res); | |
| break; | |
| } | |
| } | |
| } | |
| else hr = HRESULT_FROM_WIN32(res); | |
| RegCloseKey(patternskey); | |
| if (hr == S_OK) | |
| { | |
| *pcPatterns = pattern_count; | |
| *pcbPatternsActual = patterns_size; | |
| if (pPatterns && cbSizePatterns < patterns_size) | |
| hr = WINCODEC_ERR_INSUFFICIENTBUFFER; | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *iface, | |
| IStream *pIStream, BOOL *pfMatches) | |
| { | |
| WICBitmapPattern *patterns; | |
| UINT pattern_count=0, patterns_size=0; | |
| HRESULT hr; | |
| int i, pos; | |
| BYTE *data=NULL; | |
| ULONG datasize=0; | |
| ULONG bytesread; | |
| LARGE_INTEGER seekpos; | |
| TRACE("(%p,%p,%p)\n", iface, pIStream, pfMatches); | |
| hr = BitmapDecoderInfo_GetPatterns(iface, 0, NULL, &pattern_count, &patterns_size); | |
| if (FAILED(hr)) return hr; | |
| patterns = HeapAlloc(GetProcessHeap(), 0, patterns_size); | |
| if (!patterns) return E_OUTOFMEMORY; | |
| hr = BitmapDecoderInfo_GetPatterns(iface, patterns_size, patterns, &pattern_count, &patterns_size); | |
| if (FAILED(hr)) goto end; | |
| for (i=0; i<pattern_count; i++) | |
| { | |
| if (datasize < patterns[i].Length) | |
| { | |
| HeapFree(GetProcessHeap(), 0, data); | |
| datasize = patterns[i].Length; | |
| data = HeapAlloc(GetProcessHeap(), 0, patterns[i].Length); | |
| if (!data) | |
| { | |
| hr = E_OUTOFMEMORY; | |
| break; | |
| } | |
| } | |
| if (patterns[i].EndOfStream) | |
| seekpos.QuadPart = -patterns[i].Position.QuadPart; | |
| else | |
| seekpos.QuadPart = patterns[i].Position.QuadPart; | |
| hr = IStream_Seek(pIStream, seekpos, patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL); | |
| if (hr == STG_E_INVALIDFUNCTION) continue; /* before start of stream */ | |
| if (FAILED(hr)) break; | |
| hr = IStream_Read(pIStream, data, patterns[i].Length, &bytesread); | |
| if (hr == S_FALSE || (hr == S_OK && bytesread != patterns[i].Length)) /* past end of stream */ | |
| continue; | |
| if (FAILED(hr)) break; | |
| for (pos=0; pos<patterns[i].Length; pos++) | |
| { | |
| if ((data[pos] & patterns[i].Mask[pos]) != patterns[i].Pattern[pos]) | |
| break; | |
| } | |
| if (pos == patterns[i].Length) /* matches pattern */ | |
| { | |
| hr = S_OK; | |
| *pfMatches = TRUE; | |
| break; | |
| } | |
| } | |
| if (i == pattern_count) /* does not match any pattern */ | |
| { | |
| hr = S_OK; | |
| *pfMatches = FALSE; | |
| } | |
| end: | |
| HeapFree(GetProcessHeap(), 0, patterns); | |
| HeapFree(GetProcessHeap(), 0, data); | |
| return hr; | |
| } | |
| static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *iface, | |
| IWICBitmapDecoder **ppIBitmapDecoder) | |
| { | |
| BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface; | |
| TRACE("(%p,%p)\n", iface, ppIBitmapDecoder); | |
| return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER, | |
| &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder); | |
| } | |
| static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = { | |
| BitmapDecoderInfo_QueryInterface, | |
| BitmapDecoderInfo_AddRef, | |
| BitmapDecoderInfo_Release, | |
| BitmapDecoderInfo_GetComponentType, | |
| BitmapDecoderInfo_GetCLSID, | |
| BitmapDecoderInfo_GetSigningStatus, | |
| BitmapDecoderInfo_GetAuthor, | |
| BitmapDecoderInfo_GetVendorGUID, | |
| BitmapDecoderInfo_GetVersion, | |
| BitmapDecoderInfo_GetSpecVersion, | |
| BitmapDecoderInfo_GetFriendlyName, | |
| BitmapDecoderInfo_GetContainerFormat, | |
| BitmapDecoderInfo_GetPixelFormats, | |
| BitmapDecoderInfo_GetColorManagementVersion, | |
| BitmapDecoderInfo_GetDeviceManufacturer, | |
| BitmapDecoderInfo_GetDeviceModels, | |
| BitmapDecoderInfo_GetMimeTypes, | |
| BitmapDecoderInfo_GetFileExtensions, | |
| BitmapDecoderInfo_DoesSupportAnimation, | |
| BitmapDecoderInfo_DoesSupportChromaKey, | |
| BitmapDecoderInfo_DoesSupportLossless, | |
| BitmapDecoderInfo_DoesSupportMultiframe, | |
| BitmapDecoderInfo_MatchesMimeType, | |
| BitmapDecoderInfo_GetPatterns, | |
| BitmapDecoderInfo_MatchesPattern, | |
| BitmapDecoderInfo_CreateInstance | |
| }; | |
| static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo) | |
| { | |
| BitmapDecoderInfo *This; | |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapDecoderInfo)); | |
| if (!This) | |
| { | |
| RegCloseKey(classkey); | |
| return E_OUTOFMEMORY; | |
| } | |
| This->lpIWICBitmapDecoderInfoVtbl = &BitmapDecoderInfo_Vtbl; | |
| This->ref = 1; | |
| This->classkey = classkey; | |
| memcpy(&This->clsid, clsid, sizeof(CLSID)); | |
| *ppIInfo = (IWICComponentInfo*)This; | |
| return S_OK; | |
| } | |
| typedef struct { | |
| const IWICFormatConverterInfoVtbl *lpIWICFormatConverterInfoVtbl; | |
| LONG ref; | |
| HKEY classkey; | |
| CLSID clsid; | |
| } FormatConverterInfo; | |
| static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo *iface, REFIID iid, | |
| void **ppv) | |
| { | |
| FormatConverterInfo *This = (FormatConverterInfo*)iface; | |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); | |
| if (!ppv) return E_INVALIDARG; | |
| if (IsEqualIID(&IID_IUnknown, iid) || | |
| IsEqualIID(&IID_IWICComponentInfo, iid) || | |
| IsEqualIID(&IID_IWICFormatConverterInfo ,iid)) | |
| { | |
| *ppv = This; | |
| } | |
| else | |
| { | |
| *ppv = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI FormatConverterInfo_AddRef(IWICFormatConverterInfo *iface) | |
| { | |
| FormatConverterInfo *This = (FormatConverterInfo*)iface; | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) refcount=%u\n", iface, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI FormatConverterInfo_Release(IWICFormatConverterInfo *iface) | |
| { | |
| FormatConverterInfo *This = (FormatConverterInfo*)iface; | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p) refcount=%u\n", iface, ref); | |
| if (ref == 0) | |
| { | |
| RegCloseKey(This->classkey); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI FormatConverterInfo_GetComponentType(IWICFormatConverterInfo *iface, | |
| WICComponentType *pType) | |
| { | |
| TRACE("(%p,%p)\n", iface, pType); | |
| *pType = WICPixelFormatConverter; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI FormatConverterInfo_GetCLSID(IWICFormatConverterInfo *iface, CLSID *pclsid) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pclsid); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI FormatConverterInfo_GetSigningStatus(IWICFormatConverterInfo *iface, DWORD *pStatus) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pStatus); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI FormatConverterInfo_GetAuthor(IWICFormatConverterInfo *iface, UINT cchAuthor, | |
| WCHAR *wzAuthor, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI FormatConverterInfo_GetVendorGUID(IWICFormatConverterInfo *iface, GUID *pguidVendor) | |
| { | |
| FIXME("(%p,%p): stub\n", iface, pguidVendor); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI FormatConverterInfo_GetVersion(IWICFormatConverterInfo *iface, UINT cchVersion, | |
| WCHAR *wzVersion, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI FormatConverterInfo_GetSpecVersion(IWICFormatConverterInfo *iface, UINT cchSpecVersion, | |
| WCHAR *wzSpecVersion, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI FormatConverterInfo_GetFriendlyName(IWICFormatConverterInfo *iface, UINT cchFriendlyName, | |
| WCHAR *wzFriendlyName, UINT *pcchActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI FormatConverterInfo_GetPixelFormats(IWICFormatConverterInfo *iface, | |
| UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual) | |
| { | |
| FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI FormatConverterInfo_CreateInstance(IWICFormatConverterInfo *iface, | |
| IWICFormatConverter **ppIFormatConverter) | |
| { | |
| FormatConverterInfo *This = (FormatConverterInfo*)iface; | |
| TRACE("(%p,%p)\n", iface, ppIFormatConverter); | |
| return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER, | |
| &IID_IWICFormatConverter, (void**)ppIFormatConverter); | |
| } | |
| static BOOL ConverterSupportsFormat(IWICFormatConverterInfo *iface, const WCHAR *formatguid) | |
| { | |
| LONG res; | |
| FormatConverterInfo *This = (FormatConverterInfo*)iface; | |
| HKEY formats_key, guid_key; | |
| /* Avoid testing using IWICFormatConverter_GetPixelFormats because that | |
| would be O(n). A registry test should do better. */ | |
| res = RegOpenKeyExW(This->classkey, pixelformats_keyname, 0, KEY_READ, &formats_key); | |
| if (res != ERROR_SUCCESS) return FALSE; | |
| res = RegOpenKeyExW(formats_key, formatguid, 0, KEY_READ, &guid_key); | |
| if (res == ERROR_SUCCESS) RegCloseKey(guid_key); | |
| RegCloseKey(formats_key); | |
| return (res == ERROR_SUCCESS); | |
| } | |
| static const IWICFormatConverterInfoVtbl FormatConverterInfo_Vtbl = { | |
| FormatConverterInfo_QueryInterface, | |
| FormatConverterInfo_AddRef, | |
| FormatConverterInfo_Release, | |
| FormatConverterInfo_GetComponentType, | |
| FormatConverterInfo_GetCLSID, | |
| FormatConverterInfo_GetSigningStatus, | |
| FormatConverterInfo_GetAuthor, | |
| FormatConverterInfo_GetVendorGUID, | |
| FormatConverterInfo_GetVersion, | |
| FormatConverterInfo_GetSpecVersion, | |
| FormatConverterInfo_GetFriendlyName, | |
| FormatConverterInfo_GetPixelFormats, | |
| FormatConverterInfo_CreateInstance | |
| }; | |
| static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo) | |
| { | |
| FormatConverterInfo *This; | |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverterInfo)); | |
| if (!This) | |
| { | |
| RegCloseKey(classkey); | |
| return E_OUTOFMEMORY; | |
| } | |
| This->lpIWICFormatConverterInfoVtbl = &FormatConverterInfo_Vtbl; | |
| This->ref = 1; | |
| This->classkey = classkey; | |
| memcpy(&This->clsid, clsid, sizeof(CLSID)); | |
| *ppIInfo = (IWICComponentInfo*)This; | |
| return S_OK; | |
| } | |
| static WCHAR const clsid_keyname[] = {'C','L','S','I','D',0}; | |
| static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0}; | |
| struct category { | |
| WICComponentType type; | |
| const GUID *catid; | |
| HRESULT (*constructor)(HKEY,REFCLSID,IWICComponentInfo**); | |
| }; | |
| static const struct category categories[] = { | |
| {WICDecoder, &CATID_WICBitmapDecoders, BitmapDecoderInfo_Constructor}, | |
| {WICPixelFormatConverter, &CATID_WICFormatConverters, FormatConverterInfo_Constructor}, | |
| {0} | |
| }; | |
| HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo) | |
| { | |
| HKEY clsidkey; | |
| HKEY classkey; | |
| HKEY catidkey; | |
| HKEY instancekey; | |
| WCHAR guidstring[39]; | |
| LONG res; | |
| const struct category *category; | |
| int found=0; | |
| HRESULT hr; | |
| res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey); | |
| if (res != ERROR_SUCCESS) | |
| return HRESULT_FROM_WIN32(res); | |
| for (category=categories; category->type; category++) | |
| { | |
| StringFromGUID2(category->catid, guidstring, 39); | |
| res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey); | |
| if (res == ERROR_SUCCESS) | |
| { | |
| res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey); | |
| if (res == ERROR_SUCCESS) | |
| { | |
| StringFromGUID2(clsid, guidstring, 39); | |
| res = RegOpenKeyExW(instancekey, guidstring, 0, KEY_READ, &classkey); | |
| if (res == ERROR_SUCCESS) | |
| { | |
| RegCloseKey(classkey); | |
| found = 1; | |
| } | |
| RegCloseKey(instancekey); | |
| } | |
| RegCloseKey(catidkey); | |
| } | |
| if (found) break; | |
| } | |
| if (found) | |
| { | |
| res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &classkey); | |
| if (res == ERROR_SUCCESS) | |
| hr = category->constructor(classkey, clsid, ppIInfo); | |
| else | |
| hr = HRESULT_FROM_WIN32(res); | |
| } | |
| else | |
| hr = E_FAIL; | |
| RegCloseKey(clsidkey); | |
| return hr; | |
| } | |
| typedef struct { | |
| const IEnumUnknownVtbl *IEnumUnknown_Vtbl; | |
| LONG ref; | |
| struct list objects; | |
| struct list *cursor; | |
| } ComponentEnum; | |
| typedef struct { | |
| struct list entry; | |
| IUnknown *unk; | |
| } ComponentEnumItem; | |
| static const IEnumUnknownVtbl ComponentEnumVtbl; | |
| static HRESULT WINAPI ComponentEnum_QueryInterface(IEnumUnknown *iface, REFIID iid, | |
| void **ppv) | |
| { | |
| ComponentEnum *This = (ComponentEnum*)iface; | |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); | |
| if (!ppv) return E_INVALIDARG; | |
| if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IEnumUnknown, iid)) | |
| { | |
| *ppv = This; | |
| } | |
| else | |
| { | |
| *ppv = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI ComponentEnum_AddRef(IEnumUnknown *iface) | |
| { | |
| ComponentEnum *This = (ComponentEnum*)iface; | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) refcount=%u\n", iface, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI ComponentEnum_Release(IEnumUnknown *iface) | |
| { | |
| ComponentEnum *This = (ComponentEnum*)iface; | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| ComponentEnumItem *cursor, *cursor2; | |
| TRACE("(%p) refcount=%u\n", iface, ref); | |
| if (ref == 0) | |
| { | |
| LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->objects, ComponentEnumItem, entry) | |
| { | |
| IUnknown_Release(cursor->unk); | |
| list_remove(&cursor->entry); | |
| HeapFree(GetProcessHeap(), 0, cursor); | |
| } | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI ComponentEnum_Next(IEnumUnknown *iface, ULONG celt, | |
| IUnknown **rgelt, ULONG *pceltFetched) | |
| { | |
| ComponentEnum *This = (ComponentEnum*)iface; | |
| int num_fetched=0; | |
| ComponentEnumItem *item; | |
| TRACE("(%p,%u,%p,%p)\n", iface, celt, rgelt, pceltFetched); | |
| while (num_fetched<celt) | |
| { | |
| if (!This->cursor) | |
| { | |
| *pceltFetched = num_fetched; | |
| return S_FALSE; | |
| } | |
| item = LIST_ENTRY(This->cursor, ComponentEnumItem, entry); | |
| IUnknown_AddRef(item->unk); | |
| rgelt[num_fetched] = item->unk; | |
| num_fetched++; | |
| This->cursor = list_next(&This->objects, This->cursor); | |
| } | |
| *pceltFetched = num_fetched; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI ComponentEnum_Skip(IEnumUnknown *iface, ULONG celt) | |
| { | |
| ComponentEnum *This = (ComponentEnum*)iface; | |
| int i; | |
| TRACE("(%p,%u)\n", iface, celt); | |
| for (i=0; i<celt; i++) | |
| { | |
| if (!This->cursor) | |
| return S_FALSE; | |
| This->cursor = list_next(&This->objects, This->cursor); | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI ComponentEnum_Reset(IEnumUnknown *iface) | |
| { | |
| ComponentEnum *This = (ComponentEnum*)iface; | |
| TRACE("(%p)\n", iface); | |
| This->cursor = list_head(&This->objects); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum) | |
| { | |
| ComponentEnum *This = (ComponentEnum*)iface; | |
| ComponentEnum *new_enum; | |
| ComponentEnumItem *old_item, *new_item; | |
| HRESULT ret=S_OK; | |
| new_enum = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum)); | |
| if (!new_enum) | |
| { | |
| *ppenum = NULL; | |
| return E_OUTOFMEMORY; | |
| } | |
| new_enum->IEnumUnknown_Vtbl = &ComponentEnumVtbl; | |
| new_enum->ref = 1; | |
| new_enum->cursor = NULL; | |
| list_init(&new_enum->objects); | |
| LIST_FOR_EACH_ENTRY(old_item, &This->objects, ComponentEnumItem, entry) | |
| { | |
| new_item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem)); | |
| if (!new_item) | |
| { | |
| ret = E_OUTOFMEMORY; | |
| break; | |
| } | |
| new_item->unk = old_item->unk; | |
| list_add_tail(&new_enum->objects, &new_item->entry); | |
| IUnknown_AddRef(new_item->unk); | |
| if (&old_item->entry == This->cursor) new_enum->cursor = &new_item->entry; | |
| } | |
| if (FAILED(ret)) | |
| { | |
| IUnknown_Release((IUnknown*)new_enum); | |
| *ppenum = NULL; | |
| } | |
| else | |
| *ppenum = (IEnumUnknown*)new_enum; | |
| return ret; | |
| } | |
| static const IEnumUnknownVtbl ComponentEnumVtbl = { | |
| ComponentEnum_QueryInterface, | |
| ComponentEnum_AddRef, | |
| ComponentEnum_Release, | |
| ComponentEnum_Next, | |
| ComponentEnum_Skip, | |
| ComponentEnum_Reset, | |
| ComponentEnum_Clone | |
| }; | |
| HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown) | |
| { | |
| ComponentEnum *This; | |
| ComponentEnumItem *item; | |
| const struct category *category; | |
| HKEY clsidkey, catidkey, instancekey; | |
| WCHAR guidstring[39]; | |
| LONG res; | |
| int i; | |
| HRESULT hr=S_OK; | |
| CLSID clsid; | |
| if (options) FIXME("ignoring flags %x\n", options); | |
| res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey); | |
| if (res != ERROR_SUCCESS) | |
| return HRESULT_FROM_WIN32(res); | |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum)); | |
| if (!This) | |
| { | |
| RegCloseKey(clsidkey); | |
| return E_OUTOFMEMORY; | |
| } | |
| This->IEnumUnknown_Vtbl = &ComponentEnumVtbl; | |
| This->ref = 1; | |
| list_init(&This->objects); | |
| for (category=categories; category->type && hr == S_OK; category++) | |
| { | |
| if ((category->type & componentTypes) == 0) continue; | |
| StringFromGUID2(category->catid, guidstring, 39); | |
| res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey); | |
| if (res == ERROR_SUCCESS) | |
| { | |
| res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey); | |
| if (res == ERROR_SUCCESS) | |
| { | |
| i=0; | |
| for (;;i++) | |
| { | |
| DWORD guidstring_size = 39; | |
| res = RegEnumKeyExW(instancekey, i, guidstring, &guidstring_size, NULL, NULL, NULL, NULL); | |
| if (res != ERROR_SUCCESS) break; | |
| item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem)); | |
| if (!item) { hr = E_OUTOFMEMORY; break; } | |
| hr = CLSIDFromString(guidstring, &clsid); | |
| if (SUCCEEDED(hr)) | |
| { | |
| hr = CreateComponentInfo(&clsid, (IWICComponentInfo**)&item->unk); | |
| if (SUCCEEDED(hr)) | |
| list_add_tail(&This->objects, &item->entry); | |
| } | |
| if (FAILED(hr)) | |
| { | |
| HeapFree(GetProcessHeap(), 0, item); | |
| hr = S_OK; | |
| } | |
| } | |
| RegCloseKey(instancekey); | |
| } | |
| RegCloseKey(catidkey); | |
| } | |
| if (res != ERROR_SUCCESS && res != ERROR_NO_MORE_ITEMS) | |
| hr = HRESULT_FROM_WIN32(res); | |
| } | |
| RegCloseKey(clsidkey); | |
| if (SUCCEEDED(hr)) | |
| { | |
| IEnumUnknown_Reset((IEnumUnknown*)This); | |
| *ppIEnumUnknown = (IEnumUnknown*)This; | |
| } | |
| else | |
| { | |
| *ppIEnumUnknown = NULL; | |
| IUnknown_Release((IUnknown*)This); | |
| } | |
| return hr; | |
| } | |
| HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst) | |
| { | |
| HRESULT res; | |
| IEnumUnknown *enumconverters; | |
| IUnknown *unkconverterinfo; | |
| IWICFormatConverterInfo *converterinfo=NULL; | |
| IWICFormatConverter *converter=NULL; | |
| GUID srcFormat; | |
| WCHAR srcformatstr[39], dstformatstr[39]; | |
| BOOL canconvert; | |
| ULONG num_fetched; | |
| res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat); | |
| if (FAILED(res)) return res; | |
| if (IsEqualGUID(&srcFormat, dstFormat)) | |
| { | |
| IWICBitmapSource_AddRef(pISrc); | |
| *ppIDst = pISrc; | |
| return S_OK; | |
| } | |
| StringFromGUID2(&srcFormat, srcformatstr, 39); | |
| StringFromGUID2(dstFormat, dstformatstr, 39); | |
| res = CreateComponentEnumerator(WICPixelFormatConverter, 0, &enumconverters); | |
| if (FAILED(res)) return res; | |
| while (!converter) | |
| { | |
| res = IEnumUnknown_Next(enumconverters, 1, &unkconverterinfo, &num_fetched); | |
| if (res == S_OK) | |
| { | |
| res = IUnknown_QueryInterface(unkconverterinfo, &IID_IWICFormatConverterInfo, (void**)&converterinfo); | |
| if (SUCCEEDED(res)) | |
| { | |
| canconvert = ConverterSupportsFormat(converterinfo, srcformatstr); | |
| if (canconvert) | |
| canconvert = ConverterSupportsFormat(converterinfo, dstformatstr); | |
| if (canconvert) | |
| { | |
| res = IWICFormatConverterInfo_CreateInstance(converterinfo, &converter); | |
| if (SUCCEEDED(res)) | |
| res = IWICFormatConverter_CanConvert(converter, &srcFormat, dstFormat, &canconvert); | |
| if (SUCCEEDED(res) && canconvert) | |
| res = IWICFormatConverter_Initialize(converter, pISrc, dstFormat, WICBitmapDitherTypeNone, | |
| NULL, 0.0, WICBitmapPaletteTypeCustom); | |
| if (FAILED(res) || !canconvert) | |
| { | |
| if (converter) | |
| { | |
| IWICFormatConverter_Release(converter); | |
| converter = NULL; | |
| } | |
| res = S_OK; | |
| } | |
| } | |
| IWICFormatConverterInfo_Release(converterinfo); | |
| } | |
| IUnknown_Release(unkconverterinfo); | |
| } | |
| else | |
| break; | |
| } | |
| IEnumUnknown_Release(enumconverters); | |
| if (converter) | |
| { | |
| *ppIDst = (IWICBitmapSource*)converter; | |
| return S_OK; | |
| } | |
| else | |
| { | |
| FIXME("cannot convert %s to %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat)); | |
| *ppIDst = NULL; | |
| return WINCODEC_ERR_COMPONENTNOTFOUND; | |
| } | |
| } |