This patch makes the GOG downloader work.
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/windowscodecs/scaler.c | 169 +++++++++++++++++++++++++ dlls/windowscodecs/wincodecs_private.h | 19 +++ 2 files changed, 188 insertions(+)
diff --git a/dlls/windowscodecs/scaler.c b/dlls/windowscodecs/scaler.c index eedc1bbac4..d19e219fea 100644 --- a/dlls/windowscodecs/scaler.c +++ b/dlls/windowscodecs/scaler.c @@ -35,6 +35,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); typedef struct BitmapScaler { IWICBitmapScaler IWICBitmapScaler_iface; LONG ref; + IMILBitmapScaler IMILBitmapScaler_iface; IWICBitmapSource *source; UINT width, height; UINT src_width, src_height; @@ -50,6 +51,11 @@ static inline BitmapScaler *impl_from_IWICBitmapScaler(IWICBitmapScaler *iface) return CONTAINING_RECORD(iface, BitmapScaler, IWICBitmapScaler_iface); }
+static inline BitmapScaler *impl_from_IMILBitmapScaler(IMILBitmapScaler *iface) +{ + return CONTAINING_RECORD(iface, BitmapScaler, IMILBitmapScaler_iface); +} + static HRESULT WINAPI BitmapScaler_QueryInterface(IWICBitmapScaler *iface, REFIID iid, void **ppv) { @@ -64,8 +70,13 @@ static HRESULT WINAPI BitmapScaler_QueryInterface(IWICBitmapScaler *iface, REFII { *ppv = &This->IWICBitmapScaler_iface; } + else if (IsEqualIID(&IID_IMILBitmapScaler, iid)) + { + *ppv = &This->IMILBitmapScaler_iface; + } else { + FIXME("unknown interface %s\n", debugstr_guid(iid)); *ppv = NULL; return E_NOINTERFACE; } @@ -380,6 +391,163 @@ static const IWICBitmapScalerVtbl BitmapScaler_Vtbl = { BitmapScaler_Initialize };
+static HRESULT WINAPI IMILBitmapScaler_QueryInterface(IMILBitmapScaler *iface, REFIID iid, + void **ppv) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IMILBitmapScaler, iid) || + IsEqualIID(&IID_IMILBitmapSource, iid)) + { + IUnknown_AddRef(&This->IMILBitmapScaler_iface); + *ppv = &This->IMILBitmapScaler_iface; + return S_OK; + } + else if (IsEqualIID(&IID_IWICBitmapScaler, iid) || + IsEqualIID(&IID_IWICBitmapSource, iid)) + { + IUnknown_AddRef(&This->IWICBitmapScaler_iface); + *ppv = &This->IWICBitmapScaler_iface; + return S_OK; + } + + FIXME("unknown interface %s\n", debugstr_guid(iid)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IMILBitmapScaler_AddRef(IMILBitmapScaler *iface) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + return IWICBitmapScaler_AddRef(&This->IWICBitmapScaler_iface); +} + +static ULONG WINAPI IMILBitmapScaler_Release(IMILBitmapScaler *iface) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + return IWICBitmapScaler_Release(&This->IWICBitmapScaler_iface); +} + +static HRESULT WINAPI IMILBitmapScaler_GetSize(IMILBitmapScaler *iface, + UINT *width, UINT *height) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%p,%p)\n", iface, width, height); + + if (!This->source) + return WINCODEC_ERR_NOTINITIALIZED; + + return IWICBitmapScaler_GetSize(&This->IWICBitmapScaler_iface, width, height); +} + +static HRESULT WINAPI IMILBitmapScaler_GetPixelFormat(IMILBitmapScaler *iface, + int *format) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + IMILBitmapSource *source; + HRESULT hr; + + TRACE("(%p,%p)\n", iface, format); + + if (!format) return E_INVALIDARG; + + if (!This->source) + return WINCODEC_ERR_NOTINITIALIZED; + + hr = IWICBitmapSource_QueryInterface(This->source, &IID_IMILBitmapSource, (void **)&source); + if (hr == S_OK) + { + hr = source->lpVtbl->GetPixelFormat(source, format); + source->lpVtbl->Release(source); + } + return hr; +} + +static HRESULT WINAPI IMILBitmapScaler_GetResolution(IMILBitmapScaler *iface, + double *dpix, double *dpiy) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%p,%p)\n", iface, dpix, dpiy); + + if (!This->source) + return WINCODEC_ERR_NOTINITIALIZED; + + return IWICBitmapScaler_GetResolution(&This->IWICBitmapScaler_iface, dpix, dpiy); +} + +static HRESULT WINAPI IMILBitmapScaler_CopyPalette(IMILBitmapScaler *iface, + IWICPalette *palette) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%p)\n", iface, palette); + + if (!This->source) + return WINCODEC_ERR_NOTINITIALIZED; + + return IWICBitmapScaler_CopyPalette(&This->IWICBitmapScaler_iface, palette); +} + +static HRESULT WINAPI IMILBitmapScaler_CopyPixels(IMILBitmapScaler *iface, + const WICRect *rc, UINT stride, UINT size, BYTE *buffer) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%p,%u,%u,%p)\n", iface, rc, stride, size, buffer); + + if (!This->source) + return WINCODEC_ERR_NOTINITIALIZED; + + return IWICBitmapScaler_CopyPixels(&This->IWICBitmapScaler_iface, rc, stride, size, buffer); +} + +static HRESULT WINAPI IMILBitmapScaler_unknown1(IMILBitmapScaler *iface, void **ppv) +{ + TRACE("(%p,%p)\n", iface, ppv); + return E_NOINTERFACE; +} + +static HRESULT WINAPI IMILBitmapScaler_Initialize(IMILBitmapScaler *iface, + IMILBitmapSource *mil_source, UINT width, UINT height, + WICBitmapInterpolationMode mode) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + IWICBitmapSource *wic_source; + HRESULT hr; + + TRACE("(%p,%p,%u,%u,%u)\n", iface, mil_source, width, height, mode); + + if (!mil_source) return E_INVALIDARG; + + hr = mil_source->lpVtbl->QueryInterface(mil_source, &IID_IWICBitmapSource, (void **)&wic_source); + if (hr == S_OK) + { + hr = IWICBitmapScaler_Initialize(&This->IWICBitmapScaler_iface, wic_source, width, height, mode); + IWICBitmapSource_Release(wic_source); + } + return hr; +} + +static const IMILBitmapScalerVtbl IMILBitmapScaler_Vtbl = { + IMILBitmapScaler_QueryInterface, + IMILBitmapScaler_AddRef, + IMILBitmapScaler_Release, + IMILBitmapScaler_GetSize, + IMILBitmapScaler_GetPixelFormat, + IMILBitmapScaler_GetResolution, + IMILBitmapScaler_CopyPalette, + IMILBitmapScaler_CopyPixels, + IMILBitmapScaler_unknown1, + IMILBitmapScaler_Initialize +}; + HRESULT BitmapScaler_Create(IWICBitmapScaler **scaler) { BitmapScaler *This; @@ -388,6 +556,7 @@ HRESULT BitmapScaler_Create(IWICBitmapScaler **scaler) if (!This) return E_OUTOFMEMORY;
This->IWICBitmapScaler_iface.lpVtbl = &BitmapScaler_Vtbl; + This->IMILBitmapScaler_iface.lpVtbl = &IMILBitmapScaler_Vtbl; This->ref = 1; This->source = NULL; This->width = 0; diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index 34a417d130..10d54ef700 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -63,6 +63,25 @@ DECLARE_INTERFACE_(IMILBitmapSource,IUnknown) }; #undef INTERFACE
+#define INTERFACE IMILBitmapScaler +DECLARE_INTERFACE_(IMILBitmapScaler,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID,void **) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IWICBitmapSource methods ***/ + STDMETHOD_(HRESULT,GetSize)(THIS_ UINT *,UINT *) PURE; + STDMETHOD_(HRESULT,GetPixelFormat)(THIS_ int *) PURE; + STDMETHOD_(HRESULT,GetResolution)(THIS_ double *,double *) PURE; + STDMETHOD_(HRESULT,CopyPalette)(THIS_ IWICPalette *) PURE; + STDMETHOD_(HRESULT,CopyPixels)(THIS_ const WICRect *,UINT,UINT,BYTE *) PURE; + /*** IMILBitmapScaler methods ***/ + STDMETHOD_(HRESULT,unknown1)(THIS_ void **) PURE; + STDMETHOD_(HRESULT,Initialize)(THIS_ IMILBitmapSource *,UINT,UINT,WICBitmapInterpolationMode); +}; +#undef INTERFACE + #ifdef __i386__ /* thiscall functions are i386-specific */
#define THISCALL(func) __thiscall_ ## func
+static HRESULT WINAPI IMILBitmapScaler_QueryInterface(IMILBitmapScaler *iface, REFIID iid, + void **ppv) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IMILBitmapScaler, iid) || + IsEqualIID(&IID_IMILBitmapSource, iid)) + { + IUnknown_AddRef(&This->IMILBitmapScaler_iface);
This violates COM rules by returning a different IUnknown pointer depending on the interface queried. Does native do that?
"Vincent Povirk (they/them)" vincent@codeweavers.com wrote:
+static HRESULT WINAPI IMILBitmapScaler_QueryInterface(IMILBitmapScaler *iface, REFIID iid,
- void **ppv)
+{
- BitmapScaler *This = impl_from_IMILBitmapScaler(iface);
- TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
- if (!ppv) return E_INVALIDARG;
- if (IsEqualIID(&IID_IUnknown, iid) ||
IsEqualIID(&IID_IMILBitmapScaler, iid) ||
IsEqualIID(&IID_IMILBitmapSource, iid))
- {
IUnknown_AddRef(&This->IMILBitmapScaler_iface);
This violates COM rules by returning a different IUnknown pointer depending on the interface queried. Does native do that?
According to the test app that I have here that's how it behaves.
"Vincent Povirk (they/them)" vincent@codeweavers.com wrote:
+static HRESULT WINAPI IMILBitmapScaler_QueryInterface(IMILBitmapScaler *iface, REFIID iid,
- void **ppv)
+{
- BitmapScaler *This = impl_from_IMILBitmapScaler(iface);
- TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
- if (!ppv) return E_INVALIDARG;
- if (IsEqualIID(&IID_IUnknown, iid) ||
IsEqualIID(&IID_IMILBitmapScaler, iid) ||
IsEqualIID(&IID_IMILBitmapSource, iid))
- {
IUnknown_AddRef(&This->IMILBitmapScaler_iface);
This violates COM rules by returning a different IUnknown pointer depending on the interface queried. Does native do that?
I've added more tests for IMILBitmapScaler_QueryInterface() behaviour, and under Windows for IID_IUnknown it returns some strange interface pointer that doesn't match other public interfaces. Then I added the same test for IWICBitmap_QueryInterface() and it also returns some strange interface for IID_IUnknown. So both QI implementations in Wine have similar problems when queried for IID_IUnknown. Or do you mean some other COM rule violation in the comment above?
The rule, as I understand it, is that all interfaces should return the same pointer when queried for IUnknown. It doesn't have to be discoverable by any other IID.
I'm not sure if that applies to interfaces generally or just IUnknown. Mono's COM code (and probably .NET's as well) relies on it for IUnknown.
On Tue, May 14, 2019 at 5:01 AM Dmitry Timoshkov dmitry@baikal.ru wrote:
"Vincent Povirk (they/them)" vincent@codeweavers.com wrote:
+static HRESULT WINAPI IMILBitmapScaler_QueryInterface(IMILBitmapScaler *iface, REFIID iid,
- void **ppv)
+{
- BitmapScaler *This = impl_from_IMILBitmapScaler(iface);
- TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
- if (!ppv) return E_INVALIDARG;
- if (IsEqualIID(&IID_IUnknown, iid) ||
IsEqualIID(&IID_IMILBitmapScaler, iid) ||
IsEqualIID(&IID_IMILBitmapSource, iid))
- {
IUnknown_AddRef(&This->IMILBitmapScaler_iface);
This violates COM rules by returning a different IUnknown pointer depending on the interface queried. Does native do that?
I've added more tests for IMILBitmapScaler_QueryInterface() behaviour, and under Windows for IID_IUnknown it returns some strange interface pointer that doesn't match other public interfaces. Then I added the same test for IWICBitmap_QueryInterface() and it also returns some strange interface for IID_IUnknown. So both QI implementations in Wine have similar problems when queried for IID_IUnknown. Or do you mean some other COM rule violation in the comment above?
-- Dmitry.
"Vincent Povirk (they/them)" vincent@codeweavers.com wrote:
The rule, as I understand it, is that all interfaces should return the same pointer when queried for IUnknown. It doesn't have to be discoverable by any other IID.
I'm not sure if that applies to interfaces generally or just IUnknown. Mono's COM code (and probably .NET's as well) relies on it for IUnknown.
The code for IMILBitmapScaler_QueryInterface() follows exisiting code for instance of IWICBitmap_QueryInterface(), do I miss something?
It looks to me like BitmapScaler_QueryInterface for IUnknown will return &IWICBitmapScaler_iface, and IMILBitmapScaler_QueryInterface for IUnknown will return &IMILBitmapScaler_iface.
On Tue, May 14, 2019 at 7:48 AM Dmitry Timoshkov dmitry@baikal.ru wrote:
"Vincent Povirk (they/them)" vincent@codeweavers.com wrote:
The rule, as I understand it, is that all interfaces should return the same pointer when queried for IUnknown. It doesn't have to be discoverable by any other IID.
I'm not sure if that applies to interfaces generally or just IUnknown. Mono's COM code (and probably .NET's as well) relies on it for IUnknown.
The code for IMILBitmapScaler_QueryInterface() follows exisiting code for instance of IWICBitmap_QueryInterface(), do I miss something?
-- Dmitry.
"Vincent Povirk (they/them)" vincent@codeweavers.com wrote:
On Tue, May 14, 2019 at 7:48 AM Dmitry Timoshkov dmitry@baikal.ru wrote:
"Vincent Povirk (they/them)" vincent@codeweavers.com wrote:
The rule, as I understand it, is that all interfaces should return the same pointer when queried for IUnknown. It doesn't have to be discoverable by any other IID.
I'm not sure if that applies to interfaces generally or just IUnknown. Mono's COM code (and probably .NET's as well) relies on it for IUnknown.
The code for IMILBitmapScaler_QueryInterface() follows exisiting code for instance of IWICBitmap_QueryInterface(), do I miss something?
It looks to me like BitmapScaler_QueryInterface for IUnknown will return &IWICBitmapScaler_iface, and IMILBitmapScaler_QueryInterface for IUnknown will return &IMILBitmapScaler_iface.
Do you mean that they are supposed to return the same interface?
Yes. This is commonly used to test whether two interface pointers belong to the same object: query them for IUnknown and see if you get the same result.
"Vincent Povirk (they/them)" vincent@codeweavers.com wrote:
Yes. This is commonly used to test whether two interface pointers belong to the same object: query them for IUnknown and see if you get the same result.
I see, thanks for the explanation. Under Windows IWICBitmapScaler_QueryInterface and IMILBitmapScaler_QueryInterface return the same interface for IID_IUnknown, but that interface is neither IWICBitmapScaler nor IMILBitmapScaler. Same thing I observe with IWICBitmap and IMILBitmap. Probably the interface returned is some base class that forwards its methods to one of IWIC or IMIL classes.
I guess that changing IMILBitmapScaler_QueryInterface to return the same interface as IWICBitmapScaler_QueryInterface does is the right thing to do.