Michael Stefaniuc : avifil32: Support COM aggregation for AVIFile.
Alexandre Julliard
julliard at winehq.org
Thu Mar 7 13:57:14 CST 2013
Module: wine
Branch: master
Commit: 7854cce7575735cd06d0ef340015ef95831d47f2
URL: http://source.winehq.org/git/wine.git/?a=commit;h=7854cce7575735cd06d0ef340015ef95831d47f2
Author: Michael Stefaniuc <mstefani at 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))
More information about the wine-cvs
mailing list