Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/windowscodecs/bitmap.c | 27 ++++++++----- dlls/windowscodecs/imgfactory.c | 73 ++++++++++++++++++++++++++++++++++- dlls/windowscodecs/windowscodecs.spec | 3 +- include/wincodec.idl | 8 ++++ 4 files changed, 100 insertions(+), 11 deletions(-)
diff --git a/dlls/windowscodecs/bitmap.c b/dlls/windowscodecs/bitmap.c index 6adaab0aea..76298b22ca 100644 --- a/dlls/windowscodecs/bitmap.c +++ b/dlls/windowscodecs/bitmap.c @@ -45,6 +45,7 @@ typedef struct BitmapImpl { int palette_set; LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */ BYTE *data; + BOOL is_section; /* TRUE if data is a section created by an application */ UINT width, height; UINT stride; UINT bpp; @@ -284,7 +285,10 @@ static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface) if (This->palette) IWICPalette_Release(This->palette); This->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->cs); - HeapFree(GetProcessHeap(), 0, This->data); + if (This->is_section) + UnmapViewOfFile(This->data); + else + HeapFree(GetProcessHeap(), 0, This->data); HeapFree(GetProcessHeap(), 0, This); }
@@ -694,13 +698,12 @@ static const IMILUnknown2Vtbl IMILUnknown2Impl_Vtbl = };
HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, - UINT stride, UINT datasize, BYTE *bits, + UINT stride, UINT datasize, BYTE *data, REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option, IWICBitmap **ppIBitmap) { HRESULT hr; BitmapImpl *This; - BYTE *data; UINT bpp;
hr = get_pixelformat_bpp(pixelFormat, &bpp); @@ -713,14 +716,20 @@ HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, if (stride < ((bpp*uiWidth)+7)/8) return E_INVALIDARG;
This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl)); - data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize); - if (!This || !data) + if (!This) return E_OUTOFMEMORY; + + if (!data) { - HeapFree(GetProcessHeap(), 0, This); - HeapFree(GetProcessHeap(), 0, data); - return E_OUTOFMEMORY; + data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize); + if (!data) + { + HeapFree(GetProcessHeap(), 0, This); + return E_OUTOFMEMORY; + } + This->is_section = FALSE; } - if (bits) memcpy(data, bits, datasize); + else + This->is_section = TRUE;
This->IWICBitmap_iface.lpVtbl = &BitmapImpl_Vtbl; This->IMILBitmapSource_iface.lpVtbl = &IMILBitmapImpl_Vtbl; diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c index e1bcc89a8b..4ed01f5b26 100644 --- a/dlls/windowscodecs/imgfactory.c +++ b/dlls/windowscodecs/imgfactory.c @@ -595,12 +595,36 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromMemory(IWICComponentFacto UINT width, UINT height, REFWICPixelFormatGUID format, UINT stride, UINT size, BYTE *buffer, IWICBitmap **bitmap) { + HRESULT hr; + TRACE("(%p,%u,%u,%s,%u,%u,%p,%p\n", iface, width, height, debugstr_guid(format), stride, size, buffer, bitmap);
if (!stride || !size || !buffer || !bitmap) return E_INVALIDARG;
- return BitmapImpl_Create(width, height, stride, size, buffer, format, WICBitmapCacheOnLoad, bitmap); + hr = BitmapImpl_Create(width, height, stride, size, NULL, format, WICBitmapCacheOnLoad, bitmap); + if (SUCCEEDED(hr)) + { + IWICBitmapLock *lock; + + hr = IWICBitmap_Lock(*bitmap, NULL, WICBitmapLockWrite, &lock); + if (SUCCEEDED(hr)) + { + UINT buffersize; + BYTE *data; + + IWICBitmapLock_GetDataPointer(lock, &buffersize, &data); + memcpy(data, buffer, buffersize); + + IWICBitmapLock_Release(lock); + } + else + { + IWICBitmap_Release(*bitmap); + *bitmap = NULL; + } + } + return hr; }
static BOOL get_16bpp_format(HBITMAP hbm, WICPixelFormatGUID *format) @@ -1176,3 +1200,50 @@ HRESULT ComponentFactory_CreateInstance(REFIID iid, void** ppv)
return ret; } + +HRESULT WINAPI WICCreateBitmapFromSectionEx(UINT width, UINT height, + REFWICPixelFormatGUID format, HANDLE section, UINT stride, + UINT offset, WICSectionAccessLevel wicaccess, IWICBitmap **bitmap) +{ + DWORD access; + void *buffer; + HRESULT hr; + + TRACE("%u,%u,%s,%p,%u,%#x,%#x,%p\n", width, height, debugstr_guid(format), + section, stride, offset, wicaccess, bitmap); + + if (!width || !height || !section || !bitmap) return E_INVALIDARG; + + switch (wicaccess) + { + case WICSectionAccessLevelReadWrite: + access = FILE_MAP_READ | FILE_MAP_WRITE; + break; + + case WICSectionAccessLevelRead: + access = FILE_MAP_READ; + break; + + default: + FIXME("unsupported access %#x\n", wicaccess); + return E_INVALIDARG; + } + + buffer = MapViewOfFile(section, access, 0, offset, 0); + if (!buffer) return HRESULT_FROM_WIN32(GetLastError()); + + hr = BitmapImpl_Create(width, height, stride, 0, buffer, format, WICBitmapCacheOnLoad, bitmap); + if (FAILED(hr)) UnmapViewOfFile(buffer); + return hr; +} + +HRESULT WINAPI WICCreateBitmapFromSection(UINT width, UINT height, + REFWICPixelFormatGUID format, HANDLE section, + UINT stride, UINT offset, IWICBitmap **bitmap) +{ + TRACE("%u,%u,%s,%p,%u,%u,%p\n", width, height, debugstr_guid(format), + section, stride, offset, bitmap); + + return WICCreateBitmapFromSectionEx(width, height, format, section, + stride, offset, WICSectionAccessLevelRead, bitmap); +} diff --git a/dlls/windowscodecs/windowscodecs.spec b/dlls/windowscodecs/windowscodecs.spec index 49346fc86b..905ef835af 100644 --- a/dlls/windowscodecs/windowscodecs.spec +++ b/dlls/windowscodecs/windowscodecs.spec @@ -105,7 +105,8 @@ @ stdcall IWICStream_InitializeFromIStream_Proxy(ptr ptr) IWICStream_InitializeFromIStream_Proxy_W @ stdcall IWICStream_InitializeFromMemory_Proxy(ptr ptr long) IWICStream_InitializeFromMemory_Proxy_W @ stdcall WICConvertBitmapSource(ptr ptr ptr) -@ stub WICCreateBitmapFromSection +@ stdcall WICCreateBitmapFromSection(long long ptr long long long ptr) +@ stdcall WICCreateBitmapFromSectionEx(long long ptr long long long long ptr) @ stdcall WICCreateColorContext_Proxy(ptr ptr) @ stdcall WICCreateImagingFactory_Proxy(long ptr) @ stub WICGetMetadataContentSize diff --git a/include/wincodec.idl b/include/wincodec.idl index f2c5a9e626..50d7db7620 100644 --- a/include/wincodec.idl +++ b/include/wincodec.idl @@ -189,6 +189,12 @@ typedef enum WICPngFilterOption { WICPNFFILTEROPTION_FORCE_DWORD = CODEC_FORCE_DWORD } WICPngFilterOption;
+typedef enum WICSectionAccessLevel { + WICSectionAccessLevelRead = 0x00000001, + WICSectionAccessLevelReadWrite = 0x00000003, + WICSectionAccessLevel_FORCE_DWORD = CODEC_FORCE_DWORD +} WICSectionAccessLevel; + typedef GUID WICPixelFormatGUID; typedef REFGUID REFWICPixelFormatGUID;
@@ -1058,6 +1064,8 @@ interface IWICEnumMetadataItem : IUnknown }
cpp_quote("HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst);") +cpp_quote("HRESULT WINAPI WICCreateBitmapFromSection(UINT width, UINT height, REFWICPixelFormatGUID format, HANDLE section, UINT stride, UINT offset, IWICBitmap **bitmap);") +cpp_quote("HRESULT WINAPI WICCreateBitmapFromSectionEx(UINT width, UINT height, REFWICPixelFormatGUID format, HANDLE section, UINT stride, UINT offset, WICSectionAccessLevel access, IWICBitmap **bitmap);")
cpp_quote("HRESULT WINAPI WICMapGuidToShortName(REFGUID,UINT,WCHAR *,UINT *);") cpp_quote("HRESULT WINAPI WICMapShortNameToGuid(PCWSTR,GUID *);")
On Thu, 2018-03-15 at 20:31 +0800, Dmitry Timoshkov wrote:
+HRESULT WINAPI WICCreateBitmapFromSectionEx(UINT width, UINT height,
REFWICPixelFormatGUID format, HANDLE section, UINT stride,
UINT offset, WICSectionAccessLevel wicaccess, IWICBitmap **bitmap)
+{
- DWORD access;
- void *buffer;
- HRESULT hr;
- TRACE("%u,%u,%s,%p,%u,%#x,%#x,%p\n", width, height, debugstr_guid(format),
section, stride, offset, wicaccess, bitmap);
- if (!width || !height || !section || !bitmap) return E_INVALIDARG;
- switch (wicaccess)
- {
- case WICSectionAccessLevelReadWrite:
access = FILE_MAP_READ | FILE_MAP_WRITE;
break;
- case WICSectionAccessLevelRead:
access = FILE_MAP_READ;
break;
- default:
FIXME("unsupported access %#x\n", wicaccess);
return E_INVALIDARG;
- }
- buffer = MapViewOfFile(section, access, 0, offset, 0);
- if (!buffer) return HRESULT_FROM_WIN32(GetLastError());
MapViewOfFile wants a multiple of the allocation granularity for the offset. Does WICCreateBitmapFromSectionEx have the same constraint?
Hans Leidekker hans@codeweavers.com wrote:
- buffer = MapViewOfFile(section, access, 0, offset, 0);
- if (!buffer) return HRESULT_FROM_WIN32(GetLastError());
MapViewOfFile wants a multiple of the allocation granularity for the offset. Does WICCreateBitmapFromSectionEx have the same constraint?
I would be very much surprised if it doesn't, a passed in section handle implies using MapViewOfFile to access the bitmap bits.
On Thu, 2018-03-15 at 22:40 +0800, Dmitry Timoshkov wrote:
Hans Leidekker hans@codeweavers.com wrote:
- buffer = MapViewOfFile(section, access, 0, offset, 0);
- if (!buffer) return HRESULT_FROM_WIN32(GetLastError());
MapViewOfFile wants a multiple of the allocation granularity for the offset. Does WICCreateBitmapFromSectionEx have the same constraint?
I would be very much surprised if it doesn't, a passed in section handle implies using MapViewOfFile to access the bitmap bits.
It could also map at the base and store the offset.
Hans Leidekker hans@codeweavers.com wrote:
On Thu, 2018-03-15 at 22:40 +0800, Dmitry Timoshkov wrote:
Hans Leidekker hans@codeweavers.com wrote:
- buffer = MapViewOfFile(section, access, 0, offset, 0);
- if (!buffer) return HRESULT_FROM_WIN32(GetLastError());
MapViewOfFile wants a multiple of the allocation granularity for the offset. Does WICCreateBitmapFromSectionEx have the same constraint?
I would be very much surprised if it doesn't, a passed in section handle implies using MapViewOfFile to access the bitmap bits.
It could also map at the base and store the offset.
At the moment I'm not well enough prepared to write a test case, but feel free to write one. I'd still assume based on syntax similarity of MapViewOfFile and WICCreateBitmapFromSection that the latter is modelled around the former one.
On Thu, 2018-03-15 at 23:00 +0800, Dmitry Timoshkov wrote:
Hans Leidekker hans@codeweavers.com wrote:
On Thu, 2018-03-15 at 22:40 +0800, Dmitry Timoshkov wrote:
Hans Leidekker hans@codeweavers.com wrote:
- buffer = MapViewOfFile(section, access, 0, offset, 0);
- if (!buffer) return HRESULT_FROM_WIN32(GetLastError());
MapViewOfFile wants a multiple of the allocation granularity for the offset. Does WICCreateBitmapFromSectionEx have the same constraint?
I would be very much surprised if it doesn't, a passed in section handle implies using MapViewOfFile to access the bitmap bits.
It could also map at the base and store the offset.
At the moment I'm not well enough prepared to write a test case, but feel free to write one. I'd still assume based on syntax similarity of MapViewOfFile and WICCreateBitmapFromSection that the latter is modelled around the former one.
How about this? I'm including a modified version of your implementation that passes the test.
Hans Leidekker hans@codeweavers.com writes:
On Thu, 2018-03-15 at 23:00 +0800, Dmitry Timoshkov wrote:
Hans Leidekker hans@codeweavers.com wrote:
On Thu, 2018-03-15 at 22:40 +0800, Dmitry Timoshkov wrote:
Hans Leidekker hans@codeweavers.com wrote:
- buffer = MapViewOfFile(section, access, 0, offset, 0);
- if (!buffer) return HRESULT_FROM_WIN32(GetLastError());
MapViewOfFile wants a multiple of the allocation granularity for the offset. Does WICCreateBitmapFromSectionEx have the same constraint?
I would be very much surprised if it doesn't, a passed in section handle implies using MapViewOfFile to access the bitmap bits.
It could also map at the base and store the offset.
At the moment I'm not well enough prepared to write a test case, but feel free to write one. I'd still assume based on syntax similarity of MapViewOfFile and WICCreateBitmapFromSection that the latter is modelled around the former one.
How about this? I'm including a modified version of your implementation that passes the test.
I'd suggest doing it the same way CreateDIBSection does, to avoid mapping the entire file.
Hans Leidekker hans@codeweavers.com wrote:
- buffer = MapViewOfFile(section, access, 0, offset, 0);
- if (!buffer) return HRESULT_FROM_WIN32(GetLastError());
MapViewOfFile wants a multiple of the allocation granularity for the offset. Does WICCreateBitmapFromSectionEx have the same constraint?
I would be very much surprised if it doesn't, a passed in section handle implies using MapViewOfFile to access the bitmap bits.
It could also map at the base and store the offset.
At the moment I'm not well enough prepared to write a test case, but feel free to write one. I'd still assume based on syntax similarity of MapViewOfFile and WICCreateBitmapFromSection that the latter is modelled around the former one.
How about this? I'm including a modified version of your implementation that passes the test.
Thanks for creating a test, the patch looks good to me, feel free to send it for inclusion.