Module: wine Branch: master Commit: 7854cce7575735cd06d0ef340015ef95831d47f2 URL: http://source.winehq.org/git/wine.git/?a=commit;h=7854cce7575735cd06d0ef3400...
Author: Michael Stefaniuc mstefani@redhat.de Date: Thu Mar 7 00:45:08 2013 +0100
avifil32: Support COM aggregation for AVIFile.
Ref counting bug in QueryInterface comes free of charge!
---
dlls/avifil32/avifile.c | 118 ++++++++++++++++++++++++++------------- dlls/avifil32/avifile_private.h | 2 +- dlls/avifil32/factory.c | 13 +++- 3 files changed, 91 insertions(+), 42 deletions(-)
diff --git a/dlls/avifil32/avifile.c b/dlls/avifil32/avifile.c index 408808c..ab60c3a 100644 --- a/dlls/avifil32/avifile.c +++ b/dlls/avifil32/avifile.c @@ -30,6 +30,7 @@ * When index is missing it works, but index seems to be okay. */
+#define COBJMACROS #include <assert.h> #include <stdarg.h>
@@ -118,8 +119,10 @@ typedef struct _IAVIStreamImpl { } IAVIStreamImpl;
struct _IAVIFileImpl { + IUnknown IUnknown_inner; IAVIFile IAVIFile_iface; IPersistFile IPersistFile_iface; + IUnknown *outer_unk; LONG ref;
AVIFILEINFOW fInfo; @@ -144,6 +147,11 @@ struct _IAVIFileImpl { BOOL fDirty; };
+static inline IAVIFileImpl *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, IAVIFileImpl, IUnknown_inner); +} + static inline IAVIFileImpl *impl_from_IAVIFile(IAVIFile *iface) { return CONTAINING_RECORD(iface, IAVIFileImpl, IAVIFile_iface); @@ -180,32 +188,37 @@ static HRESULT AVIFILE_WriteBlock(IAVIStreamImpl *This, DWORD block, FOURCC ckid, DWORD flags, LPCVOID buffer, LONG size);
-static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile *iface, REFIID refiid, - LPVOID *obj) +static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown *iface, REFIID riid, void **ppv) { - IAVIFileImpl *This = impl_from_IAVIFile(iface); - - TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj); + IAVIFileImpl *This = impl_from_IUnknown(iface);
- if (IsEqualGUID(&IID_IUnknown, refiid) || - IsEqualGUID(&IID_IAVIFile, refiid)) { - *obj = iface; - IAVIFile_AddRef(iface); + TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
- return S_OK; - } else if (IsEqualGUID(&IID_IPersistFile, refiid)) { - *obj = &This->IPersistFile_iface; - IAVIFile_AddRef(iface); + if (!ppv) { + WARN("invalid parameter\n"); + return E_INVALIDARG; + } + *ppv = NULL;
- return S_OK; + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = &This->IUnknown_inner; + else if (IsEqualIID(riid, &IID_IAVIFile)) + *ppv = &This->IAVIFile_iface; + else if (IsEqualGUID(riid, &IID_IPersistFile)) + *ppv = &This->IPersistFile_iface; + else { + WARN("unknown IID %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; }
- return E_NOINTERFACE; + /* Violation of the COM aggregation ref counting rule */ + IUnknown_AddRef(&This->IUnknown_inner); + return S_OK; }
-static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface) +static ULONG WINAPI IUnknown_fnAddRef(IUnknown *iface) { - IAVIFileImpl *This = impl_from_IAVIFile(iface); + IAVIFileImpl *This = impl_from_IUnknown(iface); ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref); @@ -213,29 +226,26 @@ static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface) return ref; }
-static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface) +static ULONG WINAPI IUnknown_fnRelease(IUnknown *iface) { - IAVIFileImpl *This = impl_from_IAVIFile(iface); + IAVIFileImpl *This = impl_from_IUnknown(iface); ULONG ref = InterlockedDecrement(&This->ref); UINT i;
TRACE("(%p) ref=%d\n", This, ref);
if (!ref) { - if (This->fDirty) { - /* need to write headers to file */ + if (This->fDirty) AVIFILE_SaveFile(This); - }
for (i = 0; i < This->fInfo.dwStreams; i++) { if (This->ppStreams[i] != NULL) { - if (This->ppStreams[i]->ref != 0) { + if (This->ppStreams[i]->ref != 0) ERR(": someone has still %u reference to stream %u (%p)!\n", - This->ppStreams[i]->ref, i, This->ppStreams[i]); - } - AVIFILE_DestructAVIStream(This->ppStreams[i]); - HeapFree(GetProcessHeap(), 0, This->ppStreams[i]); - This->ppStreams[i] = NULL; + This->ppStreams[i]->ref, i, This->ppStreams[i]); + AVIFILE_DestructAVIStream(This->ppStreams[i]); + HeapFree(GetProcessHeap(), 0, This->ppStreams[i]); + This->ppStreams[i] = NULL; } }
@@ -264,6 +274,34 @@ static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface) return ref; }
+static const IUnknownVtbl unk_vtbl = +{ + IUnknown_fnQueryInterface, + IUnknown_fnAddRef, + IUnknown_fnRelease +}; + +static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile *iface, REFIID riid, void **ppv) +{ + IAVIFileImpl *This = impl_from_IAVIFile(iface); + + return IUnknown_QueryInterface(This->outer_unk, riid, ppv); +} + +static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface) +{ + IAVIFileImpl *This = impl_from_IAVIFile(iface); + + return IUnknown_AddRef(This->outer_unk); +} + +static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface) +{ + IAVIFileImpl *This = impl_from_IAVIFile(iface); + + return IUnknown_Release(This->outer_unk); +} + static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile *iface, AVIFILEINFOW *afi, LONG size) { IAVIFileImpl *This = impl_from_IAVIFile(iface); @@ -485,25 +523,25 @@ static const struct IAVIFileVtbl avif_vt = { };
-static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile *iface, REFIID refiid, void **ppv) +static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile *iface, REFIID riid, void **ppv) { IAVIFileImpl *This = impl_from_IPersistFile(iface);
- return IAVIFile_QueryInterface(&This->IAVIFile_iface, refiid, ppv); + return IUnknown_QueryInterface(This->outer_unk, riid, ppv); }
static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile *iface) { IAVIFileImpl *This = impl_from_IPersistFile(iface);
- return IAVIFile_AddRef(&This->IAVIFile_iface); + return IUnknown_AddRef(This->outer_unk); }
static ULONG WINAPI IPersistFile_fnRelease(IPersistFile *iface) { IAVIFileImpl *This = impl_from_IPersistFile(iface);
- return IAVIFile_Release(&This->IAVIFile_iface); + return IUnknown_Release(This->outer_unk); }
static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile *iface, LPCLSID pClassID) @@ -634,7 +672,7 @@ static const struct IPersistFileVtbl pf_vt = { IPersistFile_fnGetCurFile };
-HRESULT AVIFILE_CreateAVIFile(REFIID riid, void **ppv) +HRESULT AVIFILE_CreateAVIFile(IUnknown *pUnkOuter, REFIID riid, void **ppv) { IAVIFileImpl *obj; HRESULT hr; @@ -644,13 +682,17 @@ HRESULT AVIFILE_CreateAVIFile(REFIID riid, void **ppv) if (!obj) return AVIERR_MEMORY;
+ obj->IUnknown_inner.lpVtbl = &unk_vtbl; obj->IAVIFile_iface.lpVtbl = &avif_vt; obj->IPersistFile_iface.lpVtbl = &pf_vt; - obj->ref = 0; - - hr = IAVIFile_QueryInterface(&obj->IAVIFile_iface, riid, ppv); - if (FAILED(hr)) - HeapFree(GetProcessHeap(), 0, obj); + obj->ref = 1; + if (pUnkOuter) + obj->outer_unk = pUnkOuter; + else + obj->outer_unk = &obj->IUnknown_inner; + + hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv); + IUnknown_Release(&obj->IUnknown_inner);
return hr; } diff --git a/dlls/avifil32/avifile_private.h b/dlls/avifil32/avifile_private.h index b9390c6..01f0ae6 100644 --- a/dlls/avifil32/avifile_private.h +++ b/dlls/avifil32/avifile_private.h @@ -58,7 +58,7 @@ DEFINE_AVIGUID(CLSID_ACMStream, 0x0002000F, 0, 0);
extern HMODULE AVIFILE_hModule DECLSPEC_HIDDEN;
-extern HRESULT AVIFILE_CreateAVIFile(REFIID riid, LPVOID *ppobj) DECLSPEC_HIDDEN; +extern HRESULT AVIFILE_CreateAVIFile(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppobj) DECLSPEC_HIDDEN; extern HRESULT AVIFILE_CreateWAVFile(REFIID riid, LPVOID *ppobj) DECLSPEC_HIDDEN; extern HRESULT AVIFILE_CreateACMStream(REFIID riid, LPVOID *ppobj) DECLSPEC_HIDDEN; extern HRESULT AVIFILE_CreateICMStream(REFIID riid, LPVOID *ppobj) DECLSPEC_HIDDEN; diff --git a/dlls/avifil32/factory.c b/dlls/avifil32/factory.c index 295f11f..330022c 100644 --- a/dlls/avifil32/factory.c +++ b/dlls/avifil32/factory.c @@ -140,12 +140,19 @@ static HRESULT WINAPI IClassFactory_fnCreateInstance(LPCLASSFACTORY iface, TRACE("(%p,%p,%s,%p)\n", iface, pOuter, debugstr_guid(riid), ppobj);
- if (ppobj == NULL || pOuter != NULL) - return E_FAIL; + if (!ppobj) + return E_INVALIDARG; *ppobj = NULL;
+ if (pOuter && !IsEqualGUID(&IID_IUnknown, riid)) + return E_INVALIDARG; + if (IsEqualGUID(&CLSID_AVIFile, &This->clsid)) - return AVIFILE_CreateAVIFile(riid,ppobj); + return AVIFILE_CreateAVIFile(pOuter, riid, ppobj); + + if (pOuter) + return CLASS_E_NOAGGREGATION; + if (IsEqualGUID(&CLSID_ICMStream, &This->clsid)) return AVIFILE_CreateICMStream(riid,ppobj); if (IsEqualGUID(&CLSID_WAVFile, &This->clsid))