avifil32: Support COM aggregation for AVIFile.
Ref counting bug in QueryInterface comes free of charge!
This commit is contained in:
parent
39127a0700
commit
7854cce757
|
@ -30,6 +30,7 @@
|
||||||
* When index is missing it works, but index seems to be okay.
|
* When index is missing it works, but index seems to be okay.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define COBJMACROS
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@ -118,8 +119,10 @@ typedef struct _IAVIStreamImpl {
|
||||||
} IAVIStreamImpl;
|
} IAVIStreamImpl;
|
||||||
|
|
||||||
struct _IAVIFileImpl {
|
struct _IAVIFileImpl {
|
||||||
|
IUnknown IUnknown_inner;
|
||||||
IAVIFile IAVIFile_iface;
|
IAVIFile IAVIFile_iface;
|
||||||
IPersistFile IPersistFile_iface;
|
IPersistFile IPersistFile_iface;
|
||||||
|
IUnknown *outer_unk;
|
||||||
LONG ref;
|
LONG ref;
|
||||||
|
|
||||||
AVIFILEINFOW fInfo;
|
AVIFILEINFOW fInfo;
|
||||||
|
@ -144,6 +147,11 @@ struct _IAVIFileImpl {
|
||||||
BOOL fDirty;
|
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)
|
static inline IAVIFileImpl *impl_from_IAVIFile(IAVIFile *iface)
|
||||||
{
|
{
|
||||||
return CONTAINING_RECORD(iface, IAVIFileImpl, 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,
|
FOURCC ckid, DWORD flags, LPCVOID buffer,
|
||||||
LONG size);
|
LONG size);
|
||||||
|
|
||||||
static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile *iface, REFIID refiid,
|
static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown *iface, REFIID riid, void **ppv)
|
||||||
LPVOID *obj)
|
|
||||||
{
|
{
|
||||||
IAVIFileImpl *This = impl_from_IAVIFile(iface);
|
IAVIFileImpl *This = impl_from_IUnknown(iface);
|
||||||
|
|
||||||
TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
|
TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
|
||||||
|
|
||||||
if (IsEqualGUID(&IID_IUnknown, refiid) ||
|
if (!ppv) {
|
||||||
IsEqualGUID(&IID_IAVIFile, refiid)) {
|
WARN("invalid parameter\n");
|
||||||
*obj = iface;
|
return E_INVALIDARG;
|
||||||
IAVIFile_AddRef(iface);
|
}
|
||||||
|
*ppv = NULL;
|
||||||
|
|
||||||
return S_OK;
|
if (IsEqualIID(riid, &IID_IUnknown))
|
||||||
} else if (IsEqualGUID(&IID_IPersistFile, refiid)) {
|
*ppv = &This->IUnknown_inner;
|
||||||
*obj = &This->IPersistFile_iface;
|
else if (IsEqualIID(riid, &IID_IAVIFile))
|
||||||
IAVIFile_AddRef(iface);
|
*ppv = &This->IAVIFile_iface;
|
||||||
|
else if (IsEqualGUID(riid, &IID_IPersistFile))
|
||||||
return S_OK;
|
*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);
|
ULONG ref = InterlockedIncrement(&This->ref);
|
||||||
|
|
||||||
TRACE("(%p) ref=%d\n", This, ref);
|
TRACE("(%p) ref=%d\n", This, ref);
|
||||||
|
@ -213,26 +226,23 @@ static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface)
|
||||||
return ref;
|
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);
|
ULONG ref = InterlockedDecrement(&This->ref);
|
||||||
UINT i;
|
UINT i;
|
||||||
|
|
||||||
TRACE("(%p) ref=%d\n", This, ref);
|
TRACE("(%p) ref=%d\n", This, ref);
|
||||||
|
|
||||||
if (!ref) {
|
if (!ref) {
|
||||||
if (This->fDirty) {
|
if (This->fDirty)
|
||||||
/* need to write headers to file */
|
|
||||||
AVIFILE_SaveFile(This);
|
AVIFILE_SaveFile(This);
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < This->fInfo.dwStreams; i++) {
|
for (i = 0; i < This->fInfo.dwStreams; i++) {
|
||||||
if (This->ppStreams[i] != NULL) {
|
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",
|
ERR(": someone has still %u reference to stream %u (%p)!\n",
|
||||||
This->ppStreams[i]->ref, i, This->ppStreams[i]);
|
This->ppStreams[i]->ref, i, This->ppStreams[i]);
|
||||||
}
|
|
||||||
AVIFILE_DestructAVIStream(This->ppStreams[i]);
|
AVIFILE_DestructAVIStream(This->ppStreams[i]);
|
||||||
HeapFree(GetProcessHeap(), 0, This->ppStreams[i]);
|
HeapFree(GetProcessHeap(), 0, This->ppStreams[i]);
|
||||||
This->ppStreams[i] = NULL;
|
This->ppStreams[i] = NULL;
|
||||||
|
@ -264,6 +274,34 @@ static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface)
|
||||||
return ref;
|
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)
|
static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile *iface, AVIFILEINFOW *afi, LONG size)
|
||||||
{
|
{
|
||||||
IAVIFileImpl *This = impl_from_IAVIFile(iface);
|
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);
|
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)
|
static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile *iface)
|
||||||
{
|
{
|
||||||
IAVIFileImpl *This = impl_from_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)
|
static ULONG WINAPI IPersistFile_fnRelease(IPersistFile *iface)
|
||||||
{
|
{
|
||||||
IAVIFileImpl *This = impl_from_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)
|
static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile *iface, LPCLSID pClassID)
|
||||||
|
@ -634,7 +672,7 @@ static const struct IPersistFileVtbl pf_vt = {
|
||||||
IPersistFile_fnGetCurFile
|
IPersistFile_fnGetCurFile
|
||||||
};
|
};
|
||||||
|
|
||||||
HRESULT AVIFILE_CreateAVIFile(REFIID riid, void **ppv)
|
HRESULT AVIFILE_CreateAVIFile(IUnknown *pUnkOuter, REFIID riid, void **ppv)
|
||||||
{
|
{
|
||||||
IAVIFileImpl *obj;
|
IAVIFileImpl *obj;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -644,13 +682,17 @@ HRESULT AVIFILE_CreateAVIFile(REFIID riid, void **ppv)
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return AVIERR_MEMORY;
|
return AVIERR_MEMORY;
|
||||||
|
|
||||||
|
obj->IUnknown_inner.lpVtbl = &unk_vtbl;
|
||||||
obj->IAVIFile_iface.lpVtbl = &avif_vt;
|
obj->IAVIFile_iface.lpVtbl = &avif_vt;
|
||||||
obj->IPersistFile_iface.lpVtbl = &pf_vt;
|
obj->IPersistFile_iface.lpVtbl = &pf_vt;
|
||||||
obj->ref = 0;
|
obj->ref = 1;
|
||||||
|
if (pUnkOuter)
|
||||||
|
obj->outer_unk = pUnkOuter;
|
||||||
|
else
|
||||||
|
obj->outer_unk = &obj->IUnknown_inner;
|
||||||
|
|
||||||
hr = IAVIFile_QueryInterface(&obj->IAVIFile_iface, riid, ppv);
|
hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
|
||||||
if (FAILED(hr))
|
IUnknown_Release(&obj->IUnknown_inner);
|
||||||
HeapFree(GetProcessHeap(), 0, obj);
|
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ DEFINE_AVIGUID(CLSID_ACMStream, 0x0002000F, 0, 0);
|
||||||
|
|
||||||
extern HMODULE AVIFILE_hModule DECLSPEC_HIDDEN;
|
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_CreateWAVFile(REFIID riid, LPVOID *ppobj) DECLSPEC_HIDDEN;
|
||||||
extern HRESULT AVIFILE_CreateACMStream(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;
|
extern HRESULT AVIFILE_CreateICMStream(REFIID riid, LPVOID *ppobj) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -140,12 +140,19 @@ static HRESULT WINAPI IClassFactory_fnCreateInstance(LPCLASSFACTORY iface,
|
||||||
TRACE("(%p,%p,%s,%p)\n", iface, pOuter, debugstr_guid(riid),
|
TRACE("(%p,%p,%s,%p)\n", iface, pOuter, debugstr_guid(riid),
|
||||||
ppobj);
|
ppobj);
|
||||||
|
|
||||||
if (ppobj == NULL || pOuter != NULL)
|
if (!ppobj)
|
||||||
return E_FAIL;
|
return E_INVALIDARG;
|
||||||
*ppobj = NULL;
|
*ppobj = NULL;
|
||||||
|
|
||||||
|
if (pOuter && !IsEqualGUID(&IID_IUnknown, riid))
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
if (IsEqualGUID(&CLSID_AVIFile, &This->clsid))
|
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))
|
if (IsEqualGUID(&CLSID_ICMStream, &This->clsid))
|
||||||
return AVIFILE_CreateICMStream(riid,ppobj);
|
return AVIFILE_CreateICMStream(riid,ppobj);
|
||||||
if (IsEqualGUID(&CLSID_WAVFile, &This->clsid))
|
if (IsEqualGUID(&CLSID_WAVFile, &This->clsid))
|
||||||
|
|
Loading…
Reference in New Issue