From 96e9615701afa29a76f4d81427443bf5d219c007 Mon Sep 17 00:00:00 2001
From: Hidenori Takeshima <hidenori@a2.ctktv.ne.jp>
Date: Fri, 7 Sep 2001 19:46:49 +0000
Subject: [PATCH] Added some stubs. Started implementing some interfaces in
 FilterGraph.

---
 dlls/quartz/Makefile.in |   8 +
 dlls/quartz/complist.c  |  83 +++++++-
 dlls/quartz/complist.h  |  14 +-
 dlls/quartz/devenum.c   |   8 +-
 dlls/quartz/devenum.h   |   2 +-
 dlls/quartz/devmon.c    | 422 ++++++++++++++++++++++++++++++++++++++
 dlls/quartz/devmon.h    |  36 ++++
 dlls/quartz/enumunk.c   | 244 ++++++++++++++++++++++
 dlls/quartz/enumunk.h   |  16 ++
 dlls/quartz/fgclsid.c   |  97 +++++++++
 dlls/quartz/fgidisp.c   | 128 ++++++++++++
 dlls/quartz/fgraph.c    |  81 ++++++--
 dlls/quartz/fgraph.h    |  80 ++++++--
 dlls/quartz/fmap.c      |   8 +-
 dlls/quartz/fmap.h      |   2 +-
 dlls/quartz/fmap2.c     |   8 +-
 dlls/quartz/fmap2.h     |   3 +-
 dlls/quartz/ibasaud.c   |   4 +-
 dlls/quartz/ibasvid.c   |   4 +-
 dlls/quartz/idevenum.c  | 109 +++++++++-
 dlls/quartz/ifgraph.c   | 444 +++++++++++++++++++++++++++++++++++++---
 dlls/quartz/ifmap.c     |  52 +++--
 dlls/quartz/ifmap3.c    |  20 +-
 dlls/quartz/igrver.c    | 108 ++++++++++
 dlls/quartz/imcntl.c    |   4 +-
 dlls/quartz/imem.c      |   9 +-
 dlls/quartz/imesink.c   |  95 +++++++++
 dlls/quartz/imevent.c   |  16 +-
 dlls/quartz/imfilter.c  | 162 +++++++++++++++
 dlls/quartz/impos.c     |  25 ++-
 dlls/quartz/imseek.c    |   4 +-
 dlls/quartz/irclock.c   |   9 +-
 dlls/quartz/iunk.h      |   2 +-
 dlls/quartz/ividwin.c   |   4 +-
 dlls/quartz/main.c      |  10 +-
 dlls/quartz/memalloc.c  |  16 +-
 dlls/quartz/memalloc.h  |   3 +-
 dlls/quartz/monprop.c   | 205 +++++++++++++++++++
 dlls/quartz/monprop.h   |  34 +++
 dlls/quartz/quartz.spec |   9 +-
 dlls/quartz/regsvr.c    | 359 +++++++++++++++++++++++++++++---
 dlls/quartz/regsvr.h    |  54 +++--
 dlls/quartz/sysclock.c  |  17 +-
 dlls/quartz/sysclock.h  |   3 +-
 44 files changed, 2865 insertions(+), 156 deletions(-)
 create mode 100644 dlls/quartz/devmon.c
 create mode 100644 dlls/quartz/devmon.h
 create mode 100644 dlls/quartz/enumunk.c
 create mode 100644 dlls/quartz/enumunk.h
 create mode 100644 dlls/quartz/fgclsid.c
 create mode 100644 dlls/quartz/fgidisp.c
 create mode 100644 dlls/quartz/igrver.c
 create mode 100644 dlls/quartz/imesink.c
 create mode 100644 dlls/quartz/imfilter.c
 create mode 100644 dlls/quartz/monprop.c
 create mode 100644 dlls/quartz/monprop.h

diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in
index ef6264d41b9..6ce20a3b1f8 100644
--- a/dlls/quartz/Makefile.in
+++ b/dlls/quartz/Makefile.in
@@ -12,6 +12,10 @@ C_SRCS = \
 	amerror.c \
 	complist.c \
 	devenum.c \
+	devmon.c \
+	enumunk.c \
+	fgclsid.c \
+	fgidisp.c \
 	fgraph.c \
 	fmap.c \
 	fmap2.c \
@@ -21,9 +25,12 @@ C_SRCS = \
 	ifgraph.c \
 	ifmap.c \
 	ifmap3.c \
+	igrver.c \
 	imcntl.c \
 	imem.c \
+	imesink.c \
 	imevent.c \
+	imfilter.c \
 	impos.c \
 	imseek.c \
 	irclock.c \
@@ -31,6 +38,7 @@ C_SRCS = \
 	ividwin.c \
 	main.c \
 	memalloc.c \
+	monprop.c \
 	regsvr.c \
 	sysclock.c
 
diff --git a/dlls/quartz/complist.c b/dlls/quartz/complist.c
index 305a2509a74..5bf07f876e7 100644
--- a/dlls/quartz/complist.c
+++ b/dlls/quartz/complist.c
@@ -25,6 +25,7 @@ struct QUARTZ_CompList
 {
 	QUARTZ_CompListItem*	pFirst;
 	QUARTZ_CompListItem*	pLast;
+	CRITICAL_SECTION		csList;
 };
 
 struct QUARTZ_CompListItem
@@ -32,6 +33,8 @@ struct QUARTZ_CompListItem
 	IUnknown*	punk;
 	QUARTZ_CompListItem*	pNext;
 	QUARTZ_CompListItem*	pPrev;
+	void*	pvData;
+	DWORD	dwDataLen;
 };
 
 
@@ -45,6 +48,8 @@ QUARTZ_CompList* QUARTZ_CompList_Alloc( void )
 		/* construct. */
 		pList->pFirst = NULL;
 		pList->pLast = NULL;
+
+		InitializeCriticalSection( &pList->csList );
 	}
 
 	return pList;
@@ -63,17 +68,33 @@ void QUARTZ_CompList_Free( QUARTZ_CompList* pList )
 			pNext = pCur->pNext;
 			if ( pCur->punk != NULL )
 				IUnknown_Release( pCur->punk );
+			if ( pCur->pvData != NULL )
+				QUARTZ_FreeMem( pCur->pvData );
 			QUARTZ_FreeMem( pCur );
 			pCur = pNext;
 		}
+
+		DeleteCriticalSection( &pList->csList );
+
 		QUARTZ_FreeMem( pList );
 	}
 }
 
-QUARTZ_CompList* QUARTZ_CompList_Dup( QUARTZ_CompList* pList )
+void QUARTZ_CompList_Lock( QUARTZ_CompList* pList )
+{
+	EnterCriticalSection( &pList->csList );
+}
+
+void QUARTZ_CompList_Unlock( QUARTZ_CompList* pList )
+{
+	LeaveCriticalSection( &pList->csList );
+}
+
+QUARTZ_CompList* QUARTZ_CompList_Dup(
+	const QUARTZ_CompList* pList, BOOL fDupData )
 {
 	QUARTZ_CompList*	pNewList;
-	QUARTZ_CompListItem*	pCur;
+	const QUARTZ_CompListItem*	pCur;
 	HRESULT	hr;
 
 	pNewList = QUARTZ_CompList_Alloc();
@@ -85,7 +106,13 @@ QUARTZ_CompList* QUARTZ_CompList_Dup( QUARTZ_CompList* pList )
 	{
 		if ( pCur->punk != NULL )
 		{
-			hr = QUARTZ_CompList_AddComp( pNewList, pCur->punk );
+			if ( fDupData )
+				hr = QUARTZ_CompList_AddComp(
+					pNewList, pCur->punk,
+					pCur->pvData, pCur->dwDataLen );
+			else
+				hr = QUARTZ_CompList_AddComp(
+					pNewList, pCur->punk, NULL, 0 );
 			if ( FAILED(hr) )
 			{
 				QUARTZ_CompList_Free( pNewList );
@@ -98,21 +125,38 @@ QUARTZ_CompList* QUARTZ_CompList_Dup( QUARTZ_CompList* pList )
 	return pNewList;
 }
 
-HRESULT QUARTZ_CompList_AddComp( QUARTZ_CompList* pList, IUnknown* punk )
+HRESULT QUARTZ_CompList_AddComp(
+	QUARTZ_CompList* pList, IUnknown* punk,
+	const void* pvData, DWORD dwDataLen )
 {
 	QUARTZ_CompListItem*	pItem;
 
 	pItem = (QUARTZ_CompListItem*)QUARTZ_AllocMem( sizeof(QUARTZ_CompListItem) );
 	if ( pItem == NULL )
 		return E_OUTOFMEMORY; /* out of memory. */
+
+	pItem->pvData = NULL;
+	pItem->dwDataLen = 0;
+	if ( pvData != NULL )
+	{
+		pItem->pvData = (void*)QUARTZ_AllocMem( dwDataLen );
+		if ( pItem->pvData == NULL )
+		{
+			QUARTZ_FreeMem( pItem );
+			return E_OUTOFMEMORY;
+		}
+		memcpy( pItem->pvData, pvData, dwDataLen );
+		pItem->dwDataLen = dwDataLen;
+	}
+
 	pItem->punk = punk; IUnknown_AddRef(punk);
 
 	if ( pList->pFirst != NULL )
 		pList->pFirst->pPrev = pItem;
 	else
 		pList->pLast = pItem;
-	pList->pFirst = pItem;
 	pItem->pNext = pList->pFirst;
+	pList->pFirst = pItem;
 	pItem->pPrev = NULL;
 
 	return S_OK;
@@ -139,6 +183,8 @@ HRESULT QUARTZ_CompList_RemoveComp( QUARTZ_CompList* pList, IUnknown* punk )
 	/* release this item. */
 	if ( pCur->punk != NULL )
 		IUnknown_Release( pCur->punk );
+	if ( pCur->pvData != NULL )
+		QUARTZ_FreeMem( pCur->pvData );
 	QUARTZ_FreeMem( pCur );
 
 	return S_OK;
@@ -160,6 +206,23 @@ QUARTZ_CompListItem* QUARTZ_CompList_SearchComp(
 	return NULL;
 }
 
+QUARTZ_CompListItem* QUARTZ_CompList_SearchData(
+	QUARTZ_CompList* pList, const void* pvData, DWORD dwDataLen )
+{
+	QUARTZ_CompListItem*	pCur;
+
+	pCur = pList->pFirst;
+	while ( pCur != NULL )
+	{
+		if ( pCur->dwDataLen == dwDataLen &&
+		     !memcmp( pCur->pvData, pvData, dwDataLen ) )
+			return pCur;
+		pCur = pCur->pNext;
+	}
+
+	return NULL;
+}
+
 QUARTZ_CompListItem* QUARTZ_CompList_GetFirst(
 	QUARTZ_CompList* pList )
 {
@@ -176,3 +239,13 @@ IUnknown* QUARTZ_CompList_GetItemPtr( QUARTZ_CompListItem* pItem )
 {
 	return pItem->punk;
 }
+
+const void* QUARTZ_CompList_GetDataPtr( QUARTZ_CompListItem* pItem )
+{
+	return pItem->pvData;
+}
+
+DWORD QUARTZ_CompList_GetDataLength( QUARTZ_CompListItem* pItem )
+{
+	return pItem->dwDataLen;
+}
diff --git a/dlls/quartz/complist.h b/dlls/quartz/complist.h
index c5b1c45abe1..9f02dc2e1df 100644
--- a/dlls/quartz/complist.h
+++ b/dlls/quartz/complist.h
@@ -12,16 +12,26 @@ typedef struct QUARTZ_CompListItem	QUARTZ_CompListItem;
 
 QUARTZ_CompList* QUARTZ_CompList_Alloc( void );
 void QUARTZ_CompList_Free( QUARTZ_CompList* pList );
-QUARTZ_CompList* QUARTZ_CompList_Dup( QUARTZ_CompList* pList );
-HRESULT QUARTZ_CompList_AddComp( QUARTZ_CompList* pList, IUnknown* punk );
+void QUARTZ_CompList_Lock( QUARTZ_CompList* pList );
+void QUARTZ_CompList_Unlock( QUARTZ_CompList* pList );
+
+QUARTZ_CompList* QUARTZ_CompList_Dup(
+	const QUARTZ_CompList* pList, BOOL fDupData );
+HRESULT QUARTZ_CompList_AddComp(
+	QUARTZ_CompList* pList, IUnknown* punk,
+	const void* pvData, DWORD dwDataLen );
 HRESULT QUARTZ_CompList_RemoveComp( QUARTZ_CompList* pList, IUnknown* punk );
 QUARTZ_CompListItem* QUARTZ_CompList_SearchComp(
 	QUARTZ_CompList* pList, IUnknown* punk );
+QUARTZ_CompListItem* QUARTZ_CompList_SearchData(
+	QUARTZ_CompList* pList, const void* pvData, DWORD dwDataLen );
 QUARTZ_CompListItem* QUARTZ_CompList_GetFirst(
 	QUARTZ_CompList* pList );
 QUARTZ_CompListItem* QUARTZ_CompList_GetNext(
 	QUARTZ_CompList* pList, QUARTZ_CompListItem* pPrev );
 IUnknown* QUARTZ_CompList_GetItemPtr( QUARTZ_CompListItem* pItem );
+const void* QUARTZ_CompList_GetDataPtr( QUARTZ_CompListItem* pItem );
+DWORD QUARTZ_CompList_GetDataLength( QUARTZ_CompListItem* pItem );
 
 
 #endif	/* QUARTZ_COMPLIST_H */
diff --git a/dlls/quartz/devenum.c b/dlls/quartz/devenum.c
index 390409bc67e..6d94bca142f 100644
--- a/dlls/quartz/devenum.c
+++ b/dlls/quartz/devenum.c
@@ -41,6 +41,7 @@ static void QUARTZ_DestroySystemDeviceEnum(IUnknown* punk)
 HRESULT QUARTZ_CreateSystemDeviceEnum(IUnknown* punkOuter,void** ppobj)
 {
 	CSysDevEnum*	psde;
+	HRESULT	hr;
 
 	TRACE("(%p,%p)\n",punkOuter,ppobj);
 
@@ -50,7 +51,12 @@ HRESULT QUARTZ_CreateSystemDeviceEnum(IUnknown* punkOuter,void** ppobj)
 
 	QUARTZ_IUnkInit( &psde->unk, punkOuter );
 
-	CSysDevEnum_InitICreateDevEnum( psde );
+	hr = CSysDevEnum_InitICreateDevEnum( psde );
+	if ( FAILED(hr) )
+	{
+		QUARTZ_FreeObj( psde );
+		return hr;
+	}
 
 	psde->unk.pEntries = IFEntries;
 	psde->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
diff --git a/dlls/quartz/devenum.h b/dlls/quartz/devenum.h
index 10ce46fc756..59ff85d2e4a 100644
--- a/dlls/quartz/devenum.h
+++ b/dlls/quartz/devenum.h
@@ -28,7 +28,7 @@ typedef struct CSysDevEnum
 HRESULT QUARTZ_CreateSystemDeviceEnum(IUnknown* punkOuter,void** ppobj);
 
 
-void CSysDevEnum_InitICreateDevEnum( CSysDevEnum* psde );
+HRESULT CSysDevEnum_InitICreateDevEnum( CSysDevEnum* psde );
 void CSysDevEnum_UninitICreateDevEnum( CSysDevEnum* psde );
 
 
diff --git a/dlls/quartz/devmon.c b/dlls/quartz/devmon.c
new file mode 100644
index 00000000000..317d5c771c6
--- /dev/null
+++ b/dlls/quartz/devmon.c
@@ -0,0 +1,422 @@
+/*
+ * Implements IMoniker for CLSID_CDeviceMoniker.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "objidl.h"
+#include "oleidl.h"
+#include "ocidl.h"
+#include "oleauto.h"
+#include "strmif.h"
+#include "uuids.h"
+#include "wine/unicode.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "devmon.h"
+#include "monprop.h"
+#include "regsvr.h"
+
+
+static HRESULT WINAPI
+IMoniker_fnQueryInterface(IMoniker* iface,REFIID riid,void** ppobj)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IMoniker_fnAddRef(IMoniker* iface)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IMoniker_fnRelease(IMoniker* iface)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+static HRESULT WINAPI IMoniker_fnGetClassID(IMoniker* iface, CLSID *pClassID)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	TRACE("(%p)->()\n",This);
+
+	if ( pClassID == NULL )
+		return E_POINTER;
+	memcpy( pClassID, &CLSID_CDeviceMoniker, sizeof(CLSID) );
+
+	return NOERROR;
+}
+
+static HRESULT WINAPI IMoniker_fnIsDirty(IMoniker* iface)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnLoad(IMoniker* iface, IStream* pStm)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnSave(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnGetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnBindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+	HRESULT	hr;
+	IPropertyBag*	pPropBag;
+	VARIANT	vClsid;
+	CLSID	clsid;
+
+	TRACE("(%p)->(%p,%p,%s,%p)\n",This,
+		pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
+	if ( pbc != NULL )
+	{
+		FIXME("IBindCtx* pbc != NULL not implemented.\n");
+		return E_FAIL;
+	}
+	if ( pmkToLeft != NULL )
+	{
+		FIXME("IMoniker* pmkToLeft != NULL not implemented.\n");
+		return E_FAIL;
+	}
+	if ( ppvResult == NULL )
+		return E_POINTER;
+
+	hr = QUARTZ_CreateRegPropertyBag(
+			This->m_hkRoot, This->m_pwszPath, &pPropBag );
+	if ( FAILED(hr) )
+		return hr;
+
+	vClsid.n1.n2.vt = VT_BSTR;
+	hr = IPropertyBag_Read(
+			pPropBag, QUARTZ_wszCLSID, &vClsid, NULL );
+	IPropertyBag_Release( pPropBag );
+	if ( FAILED(hr) )
+		return hr;
+
+	hr = CLSIDFromString( vClsid.n1.n2.n3.bstrVal, &clsid );
+	SysFreeString(vClsid.n1.n2.n3.bstrVal);
+	if ( FAILED(hr) )
+		return hr;
+
+	return CoCreateInstance(
+		&clsid, NULL, CLSCTX_INPROC_SERVER, riid, ppvResult );
+}
+
+static HRESULT WINAPI IMoniker_fnBindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+	HRESULT	hr;
+
+	TRACE("(%p)->(%p,%p,%s,%p)\n",This,
+		pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
+	if ( pbc != NULL )
+	{
+		FIXME("IBindCtx* pbc != NULL not implemented.\n");
+		return E_FAIL;
+	}
+	if ( pmkToLeft != NULL )
+	{
+		FIXME("IMoniker* pmkToLeft != NULL not implemented.\n");
+		return E_FAIL;
+	}
+	if ( ppvResult == NULL )
+		return E_POINTER;
+
+	hr = E_NOINTERFACE;
+	if ( IsEqualGUID(riid,&IID_IUnknown) ||
+		 IsEqualGUID(riid,&IID_IPropertyBag) )
+	{
+		hr = QUARTZ_CreateRegPropertyBag(
+			This->m_hkRoot, This->m_pwszPath,
+			(IPropertyBag**)ppvResult );
+	}
+
+	return hr;
+}
+
+static HRESULT WINAPI IMoniker_fnReduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	TRACE("(%p)->()\n",This);
+
+	if ( ppmkReduced == NULL )
+		return E_POINTER;
+
+	*ppmkReduced = iface; IMoniker_AddRef(iface);
+
+	return MK_S_REDUCED_TO_SELF;
+}
+
+static HRESULT WINAPI IMoniker_fnComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnEnum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	TRACE("(%p)->()\n",This);
+
+	if ( ppenumMoniker == NULL )
+		return E_POINTER;
+
+	*ppenumMoniker = NULL;
+	return NOERROR;
+}
+
+static HRESULT WINAPI IMoniker_fnIsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnHash(IMoniker* iface,DWORD* pdwHash)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnIsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnGetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pCompositeTime)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnInverse(IMoniker* iface,IMoniker** ppmk)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnCommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnRelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnGetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IMoniker_fnIsSystemMoniker(IMoniker* iface,DWORD* pdwMksys)
+{
+	CDeviceMoniker_THIS(iface,moniker);
+
+	TRACE("(%p)->()\n",This);
+	if ( pdwMksys == NULL )
+		return E_POINTER;
+
+	*pdwMksys = MKSYS_NONE;
+	return S_FALSE;
+}
+
+
+static ICOM_VTABLE(IMoniker) imoniker =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	IMoniker_fnQueryInterface,
+	IMoniker_fnAddRef,
+	IMoniker_fnRelease,
+	/* IPersist fields */
+	IMoniker_fnGetClassID,
+	/* IPersistStream fields */
+	IMoniker_fnIsDirty,
+	IMoniker_fnLoad,
+	IMoniker_fnSave,
+	IMoniker_fnGetSizeMax,
+	/* IMoniker fields */
+	IMoniker_fnBindToObject,
+	IMoniker_fnBindToStorage,
+	IMoniker_fnReduce,
+	IMoniker_fnComposeWith,
+	IMoniker_fnEnum,
+	IMoniker_fnIsEqual,
+	IMoniker_fnHash,
+	IMoniker_fnIsRunning,
+	IMoniker_fnGetTimeOfLastChange,
+	IMoniker_fnInverse,
+	IMoniker_fnCommonPrefixWith,
+	IMoniker_fnRelativePathTo,
+	IMoniker_fnGetDisplayName,
+	IMoniker_fnParseDisplayName,
+	IMoniker_fnIsSystemMoniker,
+};
+
+
+static HRESULT CDeviceMoniker_InitIMoniker(
+	CDeviceMoniker* pdm, HKEY hkRoot, LPCWSTR lpKeyPath )
+{
+	DWORD	dwLen;
+
+	ICOM_VTBL(&pdm->moniker) = &imoniker;
+	pdm->m_hkRoot = hkRoot;
+	pdm->m_pwszPath = NULL;
+
+	dwLen = sizeof(WCHAR)*(strlenW(lpKeyPath)+1);
+	pdm->m_pwszPath = (WCHAR*)QUARTZ_AllocMem( dwLen );
+	if ( pdm->m_pwszPath == NULL )
+		return E_OUTOFMEMORY;
+	memcpy( pdm->m_pwszPath, lpKeyPath, dwLen );
+
+	return NOERROR;
+}
+
+static void CDeviceMoniker_UninitIMoniker(
+	CDeviceMoniker* pdm )
+{
+	if ( pdm->m_pwszPath != NULL )
+		QUARTZ_FreeMem( pdm->m_pwszPath );
+}
+
+
+static void QUARTZ_DestroyDeviceMoniker(IUnknown* punk)
+{
+	CDeviceMoniker_THIS(punk,unk);
+
+	CDeviceMoniker_UninitIMoniker( This );
+}
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry IFEntries[] =
+{
+  { &IID_IPersist, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
+  { &IID_IPersistStream, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
+  { &IID_IMoniker, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
+};
+
+HRESULT QUARTZ_CreateDeviceMoniker(
+	HKEY hkRoot, LPCWSTR lpKeyPath,
+	IMoniker** ppMoniker )
+{
+	CDeviceMoniker*	pdm;
+	HRESULT	hr;
+
+	TRACE("(%08x,%s,%p)\n",hkRoot,debugstr_w(lpKeyPath),ppMoniker );
+
+	pdm = (CDeviceMoniker*)QUARTZ_AllocObj( sizeof(CDeviceMoniker) );
+	if ( pdm == NULL )
+		return E_OUTOFMEMORY;
+
+	QUARTZ_IUnkInit( &pdm->unk, NULL );
+	hr = CDeviceMoniker_InitIMoniker( pdm, hkRoot, lpKeyPath );
+	if ( FAILED(hr) )
+	{
+		QUARTZ_FreeObj( pdm );
+		return hr;
+	}
+
+	pdm->unk.pEntries = IFEntries;
+	pdm->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
+	pdm->unk.pOnFinalRelease = &QUARTZ_DestroyDeviceMoniker;
+
+	*ppMoniker = (IMoniker*)(&pdm->moniker);
+
+	return S_OK;
+}
+
+
diff --git a/dlls/quartz/devmon.h b/dlls/quartz/devmon.h
new file mode 100644
index 00000000000..7791a52d24f
--- /dev/null
+++ b/dlls/quartz/devmon.h
@@ -0,0 +1,36 @@
+#ifndef	WINE_DSHOW_DEVMON_H
+#define	WINE_DSHOW_DEVMON_H
+
+/*
+		implements CLSID_CDeviceMoniker.
+
+	- At least, the following interfaces should be implemented:
+
+	IUnknown
+		+ IPersist - IPersistStream - IMoniker
+ */
+
+#include "iunk.h"
+
+typedef struct DMON_IMonikerImpl
+{
+	ICOM_VFIELD(IMoniker);
+} DMON_IMonikerImpl;
+
+typedef struct CDeviceMoniker
+{
+	QUARTZ_IUnkImpl	unk;
+	DMON_IMonikerImpl	moniker;
+	/* IMoniker fields */
+	HKEY	m_hkRoot;
+	WCHAR*	m_pwszPath;
+} CDeviceMoniker;
+
+#define	CDeviceMoniker_THIS(iface,member)	CDeviceMoniker*	This = (CDeviceMoniker*)(((char*)iface)-offsetof(CDeviceMoniker,member))
+
+HRESULT QUARTZ_CreateDeviceMoniker(
+	HKEY hkRoot, LPCWSTR lpKeyPath,
+	IMoniker** ppMoniker );
+
+
+#endif	/* WINE_DSHOW_DEVMON_H */
diff --git a/dlls/quartz/enumunk.c b/dlls/quartz/enumunk.c
new file mode 100644
index 00000000000..eeb887734ca
--- /dev/null
+++ b/dlls/quartz/enumunk.c
@@ -0,0 +1,244 @@
+/*
+ * Implementation of IEnumUnknown (for internal use).
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "wine/obj_oleaut.h"
+#include "strmif.h"
+#include "control.h"
+#include "uuids.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "enumunk.h"
+#include "iunk.h"
+
+
+
+typedef struct IEnumUnknownImpl
+{
+	ICOM_VFIELD(IEnumUnknown);
+} IEnumUnknownImpl;
+
+typedef struct
+{
+	QUARTZ_IUnkImpl	unk;
+	IEnumUnknownImpl	enumunk;
+	struct QUARTZ_IFEntry	IFEntries[1];
+	QUARTZ_CompList*	pCompList;
+	QUARTZ_CompListItem*	pItemCur;
+} CEnumUnknown;
+
+#define	CEnumUnknown_THIS(iface,member)		CEnumUnknown*	This = ((CEnumUnknown*)(((char*)iface)-offsetof(CEnumUnknown,member)))
+
+
+
+
+static HRESULT WINAPI
+IEnumUnknown_fnQueryInterface(IEnumUnknown* iface,REFIID riid,void** ppobj)
+{
+	CEnumUnknown_THIS(iface,enumunk);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IEnumUnknown_fnAddRef(IEnumUnknown* iface)
+{
+	CEnumUnknown_THIS(iface,enumunk);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IEnumUnknown_fnRelease(IEnumUnknown* iface)
+{
+	CEnumUnknown_THIS(iface,enumunk);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+static HRESULT WINAPI
+IEnumUnknown_fnNext(IEnumUnknown* iface,ULONG cReq,IUnknown** ppunk,ULONG* pcFetched)
+{
+	CEnumUnknown_THIS(iface,enumunk);
+	HRESULT	hr;
+	ULONG	cFetched;
+
+	TRACE("(%p)->(%lu,%p,%p)\n",This,cReq,ppunk,pcFetched);
+
+	if ( pcFetched == NULL && cReq > 1 )
+		return E_INVALIDARG;
+	if ( ppunk == NULL )
+		return E_POINTER;
+
+	QUARTZ_CompList_Lock( This->pCompList );
+
+	hr = NOERROR;
+	cFetched = 0;
+	while ( cReq > 0 )
+	{
+		if ( This->pItemCur == NULL )
+		{
+			hr = S_FALSE;
+			break;
+		}
+		ppunk[ cFetched ++ ] = QUARTZ_CompList_GetItemPtr( This->pItemCur );
+		IUnknown_AddRef( *ppunk );
+
+		This->pItemCur =
+			QUARTZ_CompList_GetNext( This->pCompList, This->pItemCur );
+		cReq --;
+	}
+
+	QUARTZ_CompList_Unlock( This->pCompList );
+
+	if ( pcFetched != NULL )
+		*pcFetched = cFetched;
+
+	return hr;
+}
+
+static HRESULT WINAPI
+IEnumUnknown_fnSkip(IEnumUnknown* iface,ULONG cSkip)
+{
+	CEnumUnknown_THIS(iface,enumunk);
+	HRESULT	hr;
+
+	TRACE("(%p)->()\n",This);
+
+	QUARTZ_CompList_Lock( This->pCompList );
+
+	hr = NOERROR;
+	while ( cSkip > 0 )
+	{
+		if ( This->pItemCur == NULL )
+		{
+			hr = S_FALSE;
+			break;
+		}
+		This->pItemCur =
+			QUARTZ_CompList_GetNext( This->pCompList, This->pItemCur );
+		cSkip --;
+	}
+
+	QUARTZ_CompList_Unlock( This->pCompList );
+
+	return hr;
+}
+
+static HRESULT WINAPI
+IEnumUnknown_fnReset(IEnumUnknown* iface)
+{
+	CEnumUnknown_THIS(iface,enumunk);
+
+	TRACE("(%p)->()\n",This);
+
+	QUARTZ_CompList_Lock( This->pCompList );
+
+	This->pItemCur = QUARTZ_CompList_GetFirst( This->pCompList );
+
+	QUARTZ_CompList_Unlock( This->pCompList );
+
+	return NOERROR;
+}
+
+static HRESULT WINAPI
+IEnumUnknown_fnClone(IEnumUnknown* iface,IEnumUnknown** ppunk)
+{
+	CEnumUnknown_THIS(iface,enumunk);
+	HRESULT	hr;
+
+	TRACE("(%p)->()\n",This);
+
+	if ( ppunk == NULL )
+		return E_POINTER;
+
+	QUARTZ_CompList_Lock( This->pCompList );
+
+	hr = QUARTZ_CreateEnumUnknown(
+		This->IFEntries[0].piid,
+		(void**)ppunk,
+		This->pCompList );
+
+	QUARTZ_CompList_Unlock( This->pCompList );
+
+	return hr;
+}
+
+
+static ICOM_VTABLE(IEnumUnknown) ienumunk =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	IEnumUnknown_fnQueryInterface,
+	IEnumUnknown_fnAddRef,
+	IEnumUnknown_fnRelease,
+	/* IEnumUnknown fields */
+	IEnumUnknown_fnNext,
+	IEnumUnknown_fnSkip,
+	IEnumUnknown_fnReset,
+	IEnumUnknown_fnClone,
+};
+
+void QUARTZ_DestroyEnumUnknown(IUnknown* punk)
+{
+	CEnumUnknown_THIS(punk,unk);
+
+	if ( This->pCompList != NULL )
+		QUARTZ_CompList_Free( This->pCompList );
+}
+
+HRESULT QUARTZ_CreateEnumUnknown(
+	REFIID riidEnum, void** ppobj, const QUARTZ_CompList* pCompList )
+{
+	CEnumUnknown*	penum;
+	QUARTZ_CompList*	pCompListDup;
+
+	TRACE("(%s,%p,%p)\n",debugstr_guid(riidEnum),ppobj,pCompList);
+
+	pCompListDup = QUARTZ_CompList_Dup( pCompList, FALSE );
+	if ( pCompListDup == NULL )
+		return E_OUTOFMEMORY;
+
+	penum = (CEnumUnknown*)QUARTZ_AllocObj( sizeof(CEnumUnknown) );
+	if ( penum == NULL )
+	{
+		QUARTZ_CompList_Free( pCompListDup );
+		return E_OUTOFMEMORY;
+	}
+
+	QUARTZ_IUnkInit( &penum->unk, NULL );
+	ICOM_VTBL(&penum->enumunk) = &ienumunk;
+
+	penum->IFEntries[0].piid = riidEnum;
+	penum->IFEntries[0].ofsVTPtr =
+		offsetof(CEnumUnknown,enumunk)-offsetof(CEnumUnknown,unk);
+	penum->pCompList = pCompListDup;
+	penum->pItemCur = QUARTZ_CompList_GetFirst( pCompListDup );
+
+	penum->unk.pEntries = penum->IFEntries;
+	penum->unk.dwEntries = 1;
+	penum->unk.pOnFinalRelease = QUARTZ_DestroyEnumUnknown;
+
+	*ppobj = (void*)(&penum->enumunk);
+
+	return S_OK;
+}
+
diff --git a/dlls/quartz/enumunk.h b/dlls/quartz/enumunk.h
new file mode 100644
index 00000000000..ca7dbf10b32
--- /dev/null
+++ b/dlls/quartz/enumunk.h
@@ -0,0 +1,16 @@
+/*
+ * Implementation of IEnumUnknown (for internal use).
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#ifndef	QUARTZ_ENUMUNK_H
+#define	QUARTZ_ENUMUNK_H
+
+#include "complist.h"
+
+HRESULT QUARTZ_CreateEnumUnknown(
+	REFIID riidEnum, void** ppobj, const QUARTZ_CompList* pCompList );
+
+
+#endif	/* QUARTZ_ENUMUNK_H */
diff --git a/dlls/quartz/fgclsid.c b/dlls/quartz/fgclsid.c
new file mode 100644
index 00000000000..b66609c8158
--- /dev/null
+++ b/dlls/quartz/fgclsid.c
@@ -0,0 +1,97 @@
+/*
+ * Implementation of IPersist for FilterGraph.
+ *
+ * FIXME - stub.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "wine/obj_oleaut.h"
+#include "strmif.h"
+#include "control.h"
+#include "uuids.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "fgraph.h"
+
+
+
+static HRESULT WINAPI
+IPersist_fnQueryInterface(IPersist* iface,REFIID riid,void** ppobj)
+{
+	CFilterGraph_THIS(iface,persist);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IPersist_fnAddRef(IPersist* iface)
+{
+	CFilterGraph_THIS(iface,persist);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IPersist_fnRelease(IPersist* iface)
+{
+	CFilterGraph_THIS(iface,persist);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+
+static HRESULT WINAPI
+IPersist_fnGetClassID(IPersist* iface,CLSID* pclsid)
+{
+	CFilterGraph_THIS(iface,persist);
+
+	TRACE("(%p)->()\n",This);
+
+	if ( pclsid == NULL )
+		return E_POINTER;
+	memcpy( pclsid, &CLSID_FilterGraph, sizeof(CLSID) );
+
+	return E_NOTIMPL;
+}
+
+
+static ICOM_VTABLE(IPersist) ipersist =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	IPersist_fnQueryInterface,
+	IPersist_fnAddRef,
+	IPersist_fnRelease,
+	/* IPersist fields */
+	IPersist_fnGetClassID,
+};
+
+HRESULT CFilterGraph_InitIPersist( CFilterGraph* pfg )
+{
+	TRACE("(%p)\n",pfg);
+	ICOM_VTBL(&pfg->persist) = &ipersist;
+
+	return NOERROR;
+}
+
+void CFilterGraph_UninitIPersist( CFilterGraph* pfg )
+{
+	TRACE("(%p)\n",pfg);
+}
diff --git a/dlls/quartz/fgidisp.c b/dlls/quartz/fgidisp.c
new file mode 100644
index 00000000000..cebaa82a17f
--- /dev/null
+++ b/dlls/quartz/fgidisp.c
@@ -0,0 +1,128 @@
+/*
+ * Implementation of IDispatch for FilterGraph.
+ *
+ * FIXME - stub.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "wine/obj_oleaut.h"
+#include "strmif.h"
+#include "control.h"
+#include "uuids.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "fgraph.h"
+
+
+
+static HRESULT WINAPI
+IDispatch_fnQueryInterface(IDispatch* iface,REFIID riid,void** ppobj)
+{
+	CFilterGraph_THIS(iface,disp);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IDispatch_fnAddRef(IDispatch* iface)
+{
+	CFilterGraph_THIS(iface,disp);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IDispatch_fnRelease(IDispatch* iface)
+{
+	CFilterGraph_THIS(iface,disp);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+static HRESULT WINAPI
+IDispatch_fnGetTypeInfoCount(IDispatch* iface,UINT* pcTypeInfo)
+{
+	CFilterGraph_THIS(iface,disp);
+
+	FIXME("(%p)->()\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IDispatch_fnGetTypeInfo(IDispatch* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
+{
+	CFilterGraph_THIS(iface,disp);
+
+	FIXME("(%p)->()\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IDispatch_fnGetIDsOfNames(IDispatch* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
+{
+	CFilterGraph_THIS(iface,disp);
+
+	FIXME("(%p)->()\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IDispatch_fnInvoke(IDispatch* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
+{
+	CFilterGraph_THIS(iface,disp);
+
+	FIXME("(%p)->()\n",This);
+
+	return E_NOTIMPL;
+}
+
+
+
+static ICOM_VTABLE(IDispatch) idispatch =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	IDispatch_fnQueryInterface,
+	IDispatch_fnAddRef,
+	IDispatch_fnRelease,
+	/* IDispatch fields */
+	IDispatch_fnGetTypeInfoCount,
+	IDispatch_fnGetTypeInfo,
+	IDispatch_fnGetIDsOfNames,
+	IDispatch_fnInvoke,
+};
+
+
+HRESULT CFilterGraph_InitIDispatch( CFilterGraph* pfg )
+{
+	TRACE("(%p)\n",pfg);
+	ICOM_VTBL(&pfg->disp) = &idispatch;
+
+	return NOERROR;
+}
+
+void CFilterGraph_UninitIDispatch( CFilterGraph* pfg )
+{
+	TRACE("(%p)\n",pfg);
+}
+
diff --git a/dlls/quartz/fgraph.c b/dlls/quartz/fgraph.c
index 3889fa87f89..29ff724ca97 100644
--- a/dlls/quartz/fgraph.c
+++ b/dlls/quartz/fgraph.c
@@ -1,8 +1,6 @@
 /*
  * Implementation of CLSID_FilterGraph.
  *
- * FIXME - stub.
- *
  * hidenori@a2.ctktv.ne.jp
  */
 
@@ -27,12 +25,17 @@ DEFAULT_DEBUG_CHANNEL(quartz);
 /* can I use offsetof safely? - FIXME? */
 static QUARTZ_IFEntry IFEntries[] =
 {
+  { &IID_IPersist, offsetof(CFilterGraph,persist)-offsetof(CFilterGraph,unk) },
+  { &IID_IDispatch, offsetof(CFilterGraph,disp)-offsetof(CFilterGraph,unk) },
   { &IID_IFilterGraph, offsetof(CFilterGraph,fgraph)-offsetof(CFilterGraph,unk) },
   { &IID_IGraphBuilder, offsetof(CFilterGraph,fgraph)-offsetof(CFilterGraph,unk) },
   { &IID_IFilterGraph2, offsetof(CFilterGraph,fgraph)-offsetof(CFilterGraph,unk) },
+  { &IID_IGraphVersion, offsetof(CFilterGraph,graphversion)-offsetof(CFilterGraph,unk) },
   { &IID_IMediaControl, offsetof(CFilterGraph,mediacontrol)-offsetof(CFilterGraph,unk) },
+  { &IID_IMediaFilter, offsetof(CFilterGraph,mediafilter)-offsetof(CFilterGraph,unk) },
   { &IID_IMediaEvent, offsetof(CFilterGraph,mediaevent)-offsetof(CFilterGraph,unk) },
   { &IID_IMediaEventEx, offsetof(CFilterGraph,mediaevent)-offsetof(CFilterGraph,unk) },
+  { &IID_IMediaEventSink, offsetof(CFilterGraph,mediaeventsink)-offsetof(CFilterGraph,unk) },
   { &IID_IMediaPosition, offsetof(CFilterGraph,mediaposition)-offsetof(CFilterGraph,unk) },
   { &IID_IMediaSeeking, offsetof(CFilterGraph,mediaseeking)-offsetof(CFilterGraph,unk) },
   { &IID_IBasicVideo, offsetof(CFilterGraph,basvid)-offsetof(CFilterGraph,unk) },
@@ -42,23 +45,55 @@ static QUARTZ_IFEntry IFEntries[] =
 };
 
 
+struct FGInitEntry
+{
+	HRESULT (*pInit)(CFilterGraph*);
+	void (*pUninit)(CFilterGraph*);
+};
+
+static const struct FGInitEntry FGRAPH_Init[] =
+{
+	#define	FGENT(a)	{&CFilterGraph_Init##a,&CFilterGraph_Uninit##a},
+
+	FGENT(IPersist)
+	FGENT(IDispatch)
+	FGENT(IFilterGraph2)
+	FGENT(IGraphVersion)
+	FGENT(IMediaControl)
+	FGENT(IMediaFilter)
+	FGENT(IMediaEventEx)
+	FGENT(IMediaEventSink)
+	FGENT(IMediaPosition)
+	FGENT(IMediaSeeking)
+	FGENT(IBasicVideo2)
+	FGENT(IBasicAudio)
+	FGENT(IVideoWindow)
+
+	#undef	FGENT
+	{ NULL, NULL },
+};
+
+
 static void QUARTZ_DestroyFilterGraph(IUnknown* punk)
 {
 	CFilterGraph_THIS(punk,unk);
+	int	i;
 
-	CFilterGraph_UninitIFilterGraph2( This );
-	CFilterGraph_UninitIMediaControl( This );
-	CFilterGraph_UninitIMediaEventEx( This );
-	CFilterGraph_UninitIMediaPosition( This );
-	CFilterGraph_UninitIMediaSeeking( This );
-	CFilterGraph_UninitIBasicVideo2( This );
-	CFilterGraph_UninitIBasicAudio( This );
-	CFilterGraph_UninitIVideoWindow( This );
+	i = 0;
+	while ( FGRAPH_Init[i].pInit != NULL )
+	{
+		FGRAPH_Init[i].pUninit( This );
+		i++;
+	}
+
+	TRACE( "succeeded.\n" );
 }
 
 HRESULT QUARTZ_CreateFilterGraph(IUnknown* punkOuter,void** ppobj)
 {
 	CFilterGraph*	pfg;
+	HRESULT	hr;
+	int	i;
 
 	TRACE("(%p,%p)\n",punkOuter,ppobj);
 
@@ -67,14 +102,24 @@ HRESULT QUARTZ_CreateFilterGraph(IUnknown* punkOuter,void** ppobj)
 		return E_OUTOFMEMORY;
 
 	QUARTZ_IUnkInit( &pfg->unk, punkOuter );
-	CFilterGraph_InitIFilterGraph2( pfg );
-	CFilterGraph_InitIMediaControl( pfg );
-	CFilterGraph_InitIMediaEventEx( pfg );
-	CFilterGraph_InitIMediaPosition( pfg );
-	CFilterGraph_InitIMediaSeeking( pfg );
-	CFilterGraph_InitIBasicVideo2( pfg );
-	CFilterGraph_InitIBasicAudio( pfg );
-	CFilterGraph_InitIVideoWindow( pfg );
+
+	i = 0;
+	hr = NOERROR;
+	while ( FGRAPH_Init[i].pInit != NULL )
+	{
+		hr = FGRAPH_Init[i].pInit( pfg );
+		if ( FAILED(hr) )
+			break;
+		i++;
+	}
+
+	if ( FAILED(hr) )
+	{
+		while ( --i >= 0 )
+			FGRAPH_Init[i].pUninit( pfg );
+		QUARTZ_FreeObj( pfg );
+		return hr;
+	}
 
 	pfg->unk.pEntries = IFEntries;
 	pfg->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
diff --git a/dlls/quartz/fgraph.h b/dlls/quartz/fgraph.h
index d606c11ea0e..e06551c2439 100644
--- a/dlls/quartz/fgraph.h
+++ b/dlls/quartz/fgraph.h
@@ -7,37 +7,69 @@
 	- At least, the following interfaces should be implemented:
 
 	IUnknown
+		+ IPersist
+		+ IDispatch
 		+ IFilterGraph - IGraphBuilder - IFilterGraph2
+		+ IGraphVersion
 		+ IDispatch - IMediaControl
+		+ IPersist - IMediaFilter
 		+ IDispatch - IMediaEvent - IMediaEventEx
+		+ IMediaEventSink
 		+ IDispatch - IMediaPosition
 		+ IMediaSeeking
-		+ IDispatch - IBasicVideo (pass to a renderer)
+		+ IDispatch - IBasicVideo[2] (pass to a renderer)
 		+ IDispatch - IBasicAudio (pass to a renderer)
 		+ IDispatch - IVideoWindow  (pass to a renderer)
 	(following interfaces are not implemented)
-		+ IDispatch
-		+ IMediaEventSink
-		+ IGraphVerson
+		+ IMarshal
+		+ IFilterMapper2 - IFilterMapper3
+		FIXME - Are there any missing interfaces???
  */
 
 #include "iunk.h"
+#include "complist.h"
+
+
+typedef struct FG_IPersistImpl
+{
+	ICOM_VFIELD(IPersist);
+} FG_IPersistImpl;
+
+typedef struct FG_IDispatchImpl
+{
+	ICOM_VFIELD(IDispatch);
+} FG_IDispatchImpl;
 
 typedef struct FG_IFilterGraph2Impl
 {
 	ICOM_VFIELD(IFilterGraph2);
 } FG_IFilterGraph2Impl;
 
+typedef struct FG_IGraphVersionImpl
+{
+	ICOM_VFIELD(IGraphVersion);
+} FG_IGraphVersionImpl;
+
 typedef struct FG_IMediaControlImpl
 {
 	ICOM_VFIELD(IMediaControl);
 } FG_IMediaControlImpl;
 
+typedef struct FG_IMediaFilterImpl
+{
+	ICOM_VFIELD(IMediaFilter);
+} FG_IMediaFilterImpl;
+
 typedef struct FG_IMediaEventImpl
 {
 	ICOM_VFIELD(IMediaEventEx);
 } FG_IMediaEventImpl;
 
+typedef struct FG_IMediaEventSinkImpl
+{
+	ICOM_VFIELD(IMediaEventSink);
+} FG_IMediaEventSinkImpl;
+
 typedef struct FG_IMediaPositionImpl
 {
 	ICOM_VFIELD(IMediaPosition);
@@ -67,18 +99,30 @@ typedef struct FG_IVideoWindowImpl
 typedef struct CFilterGraph
 {
 	QUARTZ_IUnkImpl	unk;
+	FG_IPersistImpl	persist;
+	FG_IDispatchImpl	disp;
 	FG_IFilterGraph2Impl	fgraph;
+	FG_IGraphVersionImpl	graphversion;
 	FG_IMediaControlImpl	mediacontrol;
+	FG_IMediaFilterImpl	mediafilter;
 	FG_IMediaEventImpl	mediaevent;
+	FG_IMediaEventSinkImpl	mediaeventsink;
 	FG_IMediaPositionImpl	mediaposition;
 	FG_IMediaSeekingImpl	mediaseeking;
 	FG_IBasicVideoImpl	basvid;
 	FG_IBasicAudioImpl	basaud;
 	FG_IVideoWindowImpl	vidwin;
 
+	/* IDispatch fields. */
 	/* IFilterGraph2 fields. */
+	QUARTZ_CompList*	m_pFilterList;
+	/* IGraphVersion fields. */
+	CRITICAL_SECTION	m_csGraphVersion;
+	LONG	m_lGraphVersion;
 	/* IMediaControl fields. */
 	/* IMediaEvent fields. */
+	HANDLE	m_hMediaEvent;
+	/* IMediaEventSink fields. */
 	/* IMediaPosition fields. */
 	/* IMediaSeeking fields. */
 	/* IBasicVideo2 fields. */
@@ -87,24 +131,36 @@ typedef struct CFilterGraph
 } CFilterGraph;
 
 #define	CFilterGraph_THIS(iface,member)		CFilterGraph*	This = ((CFilterGraph*)(((char*)iface)-offsetof(CFilterGraph,member)))
+#define	CFilterGraph_IPersist(th)		((IPersist*)&((th)->persist))
+#define	CFilterGraph_IDispatch(th)		((IDispatch*)&((th)->disp))
 
 HRESULT QUARTZ_CreateFilterGraph(IUnknown* punkOuter,void** ppobj);
 
-void CFilterGraph_InitIFilterGraph2( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIPersist( CFilterGraph* pfg );
+void CFilterGraph_UninitIPersist( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIDispatch( CFilterGraph* pfg );
+void CFilterGraph_UninitIDispatch( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIFilterGraph2( CFilterGraph* pfg );
 void CFilterGraph_UninitIFilterGraph2( CFilterGraph* pfg );
-void CFilterGraph_InitIMediaControl( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIGraphVersion( CFilterGraph* pfg );
+void CFilterGraph_UninitIGraphVersion( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIMediaControl( CFilterGraph* pfg );
 void CFilterGraph_UninitIMediaControl( CFilterGraph* pfg );
-void CFilterGraph_InitIMediaEventEx( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIMediaFilter( CFilterGraph* pfg );
+void CFilterGraph_UninitIMediaFilter( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIMediaEventEx( CFilterGraph* pfg );
 void CFilterGraph_UninitIMediaEventEx( CFilterGraph* pfg );
-void CFilterGraph_InitIMediaPosition( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIMediaEventSink( CFilterGraph* pfg );
+void CFilterGraph_UninitIMediaEventSink( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIMediaPosition( CFilterGraph* pfg );
 void CFilterGraph_UninitIMediaPosition( CFilterGraph* pfg );
-void CFilterGraph_InitIMediaSeeking( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIMediaSeeking( CFilterGraph* pfg );
 void CFilterGraph_UninitIMediaSeeking( CFilterGraph* pfg );
-void CFilterGraph_InitIBasicVideo2( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIBasicVideo2( CFilterGraph* pfg );
 void CFilterGraph_UninitIBasicVideo2( CFilterGraph* pfg );
-void CFilterGraph_InitIBasicAudio( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIBasicAudio( CFilterGraph* pfg );
 void CFilterGraph_UninitIBasicAudio( CFilterGraph* pfg );
-void CFilterGraph_InitIVideoWindow( CFilterGraph* pfg );
+HRESULT CFilterGraph_InitIVideoWindow( CFilterGraph* pfg );
 void CFilterGraph_UninitIVideoWindow( CFilterGraph* pfg );
 
 
diff --git a/dlls/quartz/fmap.c b/dlls/quartz/fmap.c
index e588f7c0d45..2853b25e50a 100644
--- a/dlls/quartz/fmap.c
+++ b/dlls/quartz/fmap.c
@@ -41,6 +41,7 @@ static void QUARTZ_DestroyFilterMapper(IUnknown* punk)
 HRESULT QUARTZ_CreateFilterMapper(IUnknown* punkOuter,void** ppobj)
 {
 	CFilterMapper*	pfm;
+	HRESULT	hr;
 
 	TRACE("(%p,%p)\n",punkOuter,ppobj);
 
@@ -49,7 +50,12 @@ HRESULT QUARTZ_CreateFilterMapper(IUnknown* punkOuter,void** ppobj)
 		return E_OUTOFMEMORY;
 
 	QUARTZ_IUnkInit( &pfm->unk, punkOuter );
-	CFilterMapper_InitIFilterMapper( pfm );
+	hr = CFilterMapper_InitIFilterMapper( pfm );
+	if ( FAILED(hr) )
+	{
+		QUARTZ_FreeObj( pfm );
+		return hr;
+	}
 
 	pfm->unk.pEntries = IFEntries;
 	pfm->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
diff --git a/dlls/quartz/fmap.h b/dlls/quartz/fmap.h
index 353898153f7..c21cc2e8076 100644
--- a/dlls/quartz/fmap.h
+++ b/dlls/quartz/fmap.h
@@ -29,7 +29,7 @@ typedef struct CFilterMapper
 HRESULT QUARTZ_CreateFilterMapper(IUnknown* punkOuter,void** ppobj);
 
 
-void CFilterMapper_InitIFilterMapper( CFilterMapper* pfm );
+HRESULT CFilterMapper_InitIFilterMapper( CFilterMapper* pfm );
 void CFilterMapper_UninitIFilterMapper( CFilterMapper* pfm );
 
 
diff --git a/dlls/quartz/fmap2.c b/dlls/quartz/fmap2.c
index ff3271792b2..96c6a9b985c 100644
--- a/dlls/quartz/fmap2.c
+++ b/dlls/quartz/fmap2.c
@@ -42,6 +42,7 @@ static void QUARTZ_DestroyFilterMapper2(IUnknown* punk)
 HRESULT QUARTZ_CreateFilterMapper2(IUnknown* punkOuter,void** ppobj)
 {
 	CFilterMapper2*	pfm;
+	HRESULT	hr;
 
 	TRACE("(%p,%p)\n",punkOuter,ppobj);
 
@@ -50,7 +51,12 @@ HRESULT QUARTZ_CreateFilterMapper2(IUnknown* punkOuter,void** ppobj)
 		return E_OUTOFMEMORY;
 
 	QUARTZ_IUnkInit( &pfm->unk, punkOuter );
-	CFilterMapper2_InitIFilterMapper3( pfm );
+	hr = CFilterMapper2_InitIFilterMapper3( pfm );
+	if ( FAILED(hr) )
+	{
+		QUARTZ_FreeObj( pfm );
+		return hr;
+	}
 
 	pfm->unk.pEntries = IFEntries;
 	pfm->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
diff --git a/dlls/quartz/fmap2.h b/dlls/quartz/fmap2.h
index 0ee05a1e5b4..6cf7718c577 100644
--- a/dlls/quartz/fmap2.h
+++ b/dlls/quartz/fmap2.h
@@ -22,6 +22,7 @@ typedef struct CFilterMapper2
 {
 	QUARTZ_IUnkImpl	unk;
 	FM2_IFilterMapper3Impl	fmap3;
+	/* IFilterMapper3 fields */
 } CFilterMapper2;
 
 #define	CFilterMapper2_THIS(iface,member)		CFilterMapper2*	This = ((CFilterMapper2*)(((char*)iface)-offsetof(CFilterMapper2,member)))
@@ -29,7 +30,7 @@ typedef struct CFilterMapper2
 HRESULT QUARTZ_CreateFilterMapper2(IUnknown* punkOuter,void** ppobj);
 
 
-void CFilterMapper2_InitIFilterMapper3( CFilterMapper2* psde );
+HRESULT CFilterMapper2_InitIFilterMapper3( CFilterMapper2* psde );
 void CFilterMapper2_UninitIFilterMapper3( CFilterMapper2* psde );
 
 
diff --git a/dlls/quartz/ibasaud.c b/dlls/quartz/ibasaud.c
index fbfe7828626..643a75a5c59 100644
--- a/dlls/quartz/ibasaud.c
+++ b/dlls/quartz/ibasaud.c
@@ -158,10 +158,12 @@ static ICOM_VTABLE(IBasicAudio) ibasicaudio =
 };
 
 
-void CFilterGraph_InitIBasicAudio( CFilterGraph* pfg )
+HRESULT CFilterGraph_InitIBasicAudio( CFilterGraph* pfg )
 {
 	TRACE("(%p)\n",pfg);
 	ICOM_VTBL(&pfg->basaud) = &ibasicaudio;
+
+	return NOERROR;
 }
 
 void CFilterGraph_UninitIBasicAudio( CFilterGraph* pfg )
diff --git a/dlls/quartz/ibasvid.c b/dlls/quartz/ibasvid.c
index 3915b1be69c..44843c34d38 100644
--- a/dlls/quartz/ibasvid.c
+++ b/dlls/quartz/ibasvid.c
@@ -479,10 +479,12 @@ static ICOM_VTABLE(IBasicVideo2) ibasicvideo =
 };
 
 
-void CFilterGraph_InitIBasicVideo2( CFilterGraph* pfg )
+HRESULT CFilterGraph_InitIBasicVideo2( CFilterGraph* pfg )
 {
 	TRACE("(%p)\n",pfg);
 	ICOM_VTBL(&pfg->basvid) = &ibasicvideo;
+
+	return NOERROR;
 }
 
 void CFilterGraph_UninitIBasicVideo2( CFilterGraph* pfg )
diff --git a/dlls/quartz/idevenum.c b/dlls/quartz/idevenum.c
index cf62c15a082..5c644bebb14 100644
--- a/dlls/quartz/idevenum.c
+++ b/dlls/quartz/idevenum.c
@@ -11,18 +11,28 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
+#include "winuser.h"
+#include "winreg.h"
 #include "winerror.h"
 #include "wine/obj_base.h"
-#include "wine/obj_oleaut.h"
+#include "objidl.h"
+#include "oleidl.h"
+#include "ocidl.h"
 #include "strmif.h"
 #include "control.h"
 #include "uuids.h"
+#include "wine/unicode.h"
 
 #include "debugtools.h"
 DEFAULT_DEBUG_CHANNEL(quartz);
 
 #include "quartz_private.h"
 #include "devenum.h"
+#include "regsvr.h"
+#include "enumunk.h"
+#include "complist.h"
+#include "devmon.h"
+
 
 static HRESULT WINAPI
 ICreateDevEnum_fnQueryInterface(ICreateDevEnum* iface,REFIID riid,void** ppobj)
@@ -58,10 +68,95 @@ static HRESULT WINAPI
 ICreateDevEnum_fnCreateClassEnumerator(ICreateDevEnum* iface,REFCLSID rclsidDeviceClass,IEnumMoniker** ppobj, DWORD dwFlags)
 {
 	CSysDevEnum_THIS(iface,createdevenum);
-
-	FIXME("(%p)->() stub!\n",This);
-
-	return E_NOTIMPL;
+	HRESULT	hr;
+	HKEY	hKey;
+	QUARTZ_CompList*	pMonList;
+	IMoniker*	pMon;
+	DWORD	dwIndex;
+	LONG	lr;
+	WCHAR	wszPath[ 1024 ];
+	DWORD	dwLen;
+	DWORD	dwNameMax;
+	DWORD	cbName;
+	FILETIME	ftLastWrite;
+
+	TRACE("(%p)->(%s,%p,%08lx)\n",This,
+		debugstr_guid(rclsidDeviceClass),ppobj,dwFlags);
+	if ( dwFlags != 0 )
+	{
+		FIXME("unknown flags %08lx\n",dwFlags);
+		return E_NOTIMPL;
+	}
+
+	if ( ppobj == NULL )
+		return E_POINTER;
+	*ppobj = NULL;
+
+	hr = QUARTZ_CreateCLSIDPath(
+		wszPath, sizeof(wszPath)/sizeof(wszPath[0]),
+		rclsidDeviceClass, QUARTZ_wszInstance );
+	if ( FAILED(hr) )
+		return hr;
+
+	if ( RegOpenKeyExW( HKEY_CLASSES_ROOT, wszPath,
+		0, KEY_READ, &hKey ) != ERROR_SUCCESS )
+		return E_FAIL;
+
+	dwLen = strlenW(wszPath);
+	wszPath[dwLen++] = '\\'; wszPath[dwLen] = 0;
+	dwNameMax = sizeof(wszPath)/sizeof(wszPath[0]) - dwLen - 8;
+
+	pMonList = QUARTZ_CompList_Alloc();
+	if ( pMonList == NULL )
+	{
+		hr = E_OUTOFMEMORY;
+		goto err;
+	}
+
+	/* enumerate all subkeys. */
+	dwIndex = 0;
+	while ( 1 )
+	{
+		cbName = dwNameMax;
+		lr = RegEnumKeyExW(
+			hKey, dwIndex, &wszPath[dwLen], &cbName,
+			NULL, NULL, NULL, &ftLastWrite );
+		if ( lr == ERROR_NO_MORE_ITEMS )
+			break;
+		if ( lr != ERROR_SUCCESS )
+		{
+			hr = E_FAIL;
+			goto err;
+		}
+
+		hr = QUARTZ_CreateDeviceMoniker(
+			HKEY_CLASSES_ROOT, wszPath, &pMon );
+		if ( FAILED(hr) )
+			goto err;
+
+		hr = QUARTZ_CompList_AddComp(
+			pMonList, (IUnknown*)pMon, NULL, 0 );
+		IMoniker_Release( pMon );
+
+		if ( FAILED(hr) )
+			goto err;
+
+		dwIndex ++;
+	}
+
+	/* create an enumerator. */
+	hr = QUARTZ_CreateEnumUnknown(
+		&IID_IEnumMoniker, (void**)ppobj, pMonList );
+	if ( FAILED(hr) )
+		goto err;
+
+	hr = S_OK;
+err:
+	if ( pMonList != NULL )
+		QUARTZ_CompList_Free( pMonList );
+	RegCloseKey( hKey );
+
+	return hr;
 }
 
 static ICOM_VTABLE(ICreateDevEnum) icreatedevenum =
@@ -75,10 +170,12 @@ static ICOM_VTABLE(ICreateDevEnum) icreatedevenum =
 	ICreateDevEnum_fnCreateClassEnumerator,
 };
 
-void CSysDevEnum_InitICreateDevEnum( CSysDevEnum* psde )
+HRESULT CSysDevEnum_InitICreateDevEnum( CSysDevEnum* psde )
 {
 	TRACE("(%p)\n",psde);
 	ICOM_VTBL(&psde->createdevenum) = &icreatedevenum;
+
+	return NOERROR;
 }
 
 void CSysDevEnum_UninitICreateDevEnum( CSysDevEnum* psde )
diff --git a/dlls/quartz/ifgraph.c b/dlls/quartz/ifgraph.c
index a6ef7d7f7a6..43565d02064 100644
--- a/dlls/quartz/ifgraph.c
+++ b/dlls/quartz/ifgraph.c
@@ -18,12 +18,63 @@
 #include "strmif.h"
 #include "control.h"
 #include "uuids.h"
+#include "vfwmsgs.h"
+#include "wine/unicode.h"
 
 #include "debugtools.h"
 DEFAULT_DEBUG_CHANNEL(quartz);
 
 #include "quartz_private.h"
 #include "fgraph.h"
+#include "enumunk.h"
+
+
+static HRESULT CFilterGraph_DisconnectAllPins( IBaseFilter* pFilter )
+{
+	IEnumPins*	pEnum = NULL;
+	IPin*	pPin;
+	IPin*	pConnTo;
+	ULONG	cFetched;
+	HRESULT	hr;
+
+	hr = IBaseFilter_EnumPins( pFilter, &pEnum );
+	if ( FAILED(hr) )
+		return hr;
+	if ( pEnum == NULL )
+		return E_FAIL;
+
+	while ( 1 )
+	{
+		pPin = NULL;
+		cFetched = 0;
+		hr = IEnumPins_Next( pEnum, 1, &pPin, &cFetched );
+		if ( FAILED(hr) )
+			break;
+		if ( hr != NOERROR || pPin == NULL || cFetched != 1 )
+		{
+			hr = NOERROR;
+			break;
+		}
+
+		pConnTo = NULL;
+		hr = IPin_ConnectedTo(pPin,&pConnTo);
+		if ( hr == NOERROR && pConnTo != NULL )
+		{
+			IPin_Disconnect(pPin);
+			IPin_Disconnect(pConnTo);
+			IPin_Release(pConnTo);
+		}
+
+		IPin_Release( pPin );
+	}
+
+	IEnumPins_Release( pEnum );
+
+	return hr;
+}
+
+
+/****************************************************************************/
 
 static HRESULT WINAPI
 IFilterGraph2_fnQueryInterface(IFilterGraph2* iface,REFIID riid,void** ppobj)
@@ -59,45 +110,272 @@ static HRESULT WINAPI
 IFilterGraph2_fnAddFilter(IFilterGraph2* iface,IBaseFilter* pFilter, LPCWSTR pName)
 {
 	CFilterGraph_THIS(iface,fgraph);
-
-	FIXME( "(%p)->() stub!\n", This );
-	return E_NOTIMPL;
+	FILTER_INFO	info;
+	HRESULT	hr;
+	HRESULT	hrSucceeded = S_OK;
+	QUARTZ_CompListItem*	pItem;
+	int i,iLen;
+
+	TRACE( "(%p)->(%p,%s)\n",This,pFilter,debugstr_w(pName) );
+
+	QUARTZ_CompList_Lock( This->m_pFilterList );
+
+	if ( pName != NULL )
+	{
+		pItem = QUARTZ_CompList_SearchData(
+			This->m_pFilterList,
+			pName, sizeof(WCHAR)*(strlenW(pName)+1) );
+		if ( pItem == NULL )
+			goto name_ok;
+
+		hrSucceeded = VFW_S_DUPLICATE_NAME;
+
+		iLen = strlenW(pName);
+		if ( iLen > 32 )
+			iLen = 32;
+		memcpy( info.achName, pName, sizeof(WCHAR)*iLen );
+		info.achName[iLen] = 0;
+	}
+	else
+	{
+		ZeroMemory( &info, sizeof(info) );
+		hr = IBaseFilter_QueryFilterInfo( pFilter, &info );
+		if ( FAILED(hr) )
+			goto end;
+
+		iLen = strlenW(info.achName);
+		pItem = QUARTZ_CompList_SearchData(
+			This->m_pFilterList,
+			info.achName, sizeof(WCHAR)*(iLen+1) );
+		if ( pItem == NULL )
+		{
+			pName = info.achName;
+			goto name_ok;
+		}
+	}
+
+	/* generate modified names for this filter.. */
+	iLen = strlenW(info.achName);
+	if ( iLen > 32 )
+		iLen = 32;
+	info.achName[iLen++] = ' ';
+
+	for ( i = 0; i <= 99; i++ )
+	{
+		info.achName[iLen+0] = (i%10) + '0';
+		info.achName[iLen+1] = ((i/10)%10) + '0';
+		info.achName[iLen+2] = 0;
+		pItem = QUARTZ_CompList_SearchData(
+			This->m_pFilterList,
+			info.achName, sizeof(WCHAR)*(iLen+3) );
+		if ( pItem == NULL )
+		{
+			pName = info.achName;
+			goto name_ok;
+		}
+	}
+
+	hr = ( pName == NULL ) ? E_FAIL : VFW_E_DUPLICATE_NAME;
+	goto end;
+
+name_ok:
+	/* register this filter. */
+	hr = QUARTZ_CompList_AddComp(
+		This->m_pFilterList, (IUnknown*)pFilter,
+		pName, sizeof(WCHAR)*(strlenW(pName)+1) );
+	if ( FAILED(hr) )
+		goto end;
+
+	hr = IBaseFilter_JoinFilterGraph(pFilter,(IFilterGraph*)iface,pName);
+	if ( FAILED(hr) )
+	{
+		QUARTZ_CompList_RemoveComp(
+			This->m_pFilterList,(IUnknown*)pFilter);
+		goto end;
+	}
+
+	EnterCriticalSection( &This->m_csGraphVersion );
+	This->m_lGraphVersion ++;
+	LeaveCriticalSection( &This->m_csGraphVersion );
+
+	hr = hrSucceeded;
+end:
+	QUARTZ_CompList_Unlock( This->m_pFilterList );
+
+	return hr;
 }
 
 static HRESULT WINAPI
 IFilterGraph2_fnRemoveFilter(IFilterGraph2* iface,IBaseFilter* pFilter)
 {
 	CFilterGraph_THIS(iface,fgraph);
+	QUARTZ_CompListItem*	pItem;
+	HRESULT	hr = NOERROR;
 
-	FIXME( "(%p)->() stub!\n", This );
-	return E_NOTIMPL;
+	TRACE( "(%p)->(%p)\n",This,pFilter );
+
+	QUARTZ_CompList_Lock( This->m_pFilterList );
+
+	pItem = QUARTZ_CompList_SearchComp(
+		This->m_pFilterList, (IUnknown*)pFilter );
+	if ( pItem != NULL )
+	{
+		CFilterGraph_DisconnectAllPins(pFilter);
+		hr = IBaseFilter_JoinFilterGraph(
+			pFilter, NULL, QUARTZ_CompList_GetDataPtr(pItem) );
+		QUARTZ_CompList_RemoveComp(
+			This->m_pFilterList, (IUnknown*)pFilter );
+	}
+
+	EnterCriticalSection( &This->m_csGraphVersion );
+	This->m_lGraphVersion ++;
+	LeaveCriticalSection( &This->m_csGraphVersion );
+
+	QUARTZ_CompList_Unlock( This->m_pFilterList );
+
+	return hr;
 }
 
 static HRESULT WINAPI
 IFilterGraph2_fnEnumFilters(IFilterGraph2* iface,IEnumFilters** ppEnum)
 {
 	CFilterGraph_THIS(iface,fgraph);
+	HRESULT	hr;
 
-	FIXME( "(%p)->() stub!\n", This );
-	return E_NOTIMPL;
+	TRACE( "(%p)->(%p)\n",This,ppEnum );
+
+	QUARTZ_CompList_Lock( This->m_pFilterList );
+
+	hr = QUARTZ_CreateEnumUnknown(
+		&IID_IEnumFilters, (void**)ppEnum, This->m_pFilterList );
+
+	QUARTZ_CompList_Unlock( This->m_pFilterList );
+
+	return hr;
 }
 
 static HRESULT WINAPI
 IFilterGraph2_fnFindFilterByName(IFilterGraph2* iface,LPCWSTR pName,IBaseFilter** ppFilter)
 {
 	CFilterGraph_THIS(iface,fgraph);
+	QUARTZ_CompListItem*	pItem;
+	HRESULT	hr = E_FAIL;
 
-	FIXME( "(%p)->() stub!\n", This );
-	return E_NOTIMPL;
+	TRACE( "(%p)->(%s,%p)\n",This,debugstr_w(pName),ppFilter );
+
+	if ( ppFilter == NULL )
+		return E_POINTER;
+	*ppFilter = NULL;
+
+	QUARTZ_CompList_Lock( This->m_pFilterList );
+
+	pItem = QUARTZ_CompList_SearchData(
+		This->m_pFilterList,
+		pName, sizeof(WCHAR)*(strlenW(pName)+1) );
+	if ( pItem != NULL )
+	{
+		*ppFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr(pItem);
+		hr = NOERROR;
+	}
+
+	QUARTZ_CompList_Unlock( This->m_pFilterList );
+
+	return hr;
 }
 
 static HRESULT WINAPI
 IFilterGraph2_fnConnectDirect(IFilterGraph2* iface,IPin* pOut,IPin* pIn,const AM_MEDIA_TYPE* pmt)
 {
 	CFilterGraph_THIS(iface,fgraph);
-
-	FIXME( "(%p)->() stub!\n", This );
-	return E_NOTIMPL;
+	IPin*	pConnTo;
+	PIN_INFO	infoIn;
+	PIN_INFO	infoOut;
+	FILTER_INFO	finfoIn;
+	FILTER_INFO	finfoOut;
+	HRESULT	hr;
+
+	TRACE( "(%p)->(%p,%p,%p)\n",This,pOut,pIn,pmt );
+
+	infoIn.pFilter = NULL;
+	infoOut.pFilter = NULL;
+	finfoIn.pGraph = NULL;
+	finfoOut.pGraph = NULL;
+
+	QUARTZ_CompList_Lock( This->m_pFilterList );
+
+	hr = IPin_QueryPinInfo(pIn,&infoIn);
+	if ( FAILED(hr) )
+		goto end;
+	hr = IPin_QueryPinInfo(pOut,&infoOut);
+	if ( FAILED(hr) )
+		goto end;
+	if ( infoIn.pFilter == NULL || infoOut.pFilter == NULL ||
+		 infoIn.dir != PINDIR_INPUT || infoOut.dir != PINDIR_OUTPUT )
+	{
+		hr = E_FAIL;
+		goto end;
+	}
+
+	hr = IBaseFilter_QueryFilterInfo(infoIn.pFilter,&finfoIn);
+	if ( FAILED(hr) )
+		goto end;
+	hr = IBaseFilter_QueryFilterInfo(infoOut.pFilter,&finfoOut);
+	if ( FAILED(hr) )
+		goto end;
+	if ( finfoIn.pGraph != ((IFilterGraph*)iface) ||
+		 finfoOut.pGraph != ((IFilterGraph*)iface) )
+	{
+		hr = E_FAIL;
+		goto end;
+	}
+
+	pConnTo = NULL;
+	hr = IPin_ConnectedTo(pIn,&pConnTo);
+	if ( FAILED(hr) )
+		goto end;
+	if ( pConnTo != NULL )
+	{
+		IPin_Release(pConnTo);
+		goto end;
+	}
+
+	pConnTo = NULL;
+	hr = IPin_ConnectedTo(pOut,&pConnTo);
+	if ( FAILED(hr) )
+		goto end;
+	if ( pConnTo != NULL )
+	{
+		IPin_Release(pConnTo);
+		goto end;
+	}
+
+	hr = IPin_Connect(pIn,pOut,pmt);
+	if ( FAILED(hr) )
+		goto end;
+	hr = IPin_Connect(pOut,pIn,pmt);
+	if ( FAILED(hr) )
+	{
+		IPin_Disconnect(pIn);
+		goto end;
+	}
+
+	EnterCriticalSection( &This->m_csGraphVersion );
+	This->m_lGraphVersion ++;
+	LeaveCriticalSection( &This->m_csGraphVersion );
+
+end:
+	QUARTZ_CompList_Unlock( This->m_pFilterList );
+
+	if ( infoIn.pFilter != NULL )
+		IBaseFilter_Release(infoIn.pFilter);
+	if ( infoOut.pFilter != NULL )
+		IBaseFilter_Release(infoOut.pFilter);
+	if ( finfoIn.pGraph != NULL )
+		IFilterGraph_Release(finfoIn.pGraph);
+	if ( finfoOut.pGraph != NULL )
+		IFilterGraph_Release(finfoOut.pGraph);
+
+	return hr;
 }
 
 static HRESULT WINAPI
@@ -105,7 +383,12 @@ IFilterGraph2_fnReconnect(IFilterGraph2* iface,IPin* pPin)
 {
 	CFilterGraph_THIS(iface,fgraph);
 
-	FIXME( "(%p)->() stub!\n", This );
+	FIXME( "(%p)->(%p) stub!\n",This,pPin );
+
+	EnterCriticalSection( &This->m_csGraphVersion );
+	This->m_lGraphVersion ++;
+	LeaveCriticalSection( &This->m_csGraphVersion );
+
 	return E_NOTIMPL;
 }
 
@@ -114,7 +397,12 @@ IFilterGraph2_fnDisconnect(IFilterGraph2* iface,IPin* pPin)
 {
 	CFilterGraph_THIS(iface,fgraph);
 
-	FIXME( "(%p)->() stub!\n", This );
+	FIXME( "(%p)->(%p) stub!\n",This,pPin );
+
+	EnterCriticalSection( &This->m_csGraphVersion );
+	This->m_lGraphVersion ++;
+	LeaveCriticalSection( &This->m_csGraphVersion );
+
 	return E_NOTIMPL;
 }
 
@@ -131,8 +419,19 @@ static HRESULT WINAPI
 IFilterGraph2_fnConnect(IFilterGraph2* iface,IPin* pOut,IPin* pIn)
 {
 	CFilterGraph_THIS(iface,fgraph);
+	HRESULT	hr;
+
+	TRACE( "(%p)->(%p,%p)\n",This,pOut,pIn );
+
+	/* At first, try to connect directly. */
+	hr = IFilterGraph_ConnectDirect(iface,pOut,pIn,NULL);
+	if ( hr == NOERROR )
+		return NOERROR;
+
+	/* FIXME - try to connect indirectly. */
+	FIXME( "(%p)->(%p,%p) stub!\n",This,pOut,pIn );
+
 
-	FIXME( "(%p)->() stub!\n", This );
 	return E_NOTIMPL;
 }
 
@@ -141,7 +440,7 @@ IFilterGraph2_fnRender(IFilterGraph2* iface,IPin* pOut)
 {
 	CFilterGraph_THIS(iface,fgraph);
 
-	FIXME( "(%p)->() stub!\n", This );
+	FIXME( "(%p)->(%p) stub!\n",This,pOut );
 	return E_NOTIMPL;
 }
 
@@ -149,9 +448,81 @@ static HRESULT WINAPI
 IFilterGraph2_fnRenderFile(IFilterGraph2* iface,LPCWSTR lpFileName,LPCWSTR lpPlayList)
 {
 	CFilterGraph_THIS(iface,fgraph);
-
-	FIXME( "(%p)->() stub!\n", This );
-	return E_NOTIMPL;
+	HRESULT	hr;
+	IBaseFilter*	pFilter = NULL;
+	IEnumPins*	pEnum = NULL;
+	IPin*	pPin;
+	ULONG	cFetched;
+	PIN_DIRECTION	dir;
+	ULONG	cTryToRender;
+	ULONG	cActRender;
+
+	TRACE( "(%p)->(%s,%s)\n",This,
+		debugstr_w(lpFileName),debugstr_w(lpPlayList) );
+
+	if ( lpPlayList != NULL )
+		return E_INVALIDARG;
+
+	pFilter = NULL;
+	hr = IFilterGraph2_AddSourceFilter(iface,lpFileName,NULL,&pFilter);
+	if ( FAILED(hr) )
+		goto end;
+	if ( pFilter == NULL )
+	{
+		hr = E_FAIL;
+		goto end;
+	}
+	pEnum = NULL;
+	hr = IBaseFilter_EnumPins( pFilter, &pEnum );
+	if ( FAILED(hr) )
+		goto end;
+	if ( pEnum == NULL )
+	{
+		hr = E_FAIL;
+		goto end;
+	}
+
+	cTryToRender = 0;
+	cActRender = 0;
+
+	while ( 1 )
+	{
+		pPin = NULL;
+		cFetched = 0;
+		hr = IEnumPins_Next( pEnum, 1, &pPin, &cFetched );
+		if ( FAILED(hr) )
+			goto end;
+		if ( hr != NOERROR || pPin == NULL || cFetched != 1 )
+		{
+			hr = NOERROR;
+			break;
+		}
+		hr = IPin_QueryDirection( pPin, &dir );
+		if ( hr == NOERROR && dir == PINDIR_OUTPUT )
+		{
+			cTryToRender ++;
+			hr = IFilterGraph2_Render( iface, pPin );
+			if ( hr == NOERROR )
+				cActRender ++;
+		}
+		IPin_Release( pPin );
+	}
+
+	if ( hr == NOERROR )
+	{
+		if ( cTryToRender > cActRender )
+			hr = VFW_S_PARTIAL_RENDER;
+		if ( cActRender == 0 )
+			hr = E_FAIL;
+	}
+
+end:
+	if ( pEnum != NULL )
+		IEnumPins_Release( pEnum );
+	if ( pFilter != NULL )
+		IBaseFilter_Release( pFilter );
+
+	return hr;
 }
 
 static HRESULT WINAPI
@@ -159,7 +530,8 @@ IFilterGraph2_fnAddSourceFilter(IFilterGraph2* iface,LPCWSTR lpFileName,LPCWSTR
 {
 	CFilterGraph_THIS(iface,fgraph);
 
-	FIXME( "(%p)->() stub!\n", This );
+	FIXME( "(%p)->(%s,%s,%p) stub!\n",This,
+		debugstr_w(lpFileName),debugstr_w(lpFilterName),ppBaseFilter );
 	return E_NOTIMPL;
 }
 
@@ -208,7 +580,12 @@ IFilterGraph2_fnReconnectEx(IFilterGraph2* iface,IPin* pPin,const AM_MEDIA_TYPE*
 {
 	CFilterGraph_THIS(iface,fgraph);
 
-	FIXME( "(%p)->() stub!\n", This );
+	FIXME( "(%p)->(%p,%p) stub!\n",This,pPin,pmt );
+
+	EnterCriticalSection( &This->m_csGraphVersion );
+	This->m_lGraphVersion ++;
+	LeaveCriticalSection( &This->m_csGraphVersion );
+
 	return E_NOTIMPL;
 }
 
@@ -218,7 +595,7 @@ IFilterGraph2_fnRenderEx(IFilterGraph2* iface,IPin* pPin,DWORD dwParam1,DWORD* p
 	CFilterGraph_THIS(iface,fgraph);
 
 	/* undoc. */
-	FIXME( "(%p)->() stub!\n", This );
+	FIXME( "(%p)->(%p,%08lx,%p) stub!\n",This,pPin,dwParam1,pdwParam2);
 	return E_NOTIMPL;
 }
 
@@ -255,13 +632,34 @@ static ICOM_VTABLE(IFilterGraph2) ifgraph =
 	IFilterGraph2_fnRenderEx,
 };
 
-void CFilterGraph_InitIFilterGraph2( CFilterGraph* pfg )
+HRESULT CFilterGraph_InitIFilterGraph2( CFilterGraph* pfg )
 {
 	TRACE("(%p)\n",pfg);
 	ICOM_VTBL(&pfg->fgraph) = &ifgraph;
+
+	pfg->m_pFilterList = QUARTZ_CompList_Alloc();
+	if ( pfg->m_pFilterList == NULL )
+		return E_OUTOFMEMORY;
+
+	return NOERROR;
 }
 
 void CFilterGraph_UninitIFilterGraph2( CFilterGraph* pfg )
 {
+	QUARTZ_CompListItem*	pItem;
+
 	TRACE("(%p)\n",pfg);
+
+	/* remove all filters... */
+	while ( 1 )
+	{
+		pItem = QUARTZ_CompList_GetFirst( pfg->m_pFilterList );
+		if ( pItem == NULL )
+			break;
+		IFilterGraph2_fnRemoveFilter(
+			(IFilterGraph2*)(&pfg->fgraph),
+			(IBaseFilter*)QUARTZ_CompList_GetItemPtr(pItem) );
+	}
+
+	QUARTZ_CompList_Free( pfg->m_pFilterList );
 }
diff --git a/dlls/quartz/ifmap.c b/dlls/quartz/ifmap.c
index 9927e16c725..8d420d0dcd9 100644
--- a/dlls/quartz/ifmap.c
+++ b/dlls/quartz/ifmap.c
@@ -11,6 +11,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
+#include "winreg.h"
 #include "winerror.h"
 #include "wine/obj_base.h"
 #include "wine/obj_oleaut.h"
@@ -23,6 +24,7 @@ DEFAULT_DEBUG_CHANNEL(quartz);
 
 #include "quartz_private.h"
 #include "fmap.h"
+#include "regsvr.h"
 
 
 static HRESULT WINAPI
@@ -61,19 +63,35 @@ IFilterMapper_fnRegisterFilter(IFilterMapper* iface,CLSID clsid,LPCWSTR lpwszNam
 {
 	CFilterMapper_THIS(iface,fmap);
 
-	TRACE("(%p)->() stub!\n",This);
+	FIXME("(%p)->(%s,%s,%08lx)\n",This,
+		debugstr_guid(&clsid),debugstr_w(lpwszName),dwMerit);
 
-	return E_NOTIMPL;
+	/* FIXME */
+	/* FIXME - handle dwMerit! */
+	return QUARTZ_RegisterAMovieFilter(
+		&CLSID_LegacyAmFilterCategory,
+		&clsid,
+		NULL, 0,
+		lpwszName, NULL, TRUE );
 }
 
 static HRESULT WINAPI
 IFilterMapper_fnRegisterFilterInstance(IFilterMapper* iface,CLSID clsid,LPCWSTR lpwszName,CLSID* pclsidMedia)
 {
 	CFilterMapper_THIS(iface,fmap);
+	HRESULT	hr;
 
-	TRACE("(%p)->() stub!\n",This);
+	FIXME("(%p)->()\n",This);
 
-	return E_NOTIMPL;
+	if ( pclsidMedia == NULL )
+		return E_POINTER;
+	hr = CoCreateGuid(pclsidMedia);
+	if ( FAILED(hr) )
+		return hr;
+
+	/* FIXME */
+	return IFilterMapper_RegisterFilter(iface,
+		*pclsidMedia,lpwszName,0x60000000);
 }
 
 static HRESULT WINAPI
@@ -81,7 +99,7 @@ IFilterMapper_fnRegisterPin(IFilterMapper* iface,CLSID clsidFilter,LPCWSTR lpwsz
 {
 	CFilterMapper_THIS(iface,fmap);
 
-	TRACE("(%p)->() stub!\n",This);
+	FIXME("(%p)->() stub!\n",This);
 
 	return E_NOTIMPL;
 }
@@ -91,7 +109,7 @@ IFilterMapper_fnRegisterPinType(IFilterMapper* iface,CLSID clsidFilter,LPCWSTR l
 {
 	CFilterMapper_THIS(iface,fmap);
 
-	TRACE("(%p)->() stub!\n",This);
+	FIXME("(%p)->() stub!\n",This);
 
 	return E_NOTIMPL;
 }
@@ -101,9 +119,13 @@ IFilterMapper_fnUnregisterFilter(IFilterMapper* iface,CLSID clsidFilter)
 {
 	CFilterMapper_THIS(iface,fmap);
 
-	TRACE("(%p)->() stub!\n",This);
+	FIXME("(%p)->(%s)\n",This,debugstr_guid(&clsidFilter));
 
-	return E_NOTIMPL;
+	/* FIXME */
+	return QUARTZ_RegisterAMovieFilter(
+		&CLSID_LegacyAmFilterCategory,
+		&clsidFilter,
+		NULL, 0, NULL, NULL, FALSE );
 }
 
 static HRESULT WINAPI
@@ -111,9 +133,10 @@ IFilterMapper_fnUnregisterFilterInstance(IFilterMapper* iface,CLSID clsidMedia)
 {
 	CFilterMapper_THIS(iface,fmap);
 
-	TRACE("(%p)->() stub!\n",This);
+	FIXME("(%p)->(%s)\n",This,debugstr_guid(&clsidMedia));
 
-	return E_NOTIMPL;
+	/* FIXME */
+	return IFilterMapper_UnregisterFilter(iface,clsidMedia);
 }
 
 static HRESULT WINAPI
@@ -121,7 +144,8 @@ IFilterMapper_fnUnregisterPin(IFilterMapper* iface,CLSID clsidPin,LPCWSTR lpwszN
 {
 	CFilterMapper_THIS(iface,fmap);
 
-	TRACE("(%p)->() stub!\n",This);
+	FIXME("(%p)->(%s,%s) stub!\n",This,
+		debugstr_guid(&clsidPin),debugstr_w(lpwszName));
 
 	return E_NOTIMPL;
 }
@@ -131,7 +155,7 @@ IFilterMapper_fnEnumMatchingFilters(IFilterMapper* iface,IEnumRegFilters** ppobj
 {
 	CFilterMapper_THIS(iface,fmap);
 
-	TRACE("(%p)->() stub!\n",This);
+	FIXME("(%p)->() stub!\n",This);
 
 	return E_NOTIMPL;
 }
@@ -157,10 +181,12 @@ static ICOM_VTABLE(IFilterMapper) ifmap =
 };
 
 
-void CFilterMapper_InitIFilterMapper( CFilterMapper* pfm )
+HRESULT CFilterMapper_InitIFilterMapper( CFilterMapper* pfm )
 {
 	TRACE("(%p)\n",pfm);
 	ICOM_VTBL(&pfm->fmap) = &ifmap;
+
+	return NOERROR;
 }
 
 void CFilterMapper_UninitIFilterMapper( CFilterMapper* pfm )
diff --git a/dlls/quartz/ifmap3.c b/dlls/quartz/ifmap3.c
index d8b51c3978b..b706ab43804 100644
--- a/dlls/quartz/ifmap3.c
+++ b/dlls/quartz/ifmap3.c
@@ -11,6 +11,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
+#include "winreg.h"
 #include "winerror.h"
 #include "wine/obj_base.h"
 #include "wine/obj_oleaut.h"
@@ -23,6 +24,7 @@ DEFAULT_DEBUG_CHANNEL(quartz);
 
 #include "quartz_private.h"
 #include "fmap2.h"
+#include "regsvr.h"
 
 
 static HRESULT WINAPI
@@ -60,7 +62,9 @@ IFilterMapper3_fnCreateCategory(IFilterMapper3* iface,REFCLSID rclsidCategory,DW
 {
 	CFilterMapper2_THIS(iface,fmap3);
 
-	FIXME("(%p)->() stub!\n",This);
+	FIXME("(%p)->(%s,%lu,%s) stub!\n",This,
+		debugstr_guid(rclsidCategory),
+		(unsigned long)dwMerit,debugstr_w(lpwszDesc));
 
 	return E_NOTIMPL;
 }
@@ -71,7 +75,10 @@ IFilterMapper3_fnUnregisterFilter(IFilterMapper3* iface,const CLSID* pclsidCateg
 {
 	CFilterMapper2_THIS(iface,fmap3);
 
-	FIXME("(%p)->() stub!\n",This);
+	FIXME("(%p)->(%s,%s,%s) stub!\n",This,
+		debugstr_guid(pclsidCategory),
+		debugstr_w(lpwszInst),
+		debugstr_guid(rclsidFilter));
 
 	return E_NOTIMPL;
 }
@@ -82,7 +89,10 @@ IFilterMapper3_fnRegisterFilter(IFilterMapper3* iface,REFCLSID rclsidFilter,LPCW
 {
 	CFilterMapper2_THIS(iface,fmap3);
 
-	FIXME("(%p)->() stub!\n",This);
+	FIXME( "(%p)->(%s,%s,%p,%s,%s,%p) stub!\n",This,
+		debugstr_guid(rclsidFilter),debugstr_w(lpName),
+		ppMoniker,debugstr_guid(pclsidCategory),
+		debugstr_w(lpwszInst),pRF2 );
 
 	return E_NOTIMPL;
 }
@@ -129,10 +139,12 @@ static ICOM_VTABLE(IFilterMapper3) ifmap3 =
 };
 
 
-void CFilterMapper2_InitIFilterMapper3( CFilterMapper2* pfm )
+HRESULT CFilterMapper2_InitIFilterMapper3( CFilterMapper2* pfm )
 {
 	TRACE("(%p)\n",pfm);
 	ICOM_VTBL(&pfm->fmap3) = &ifmap3;
+
+	return NOERROR;
 }
 
 void CFilterMapper2_UninitIFilterMapper3( CFilterMapper2* pfm )
diff --git a/dlls/quartz/igrver.c b/dlls/quartz/igrver.c
new file mode 100644
index 00000000000..a7e157961c8
--- /dev/null
+++ b/dlls/quartz/igrver.c
@@ -0,0 +1,108 @@
+/*
+ * Implementation of IGraphVersion for FilterGraph.
+ *
+ * FIXME - stub.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "wine/obj_oleaut.h"
+#include "strmif.h"
+#include "control.h"
+#include "uuids.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "fgraph.h"
+
+
+
+static HRESULT WINAPI
+IGraphVersion_fnQueryInterface(IGraphVersion* iface,REFIID riid,void** ppobj)
+{
+	CFilterGraph_THIS(iface,graphversion);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IGraphVersion_fnAddRef(IGraphVersion* iface)
+{
+	CFilterGraph_THIS(iface,graphversion);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IGraphVersion_fnRelease(IGraphVersion* iface)
+{
+	CFilterGraph_THIS(iface,graphversion);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+
+static HRESULT WINAPI
+IGraphVersion_fnQueryVersion(IGraphVersion* iface,LONG* plVersion)
+{
+	CFilterGraph_THIS(iface,graphversion);
+
+	TRACE("(%p)->(%p)\n",This,plVersion);
+
+	if ( plVersion == NULL )
+		return E_POINTER;
+
+	EnterCriticalSection( &This->m_csGraphVersion );
+	*plVersion = This->m_lGraphVersion;
+	LeaveCriticalSection( &This->m_csGraphVersion );
+
+	return NOERROR;
+}
+
+
+static ICOM_VTABLE(IGraphVersion) igraphversion =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	IGraphVersion_fnQueryInterface,
+	IGraphVersion_fnAddRef,
+	IGraphVersion_fnRelease,
+	/* IGraphVersion fields */
+	IGraphVersion_fnQueryVersion,
+};
+
+
+
+HRESULT CFilterGraph_InitIGraphVersion( CFilterGraph* pfg )
+{
+	TRACE("(%p)\n",pfg);
+	ICOM_VTBL(&pfg->graphversion) = &igraphversion;
+
+	InitializeCriticalSection( &pfg->m_csGraphVersion );
+	pfg->m_lGraphVersion = 1;
+
+	return NOERROR;
+}
+
+void CFilterGraph_UninitIGraphVersion( CFilterGraph* pfg )
+{
+	TRACE("(%p)\n",pfg);
+
+	DeleteCriticalSection( &pfg->m_csGraphVersion );
+}
+
diff --git a/dlls/quartz/imcntl.c b/dlls/quartz/imcntl.c
index 0e91bee1424..67bb2fa368f 100644
--- a/dlls/quartz/imcntl.c
+++ b/dlls/quartz/imcntl.c
@@ -213,10 +213,12 @@ static ICOM_VTABLE(IMediaControl) imediacontrol =
 };
 
 
-void CFilterGraph_InitIMediaControl( CFilterGraph* pfg )
+HRESULT CFilterGraph_InitIMediaControl( CFilterGraph* pfg )
 {
 	TRACE("(%p)\n",pfg);
 	ICOM_VTBL(&pfg->mediacontrol) = &imediacontrol;
+
+	return NOERROR;
 }
 
 void CFilterGraph_UninitIMediaControl( CFilterGraph* pfg )
diff --git a/dlls/quartz/imem.c b/dlls/quartz/imem.c
index 5d7b1d67937..7053fea3f52 100644
--- a/dlls/quartz/imem.c
+++ b/dlls/quartz/imem.c
@@ -126,8 +126,15 @@ static ICOM_VTABLE(IMemAllocator) imemalloc =
 };
 
 
-void CMemoryAllocator_InitIMemAllocator( CMemoryAllocator* pma )
+HRESULT CMemoryAllocator_InitIMemAllocator( CMemoryAllocator* pma )
 {
 	TRACE("(%p)\n",pma);
 	ICOM_VTBL(&pma->memalloc) = &imemalloc;
+
+	return NOERROR;
+}
+
+void CMemoryAllocator_UninitIMemAllocator( CMemoryAllocator* pma )
+{
+	TRACE("(%p)\n",pma);
 }
diff --git a/dlls/quartz/imesink.c b/dlls/quartz/imesink.c
new file mode 100644
index 00000000000..5e2e7bfce42
--- /dev/null
+++ b/dlls/quartz/imesink.c
@@ -0,0 +1,95 @@
+/*
+ * Implementation of IMediaEventSink for FilterGraph.
+ *
+ * FIXME - stub.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "wine/obj_oleaut.h"
+#include "strmif.h"
+#include "control.h"
+#include "uuids.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "fgraph.h"
+
+
+
+static HRESULT WINAPI
+IMediaEventSink_fnQueryInterface(IMediaEventSink* iface,REFIID riid,void** ppobj)
+{
+	CFilterGraph_THIS(iface,mediaeventsink);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IMediaEventSink_fnAddRef(IMediaEventSink* iface)
+{
+	CFilterGraph_THIS(iface,mediaeventsink);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IMediaEventSink_fnRelease(IMediaEventSink* iface)
+{
+	CFilterGraph_THIS(iface,mediaeventsink);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+static HRESULT WINAPI
+IMediaEventSink_fnNotify(IMediaEventSink* iface,long lEventCode,LONG_PTR lParam1,LONG_PTR lParam2)
+{
+	CFilterGraph_THIS(iface,mediaeventsink);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+
+static ICOM_VTABLE(IMediaEventSink) imediaeventsink =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	IMediaEventSink_fnQueryInterface,
+	IMediaEventSink_fnAddRef,
+	IMediaEventSink_fnRelease,
+	/* IMediaEventSink fields */
+	IMediaEventSink_fnNotify,
+};
+
+
+
+HRESULT CFilterGraph_InitIMediaEventSink( CFilterGraph* pfg )
+{
+	TRACE("(%p)\n",pfg);
+	ICOM_VTBL(&pfg->mediaeventsink) = &imediaeventsink;
+
+	return NOERROR;
+}
+
+void CFilterGraph_UninitIMediaEventSink( CFilterGraph* pfg )
+{
+	TRACE("(%p)\n",pfg);
+}
+
diff --git a/dlls/quartz/imevent.c b/dlls/quartz/imevent.c
index 12a3078b20b..eaf44382599 100644
--- a/dlls/quartz/imevent.c
+++ b/dlls/quartz/imevent.c
@@ -102,9 +102,11 @@ IMediaEventEx_fnGetEventHandle(IMediaEventEx* iface,OAEVENT* hEvent)
 {
 	CFilterGraph_THIS(iface,mediaevent);
 
-	FIXME("(%p)->() stub!\n",This);
+	TRACE("(%p)->()\n",This);
 
-	return E_NOTIMPL;
+	*hEvent = (OAEVENT)This->m_hMediaEvent;
+
+	return NOERROR;
 }
 
 static HRESULT WINAPI
@@ -215,13 +217,21 @@ static ICOM_VTABLE(IMediaEventEx) imediaevent =
 };
 
 
-void CFilterGraph_InitIMediaEventEx( CFilterGraph* pfg )
+HRESULT CFilterGraph_InitIMediaEventEx( CFilterGraph* pfg )
 {
 	TRACE("(%p)\n",pfg);
 	ICOM_VTBL(&pfg->mediaevent) = &imediaevent;
+
+	pfg->m_hMediaEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
+	if ( pfg->m_hMediaEvent == (HANDLE)NULL )
+		return E_OUTOFMEMORY;
+
+	return NOERROR;
 }
 
 void CFilterGraph_UninitIMediaEventEx( CFilterGraph* pfg )
 {
 	TRACE("(%p)\n",pfg);
+
+	CloseHandle( pfg->m_hMediaEvent );
 }
diff --git a/dlls/quartz/imfilter.c b/dlls/quartz/imfilter.c
new file mode 100644
index 00000000000..2c7e94a233a
--- /dev/null
+++ b/dlls/quartz/imfilter.c
@@ -0,0 +1,162 @@
+/*
+ * Implementation of IMediaFilter for FilterGraph.
+ *
+ * FIXME - stub.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "wine/obj_oleaut.h"
+#include "strmif.h"
+#include "control.h"
+#include "uuids.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "fgraph.h"
+
+
+
+static HRESULT WINAPI
+IMediaFilter_fnQueryInterface(IMediaFilter* iface,REFIID riid,void** ppobj)
+{
+	CFilterGraph_THIS(iface,mediafilter);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IMediaFilter_fnAddRef(IMediaFilter* iface)
+{
+	CFilterGraph_THIS(iface,mediafilter);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IMediaFilter_fnRelease(IMediaFilter* iface)
+{
+	CFilterGraph_THIS(iface,mediafilter);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+
+static HRESULT WINAPI
+IMediaFilter_fnGetClassID(IMediaFilter* iface,CLSID* pclsid)
+{
+	CFilterGraph_THIS(iface,mediafilter);
+
+	TRACE("(%p)->()\n",This);
+
+	return IPersist_GetClassID(
+		CFilterGraph_IPersist(This),pclsid);
+}
+
+static HRESULT WINAPI
+IMediaFilter_fnStop(IMediaFilter* iface)
+{
+	CFilterGraph_THIS(iface,mediafilter);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IMediaFilter_fnPause(IMediaFilter* iface)
+{
+	CFilterGraph_THIS(iface,mediafilter);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IMediaFilter_fnRun(IMediaFilter* iface,REFERENCE_TIME rtStart)
+{
+	CFilterGraph_THIS(iface,mediafilter);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IMediaFilter_fnGetState(IMediaFilter* iface,DWORD dw,FILTER_STATE* pState)
+{
+	CFilterGraph_THIS(iface,mediafilter);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IMediaFilter_fnSetSyncSource(IMediaFilter* iface,IReferenceClock* pobjClock)
+{
+	CFilterGraph_THIS(iface,mediafilter);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IMediaFilter_fnGetSyncSource(IMediaFilter* iface,IReferenceClock** ppobjClock)
+{
+	CFilterGraph_THIS(iface,mediafilter);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+
+
+static ICOM_VTABLE(IMediaFilter) imediafilter =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	IMediaFilter_fnQueryInterface,
+	IMediaFilter_fnAddRef,
+	IMediaFilter_fnRelease,
+	/* IPersist fields */
+	IMediaFilter_fnGetClassID,
+	/* IMediaFilter fields */
+	IMediaFilter_fnStop,
+	IMediaFilter_fnPause,
+	IMediaFilter_fnRun,
+	IMediaFilter_fnGetState,
+	IMediaFilter_fnSetSyncSource,
+	IMediaFilter_fnGetSyncSource,
+};
+
+HRESULT CFilterGraph_InitIMediaFilter( CFilterGraph* pfg )
+{
+	TRACE("(%p)\n",pfg);
+	ICOM_VTBL(&pfg->mediafilter) = &imediafilter;
+
+	return NOERROR;
+}
+
+void CFilterGraph_UninitIMediaFilter( CFilterGraph* pfg )
+{
+	TRACE("(%p)\n",pfg);
+}
diff --git a/dlls/quartz/impos.c b/dlls/quartz/impos.c
index caf6e3f0073..2036d509ca0 100644
--- a/dlls/quartz/impos.c
+++ b/dlls/quartz/impos.c
@@ -60,9 +60,10 @@ IMediaPosition_fnGetTypeInfoCount(IMediaPosition* iface,UINT* pcTypeInfo)
 {
 	CFilterGraph_THIS(iface,mediaposition);
 
-	FIXME("(%p)->()\n",This);
+	TRACE("(%p)->()\n",This);
 
-	return E_NOTIMPL;
+	return IDispatch_GetTypeInfoCount(
+		CFilterGraph_IDispatch(This),pcTypeInfo);
 }
 
 static HRESULT WINAPI
@@ -70,9 +71,10 @@ IMediaPosition_fnGetTypeInfo(IMediaPosition* iface,UINT iTypeInfo, LCID lcid, IT
 {
 	CFilterGraph_THIS(iface,mediaposition);
 
-	FIXME("(%p)->()\n",This);
+	TRACE("(%p)->()\n",This);
 
-	return E_NOTIMPL;
+	return IDispatch_GetTypeInfo(
+		CFilterGraph_IDispatch(This),iTypeInfo,lcid,ppobj);
 }
 
 static HRESULT WINAPI
@@ -80,9 +82,10 @@ IMediaPosition_fnGetIDsOfNames(IMediaPosition* iface,REFIID riid, LPOLESTR* ppws
 {
 	CFilterGraph_THIS(iface,mediaposition);
 
-	FIXME("(%p)->()\n",This);
+	TRACE("(%p)->()\n",This);
 
-	return E_NOTIMPL;
+	return IDispatch_GetIDsOfNames(
+		CFilterGraph_IDispatch(This),riid,ppwszName,cNames,lcid,pDispId);
 }
 
 static HRESULT WINAPI
@@ -90,9 +93,11 @@ IMediaPosition_fnInvoke(IMediaPosition* iface,DISPID DispId, REFIID riid, LCID l
 {
 	CFilterGraph_THIS(iface,mediaposition);
 
-	FIXME("(%p)->()\n",This);
+	TRACE("(%p)->()\n",This);
 
-	return E_NOTIMPL;
+	return IDispatch_Invoke(
+		CFilterGraph_IDispatch(This),
+		DispId,riid,lcid,wFlags,pDispParams,pVarRes,pExcepInfo,puArgErr);
 }
 
 
@@ -234,10 +239,12 @@ static ICOM_VTABLE(IMediaPosition) imediaposition =
 };
 
 
-void CFilterGraph_InitIMediaPosition( CFilterGraph* pfg )
+HRESULT CFilterGraph_InitIMediaPosition( CFilterGraph* pfg )
 {
 	TRACE("(%p)\n",pfg);
 	ICOM_VTBL(&pfg->mediaposition) = &imediaposition;
+
+	return NOERROR;
 }
 
 void CFilterGraph_UninitIMediaPosition( CFilterGraph* pfg )
diff --git a/dlls/quartz/imseek.c b/dlls/quartz/imseek.c
index 2dbc5000297..cf67ff76f5a 100644
--- a/dlls/quartz/imseek.c
+++ b/dlls/quartz/imseek.c
@@ -257,10 +257,12 @@ static ICOM_VTABLE(IMediaSeeking) imediaseeking =
 	IMediaSeeking_fnGetPreroll,
 };
 
-void CFilterGraph_InitIMediaSeeking( CFilterGraph* pfg )
+HRESULT CFilterGraph_InitIMediaSeeking( CFilterGraph* pfg )
 {
 	TRACE("(%p)\n",pfg);
 	ICOM_VTBL(&pfg->mediaseeking) = &imediaseeking;
+
+	return NOERROR;
 }
 
 void CFilterGraph_UninitIMediaSeeking( CFilterGraph* pfg )
diff --git a/dlls/quartz/irclock.c b/dlls/quartz/irclock.c
index a780774b730..910f3103848 100644
--- a/dlls/quartz/irclock.c
+++ b/dlls/quartz/irclock.c
@@ -104,8 +104,15 @@ static ICOM_VTABLE(IReferenceClock) irefclk =
 };
 
 
-void CSystemClock_InitIReferenceClock( CSystemClock* psc )
+HRESULT CSystemClock_InitIReferenceClock( CSystemClock* psc )
 {
 	TRACE("(%p)\n",psc);
 	ICOM_VTBL(&psc->refclk) = &irefclk;
+
+	return NOERROR;
+}
+
+void CSystemClock_UninitIReferenceClock( CSystemClock* psc )
+{
+	TRACE("(%p)\n",psc);
 }
diff --git a/dlls/quartz/iunk.h b/dlls/quartz/iunk.h
index 0555f3b82d7..338d1136e9a 100644
--- a/dlls/quartz/iunk.h
+++ b/dlls/quartz/iunk.h
@@ -29,7 +29,7 @@
 
 typedef struct QUARTZ_IFEntry
 {
-	REFIID		piid;		/* interface ID. */
+	const IID*	piid;		/* interface ID. */
 	size_t		ofsVTPtr;	/* offset from IUnknown. */
 } QUARTZ_IFEntry;
 
diff --git a/dlls/quartz/ividwin.c b/dlls/quartz/ividwin.c
index 5feb73f04e5..a81fa751926 100644
--- a/dlls/quartz/ividwin.c
+++ b/dlls/quartz/ividwin.c
@@ -547,10 +547,12 @@ static ICOM_VTABLE(IVideoWindow) ivideowindow =
 };
 
 
-void CFilterGraph_InitIVideoWindow( CFilterGraph* pfg )
+HRESULT CFilterGraph_InitIVideoWindow( CFilterGraph* pfg )
 {
 	TRACE("(%p)\n",pfg);
 	ICOM_VTBL(&pfg->vidwin) = &ivideowindow;
+
+	return NOERROR;
 }
 
 void CFilterGraph_UninitIVideoWindow( CFilterGraph* pfg )
diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c
index b1479584d18..90cc02d7932 100644
--- a/dlls/quartz/main.c
+++ b/dlls/quartz/main.c
@@ -50,7 +50,7 @@ typedef struct
 {
 	/* IUnknown fields */
 	ICOM_VFIELD(IClassFactory);
-	DWORD	ref;
+	LONG	ref;
 	/* IClassFactory fields */
 	const QUARTZ_CLASSENTRY* pEntry;
 } IClassFactoryImpl;
@@ -128,16 +128,18 @@ static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface)
 
 	TRACE("(%p)->()\n",This);
 
-	return ++(This->ref);
+	return InterlockedExchangeAdd(&(This->ref),1) + 1;
 }
 
 static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface)
 {
 	ICOM_THIS(IClassFactoryImpl,iface);
+	LONG	ref;
 
 	TRACE("(%p)->()\n",This);
-	if ( (--(This->ref)) > 0 )
-		return This->ref;
+	ref = InterlockedExchangeAdd(&(This->ref),-1) - 1;
+	if ( ref > 0 )
+		return (ULONG)ref;
 
 	QUARTZ_FreeObj(This);
 	return 0;
diff --git a/dlls/quartz/memalloc.c b/dlls/quartz/memalloc.c
index 16410bf5e2c..7bde1491308 100644
--- a/dlls/quartz/memalloc.c
+++ b/dlls/quartz/memalloc.c
@@ -29,9 +29,17 @@ static QUARTZ_IFEntry IFEntries[] =
   { &IID_IMemAllocator, offsetof(CMemoryAllocator,memalloc)-offsetof(CMemoryAllocator,unk) },
 };
 
+static void QUARTZ_DestroyMemoryAllocator(IUnknown* punk)
+{
+	CMemoryAllocator_THIS(punk,unk);
+
+	CMemoryAllocator_UninitIMemAllocator( This );
+}
+
 HRESULT QUARTZ_CreateMemoryAllocator(IUnknown* punkOuter,void** ppobj)
 {
 	CMemoryAllocator*	pma;
+	HRESULT	hr;
 
 	TRACE("(%p,%p)\n",punkOuter,ppobj);
 
@@ -40,10 +48,16 @@ HRESULT QUARTZ_CreateMemoryAllocator(IUnknown* punkOuter,void** ppobj)
 		return E_OUTOFMEMORY;
 
 	QUARTZ_IUnkInit( &pma->unk, punkOuter );
-	CMemoryAllocator_InitIMemAllocator( pma );
+	hr = CMemoryAllocator_InitIMemAllocator( pma );
+	if ( FAILED(hr) )
+	{
+		QUARTZ_FreeObj( pma );
+		return hr;
+	}
 
 	pma->unk.pEntries = IFEntries;
 	pma->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
+	pma->unk.pOnFinalRelease = QUARTZ_DestroyMemoryAllocator;
 
 	*ppobj = (void*)(&pma->unk);
 
diff --git a/dlls/quartz/memalloc.h b/dlls/quartz/memalloc.h
index 408e9dbc2ee..4b6ae4ac8a9 100644
--- a/dlls/quartz/memalloc.h
+++ b/dlls/quartz/memalloc.h
@@ -30,7 +30,8 @@ typedef struct CMemoryAllocator
 
 HRESULT QUARTZ_CreateMemoryAllocator(IUnknown* punkOuter,void** ppobj);
 
-void CMemoryAllocator_InitIMemAllocator( CMemoryAllocator* pma );
+HRESULT CMemoryAllocator_InitIMemAllocator( CMemoryAllocator* pma );
+void CMemoryAllocator_UninitIMemAllocator( CMemoryAllocator* pma );
 
 
 #endif  /* WINE_DSHOW_MEMALLOC_H */
diff --git a/dlls/quartz/monprop.c b/dlls/quartz/monprop.c
new file mode 100644
index 00000000000..81a029c08ec
--- /dev/null
+++ b/dlls/quartz/monprop.c
@@ -0,0 +1,205 @@
+/*
+ * Implements IPropertyBag. (internal)
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "objidl.h"
+#include "oleidl.h"
+#include "ocidl.h"
+#include "oleauto.h"
+#include "strmif.h"
+#include "wine/unicode.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "monprop.h"
+
+
+static HRESULT WINAPI
+IPropertyBag_fnQueryInterface(IPropertyBag* iface,REFIID riid,void** ppobj)
+{
+	CRegPropertyBag_THIS(iface,propbag);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IPropertyBag_fnAddRef(IPropertyBag* iface)
+{
+	CRegPropertyBag_THIS(iface,propbag);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IPropertyBag_fnRelease(IPropertyBag* iface)
+{
+	CRegPropertyBag_THIS(iface,propbag);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+static HRESULT WINAPI
+IPropertyBag_fnRead(IPropertyBag* iface,LPCOLESTR lpszPropName,VARIANT* pVar,IErrorLog* pLog)
+{
+	CRegPropertyBag_THIS(iface,propbag);
+	LONG	lr;
+	DWORD	dwSize;
+	DWORD	dwValueType;
+
+	TRACE("(%p)->(%s,%p,%p)\n",This,
+		debugstr_w(lpszPropName),pVar,pLog);
+
+	if ( lpszPropName == NULL || pVar == NULL )
+		return E_POINTER;
+
+	dwSize = 0;
+	lr = RegQueryValueExW(
+		This->m_hKey, lpszPropName, NULL,
+		&dwValueType, NULL, &dwSize );
+	if ( lr != ERROR_SUCCESS )
+		return E_INVALIDARG;
+
+	switch ( dwValueType )
+	{
+	case REG_SZ:
+		if ( pVar->n1.n2.vt == VT_EMPTY )
+			pVar->n1.n2.vt = VT_BSTR;
+		if ( pVar->n1.n2.vt != VT_BSTR )
+			return E_FAIL;
+
+		pVar->n1.n2.n3.bstrVal = SysAllocStringByteLen(
+			NULL, dwSize );
+		if ( pVar->n1.n2.n3.bstrVal == NULL )
+			return E_OUTOFMEMORY;
+		lr = RegQueryValueExW(
+			This->m_hKey, lpszPropName, NULL,
+			&dwValueType,
+			(BYTE*)pVar->n1.n2.n3.bstrVal, &dwSize );
+		if ( lr != ERROR_SUCCESS )
+		{
+			SysFreeString(pVar->n1.n2.n3.bstrVal);
+			return E_FAIL;
+		}
+		break;
+	default:
+		FIXME("(%p)->(%s,%p,%p) - unsupported value type.\n",This,
+			debugstr_w(lpszPropName),pVar,pLog);
+		return E_FAIL;
+	}
+
+	return NOERROR;
+}
+
+static HRESULT WINAPI
+IPropertyBag_fnWrite(IPropertyBag* iface,LPCOLESTR lpszPropName,VARIANT* pVar)
+{
+	CRegPropertyBag_THIS(iface,propbag);
+
+	FIXME("(%p)->(%s,%p) stub!\n",This,
+		debugstr_w(lpszPropName),pVar);
+
+	if ( lpszPropName == NULL || pVar == NULL )
+		return E_POINTER;
+
+	return E_NOTIMPL;
+}
+
+
+
+
+static ICOM_VTABLE(IPropertyBag) ipropbag =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	IPropertyBag_fnQueryInterface,
+	IPropertyBag_fnAddRef,
+	IPropertyBag_fnRelease,
+	/* IPropertyBag fields */
+	IPropertyBag_fnRead,
+	IPropertyBag_fnWrite,
+};
+
+static HRESULT CRegPropertyBag_InitIPropertyBag(
+	CRegPropertyBag* prpb, HKEY hkRoot, LPCWSTR lpKeyPath )
+{
+	ICOM_VTBL(&prpb->propbag) = &ipropbag;
+
+	if ( RegOpenKeyExW(
+		hkRoot, lpKeyPath, 0,
+		KEY_ALL_ACCESS, &prpb->m_hKey ) != ERROR_SUCCESS )
+		return E_FAIL;
+
+	return NOERROR;
+}
+
+static void CRegPropertyBag_UninitIPropertyBag(
+	CRegPropertyBag* prpb )
+{
+	RegCloseKey( prpb->m_hKey );
+}
+
+
+static void QUARTZ_DestroyRegPropertyBag(IUnknown* punk)
+{
+	CRegPropertyBag_THIS(punk,unk);
+
+	CRegPropertyBag_UninitIPropertyBag(This);
+}
+
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry IFEntries[] =
+{
+  { &IID_IPropertyBag, offsetof(CRegPropertyBag,propbag)-offsetof(CRegPropertyBag,unk) },
+};
+
+HRESULT QUARTZ_CreateRegPropertyBag(
+	HKEY hkRoot, LPCWSTR lpKeyPath,
+	IPropertyBag** ppPropBag )
+{
+	CRegPropertyBag*	prpb;
+	HRESULT	hr;
+
+	TRACE("(%08x,%s,%p)\n",hkRoot,debugstr_w(lpKeyPath),ppPropBag );
+
+	prpb = (CRegPropertyBag*)QUARTZ_AllocObj( sizeof(CRegPropertyBag) );
+	if ( prpb == NULL )
+		return E_OUTOFMEMORY;
+
+	QUARTZ_IUnkInit( &prpb->unk, NULL );
+	hr = CRegPropertyBag_InitIPropertyBag( prpb, hkRoot, lpKeyPath );
+	if ( FAILED(hr) )
+	{
+		QUARTZ_FreeObj( prpb );
+		return hr;
+	}
+
+	prpb->unk.pEntries = IFEntries;
+	prpb->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
+	prpb->unk.pOnFinalRelease = &QUARTZ_DestroyRegPropertyBag;
+
+	*ppPropBag = (IPropertyBag*)(&prpb->propbag);
+
+	return S_OK;
+}
+
+
diff --git a/dlls/quartz/monprop.h b/dlls/quartz/monprop.h
new file mode 100644
index 00000000000..25c4946b97e
--- /dev/null
+++ b/dlls/quartz/monprop.h
@@ -0,0 +1,34 @@
+#ifndef	WINE_DSHOW_MONPROP_H
+#define	WINE_DSHOW_MONPROP_H
+
+/*
+		implements IPropertyBag for accessing registry.
+
+	- At least, the following interfaces should be implemented:
+
+	IUnknown
+		+ IPropertyBag
+ */
+
+#include "iunk.h"
+
+typedef struct DMON_IPropertyBagImpl
+{
+	ICOM_VFIELD(IPropertyBag);
+} DMON_IPropertyBagImpl;
+
+typedef struct CRegPropertyBag
+{
+	QUARTZ_IUnkImpl	unk;
+	DMON_IPropertyBagImpl	propbag;
+	/* IPropertyBag fields */
+	HKEY	m_hKey;
+} CRegPropertyBag;
+
+#define	CRegPropertyBag_THIS(iface,member)	CRegPropertyBag*	This = (CRegPropertyBag*)(((char*)iface)-offsetof(CRegPropertyBag,member))
+
+HRESULT QUARTZ_CreateRegPropertyBag(
+	HKEY hkRoot, LPCWSTR lpKeyPath,
+	IPropertyBag** ppPropBag );
+
+#endif	/* WINE_DSHOW_MONPROP_H */
diff --git a/dlls/quartz/quartz.spec b/dlls/quartz/quartz.spec
index b32471f703c..809f83ba449 100644
--- a/dlls/quartz/quartz.spec
+++ b/dlls/quartz/quartz.spec
@@ -2,9 +2,14 @@ name	quartz
 type	win32
 init	QUARTZ_DllMain
 
-#import ole2.dll
-import kernel32.dll
 import ntdll.dll
+import kernel32.dll
+import user32.dll
+#import gdi32.dll
+import advapi32.dll
+#import winmm.dll
+import ole32.dll
+import oleaut32.dll
 
 debug_channels (quartz)
 
diff --git a/dlls/quartz/regsvr.c b/dlls/quartz/regsvr.c
index 3def2762364..f979137f46d 100644
--- a/dlls/quartz/regsvr.c
+++ b/dlls/quartz/regsvr.c
@@ -9,49 +9,362 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
+#include "winuser.h"
 #include "winerror.h"
 #include "winreg.h"
+#include "uuids.h"
+#include "wine/unicode.h"
 
 #include "debugtools.h"
 DEFAULT_DEBUG_CHANNEL(quartz);
 
 #include "regsvr.h"
 
+#ifndef	NUMELEMS
+#define	NUMELEMS(elem)	(sizeof(elem)/sizeof((elem)[0]))
+#endif	/* NUMELEMS */
 
-HRESULT QUARTZ_RegisterDLLServer(
-	const CLSID* pclsid,
-	LPCSTR lpFriendlyName,
-	LPCSTR lpNameOfDLL )
+const WCHAR QUARTZ_wszREG_SZ[] =
+	{'R','E','G','_','S','Z',0};
+const WCHAR QUARTZ_wszInprocServer32[] =
+	{'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
+const WCHAR QUARTZ_wszThreadingModel[] =
+	{'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
+const WCHAR QUARTZ_wszBoth[] =
+	{'B','o','t','h',0};
+const WCHAR QUARTZ_wszCLSID[] =
+	{'C','L','S','I','D',0};
+const WCHAR QUARTZ_wszFilterData[] =
+	{'F','i','l','t','e','r',' ','D','a','t','a',0};
+const WCHAR QUARTZ_wszFriendlyName[] =
+	{'F','r','i','e','n','d','l','y','N','a','m','e',0};
+const WCHAR QUARTZ_wszInstance[] =
+	{'I','n','s','t','a','n','c','e',0};
+const WCHAR QUARTZ_wszMerit[] =
+	{'M','e','r','i','t',0};
+
+static
+void QUARTZ_CatPathSepW( WCHAR* pBuf )
+{
+	int	len = strlenW(pBuf);
+	pBuf[len] = '\\';
+	pBuf[len+1] = 0;
+}
+
+static
+void QUARTZ_GUIDtoString( WCHAR* pBuf, const GUID* pguid )
+{
+	/* W"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}" */
+	static const WCHAR wszFmt[] =
+		{'{','%','0','8','X','-','%','0','4','X','-','%','0','4','X',
+		 '-','%','0','2','X','%','0','2','X','-','%','0','2','X','%',
+		 '0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
+		 '%','0','2','X','}',0};
+
+	wsprintfW( pBuf, wszFmt,
+		pguid->Data1, pguid->Data2, pguid->Data3,
+		pguid->Data4[0], pguid->Data4[1],
+		pguid->Data4[2], pguid->Data4[3],
+		pguid->Data4[4], pguid->Data4[5],
+		pguid->Data4[6], pguid->Data4[7] );
+}
+
+static
+LONG QUARTZ_RegOpenKeyW(
+	HKEY hkRoot, LPCWSTR lpszPath,
+	REGSAM rsAccess, HKEY* phKey,
+	BOOL fCreateKey )
+{
+	DWORD	dwDisp;
+	WCHAR	wszREG_SZ[ NUMELEMS(QUARTZ_wszREG_SZ) ];
+
+	memcpy(wszREG_SZ,QUARTZ_wszREG_SZ,sizeof(QUARTZ_wszREG_SZ) );
+
+	if ( fCreateKey )
+		return RegCreateKeyExW(
+			hkRoot, lpszPath, 0, wszREG_SZ,
+			REG_OPTION_NON_VOLATILE, rsAccess, NULL, phKey, &dwDisp );
+	else
+		return RegOpenKeyExW(
+			hkRoot, lpszPath, 0, rsAccess, phKey );
+}
+
+static
+LONG QUARTZ_RegSetValueString(
+	HKEY hKey, LPCWSTR lpszName, LPCWSTR lpValue )
+{
+	return RegSetValueExW(
+		hKey, lpszName, 0, REG_SZ,
+		(const BYTE*)lpValue,
+		sizeof(lpValue[0]) * (strlenW(lpValue)+1) );
+}
+
+static
+LONG QUARTZ_RegSetValueDWord(
+	HKEY hKey, LPCWSTR lpszName, DWORD dwValue )
 {
-	FIXME( "stub!\n" );
-	return E_FAIL;
+	return RegSetValueExW(
+		hKey, lpszName, 0, REG_DWORD,
+		(const BYTE*)(&dwValue), sizeof(DWORD) );
 }
 
-HRESULT QUARTZ_UnregisterDLLServer(
-	const CLSID* pclsid )
+static
+LONG QUARTZ_RegSetValueBinary(
+	HKEY hKey, LPCWSTR lpszName,
+	const BYTE* pData, int iLenOfData )
 {
-	FIXME( "stub!\n" );
-	return E_FAIL;
+	return RegSetValueExW(
+		hKey, lpszName, 0, REG_BINARY, pData, iLenOfData );
 }
 
+HRESULT QUARTZ_CreateCLSIDPath(
+        WCHAR* pwszBuf, DWORD dwBufLen,
+        const CLSID* pclsid,
+        LPCWSTR lpszPathFromCLSID )
+{
+	int avail;
+
+	strcpyW( pwszBuf, QUARTZ_wszCLSID );
+	QUARTZ_CatPathSepW( pwszBuf+5 );
+	QUARTZ_GUIDtoString( pwszBuf+6, pclsid );
+	if ( lpszPathFromCLSID != NULL )
+	{
+		avail = (int)dwBufLen - strlenW(pwszBuf) - 8;
+		if ( avail <= strlenW(lpszPathFromCLSID) )
+			return E_FAIL;
+		QUARTZ_CatPathSepW( pwszBuf );
+		strcatW( pwszBuf, lpszPathFromCLSID );
+	}
+
+	return NOERROR;
+}
 
-HRESULT QUARTZ_RegisterFilter(
-	const CLSID* pguidFilterCategory,
-	const CLSID* pclsid,
-	const BYTE* pbFilterData,
-	DWORD cbFilterData,
-	LPCSTR lpFriendlyName )
+HRESULT QUARTZ_OpenCLSIDKey(
+	HKEY* phKey,	/* [OUT] hKey */
+	REGSAM rsAccess,	/* [IN] access */
+	BOOL fCreate,	/* TRUE = RegCreateKey, FALSE = RegOpenKey */
+	const CLSID* pclsid,	/* CLSID */
+	LPCWSTR lpszPathFromCLSID )	/* related path from CLSID */
 {
-	FIXME( "stub!\n" );
-	return E_FAIL;
+	WCHAR	szKey[ 1024 ];
+	HRESULT	hr;
+	LONG	lr;
+
+	hr = QUARTZ_CreateCLSIDPath(
+		szKey, NUMELEMS(szKey),
+		pclsid, lpszPathFromCLSID );
+	if ( FAILED(hr) )
+		return hr;
+
+	lr = QUARTZ_RegOpenKeyW(
+		HKEY_CLASSES_ROOT, szKey, rsAccess, phKey, fCreate );
+	if ( lr != ERROR_SUCCESS )
+		return E_FAIL;
+
+	return S_OK;
 }
 
-HRESULT QUARTZ_UnregisterFilter(
-	const CLSID* pguidFilterCategory,
-	const CLSID* pclsid )
+
+
+HRESULT QUARTZ_RegisterAMovieDLLServer(
+	const CLSID* pclsid,	/* [IN] CLSID */
+	LPCWSTR lpFriendlyName,	/* [IN] Friendly name */
+	LPCWSTR lpNameOfDLL,	/* [IN] name of the registered DLL */
+	BOOL fRegister )	/* [IN] TRUE = register, FALSE = unregister */
 {
-	FIXME( "stub!\n" );
-	return E_FAIL;
+	HRESULT	hr;
+	HKEY	hKey;
+
+	if ( fRegister )
+	{
+		hr = QUARTZ_OpenCLSIDKey(
+			&hKey, KEY_ALL_ACCESS, TRUE,
+			pclsid, NULL );
+		if ( FAILED(hr) )
+			return hr;
+
+			if ( lpFriendlyName != NULL && QUARTZ_RegSetValueString(
+				hKey, NULL, lpFriendlyName ) != ERROR_SUCCESS )
+				hr = E_FAIL;
+
+		RegCloseKey( hKey );
+		if ( FAILED(hr) )
+			return hr;
+
+		hr = QUARTZ_OpenCLSIDKey(
+			&hKey, KEY_ALL_ACCESS, TRUE,
+			pclsid, QUARTZ_wszInprocServer32 );
+		if ( FAILED(hr) )
+			return hr;
+
+			if ( QUARTZ_RegSetValueString(
+				hKey, NULL, lpNameOfDLL ) != ERROR_SUCCESS )
+				hr = E_FAIL;
+			if ( QUARTZ_RegSetValueString(
+				hKey, QUARTZ_wszThreadingModel,
+				QUARTZ_wszBoth ) != ERROR_SUCCESS )
+				hr = E_FAIL;
+
+		RegCloseKey( hKey );
+		if ( FAILED(hr) )
+			return hr;
+	}
+	else
+	{
+		hr = QUARTZ_OpenCLSIDKey(
+			&hKey, KEY_ALL_ACCESS, FALSE,
+			pclsid, NULL );
+		if ( FAILED(hr) )
+			return NOERROR;
+
+			RegDeleteValueW( hKey, NULL );
+			RegDeleteValueW( hKey, QUARTZ_wszThreadingModel );
+
+		RegCloseKey( hKey );
+		if ( FAILED(hr) )
+			return hr;
+
+		/* I think key should be deleted only if no subkey exists. */
+		FIXME( "unregister %s - key should be removed!\n",
+				debugstr_guid(pclsid) );
+	}
+
+	return NOERROR;
+}
+
+
+HRESULT QUARTZ_RegisterCategory(
+	const CLSID* pguidFilterCategory,	/* [IN] Category */
+	LPCWSTR lpFriendlyName,	/* [IN] friendly name */
+	DWORD dwMerit,	/* [IN] merit */
+	BOOL fRegister )	/* [IN] TRUE = register, FALSE = unregister */
+{
+	HRESULT	hr;
+	HKEY	hKey;
+	WCHAR	szFilterPath[ 256 ];
+	WCHAR	szCLSID[ 256 ];
+
+	QUARTZ_GUIDtoString( szCLSID, pguidFilterCategory );
+	strcpyW( szFilterPath, QUARTZ_wszInstance );
+	QUARTZ_CatPathSepW( szFilterPath );
+	strcatW( szFilterPath, szCLSID );
+
+	if ( fRegister )
+	{
+		hr = QUARTZ_OpenCLSIDKey(
+			&hKey, KEY_ALL_ACCESS, TRUE,
+			&CLSID_ActiveMovieCategories, szFilterPath );
+		if ( FAILED(hr) )
+			return hr;
+
+			if ( QUARTZ_RegSetValueString(
+				hKey, QUARTZ_wszCLSID, szCLSID ) != ERROR_SUCCESS )
+				hr = E_FAIL;
+			if ( lpFriendlyName != NULL && QUARTZ_RegSetValueString(
+				hKey, QUARTZ_wszFriendlyName,
+				lpFriendlyName ) != ERROR_SUCCESS )
+				hr = E_FAIL;
+			if ( dwMerit != 0 &&
+				 QUARTZ_RegSetValueDWord(
+				 	hKey, QUARTZ_wszMerit, dwMerit ) != ERROR_SUCCESS )
+				hr = E_FAIL;
+
+		RegCloseKey( hKey );
+		if ( FAILED(hr) )
+			return hr;
+	}
+	else
+	{
+		hr = QUARTZ_OpenCLSIDKey(
+			&hKey, KEY_ALL_ACCESS, FALSE,
+			&CLSID_ActiveMovieCategories, szFilterPath );
+		if ( FAILED(hr) )
+			return NOERROR;
+
+			RegDeleteValueW( hKey, QUARTZ_wszCLSID );
+			RegDeleteValueW( hKey, QUARTZ_wszFriendlyName );
+			RegDeleteValueW( hKey, QUARTZ_wszMerit );
+
+		RegCloseKey( hKey );
+		if ( FAILED(hr) )
+			return hr;
+
+		/* I think key should be deleted only if no subkey exists. */
+		FIXME( "unregister category %s - key should be removed!\n",
+			debugstr_guid(pguidFilterCategory) );
+	}
+
+	return NOERROR;
+}
+
+
+HRESULT QUARTZ_RegisterAMovieFilter(
+	const CLSID* pguidFilterCategory,	/* [IN] Category */
+	const CLSID* pclsid,	/* [IN] CLSID of this filter */
+	const BYTE* pbFilterData,	/* [IN] filter data(no spec) */
+	DWORD cbFilterData,	/* [IN] size of the filter data */
+	LPCWSTR lpFriendlyName,	/* [IN] friendly name */
+	LPCWSTR lpInstance,	/* [IN] instance */
+	BOOL fRegister )	/* [IN] TRUE = register, FALSE = unregister */
+{
+	HRESULT	hr;
+	HKEY	hKey;
+	WCHAR	szFilterPath[ 256 ];
+	WCHAR	szCLSID[ 256 ];
+
+	QUARTZ_GUIDtoString( szCLSID, pclsid );
+	strcpyW( szFilterPath, QUARTZ_wszInstance );
+	QUARTZ_CatPathSepW( szFilterPath );
+	strcatW( szFilterPath, ( lpInstance != NULL ) ? lpInstance : szCLSID );
+
+	if ( fRegister )
+	{
+		hr = QUARTZ_OpenCLSIDKey(
+			&hKey, KEY_ALL_ACCESS, TRUE,
+			pguidFilterCategory, szFilterPath );
+		if ( FAILED(hr) )
+			return hr;
+
+			if ( QUARTZ_RegSetValueString(
+				hKey, QUARTZ_wszCLSID, szCLSID ) != ERROR_SUCCESS )
+				hr = E_FAIL;
+			if ( pbFilterData != NULL && cbFilterData > 0 &&
+				 QUARTZ_RegSetValueBinary(
+				 	hKey, QUARTZ_wszFilterData,
+				 	pbFilterData, cbFilterData ) != ERROR_SUCCESS )
+				hr = E_FAIL;
+			if ( lpFriendlyName != NULL && QUARTZ_RegSetValueString(
+				hKey, QUARTZ_wszFriendlyName,
+				lpFriendlyName ) != ERROR_SUCCESS )
+				hr = E_FAIL;
+
+		RegCloseKey( hKey );
+		if ( FAILED(hr) )
+			return hr;
+	}
+	else
+	{
+		hr = QUARTZ_OpenCLSIDKey(
+			&hKey, KEY_ALL_ACCESS, FALSE,
+			pguidFilterCategory, szFilterPath );
+		if ( FAILED(hr) )
+			return NOERROR;
+
+			RegDeleteValueW( hKey, QUARTZ_wszCLSID );
+			RegDeleteValueW( hKey, QUARTZ_wszFilterData );
+			RegDeleteValueW( hKey, QUARTZ_wszFriendlyName );
+
+		RegCloseKey( hKey );
+		if ( FAILED(hr) )
+			return hr;
+
+		/* I think key should be deleted only if no subkey exists. */
+		FIXME( "unregister category %s filter %s - key should be removed!\n",
+			debugstr_guid(pguidFilterCategory),
+			debugstr_guid(pclsid) );
+	}
+
+	return NOERROR;
 }
 
 
diff --git a/dlls/quartz/regsvr.h b/dlls/quartz/regsvr.h
index 71028f7bac6..62b83bd3f42 100644
--- a/dlls/quartz/regsvr.h
+++ b/dlls/quartz/regsvr.h
@@ -7,23 +7,49 @@
 #ifndef	QUARTZ_REGSVR_H
 #define	QUARTZ_REGSVR_H
 
+extern const WCHAR QUARTZ_wszREG_SZ[];
+extern const WCHAR QUARTZ_wszInprocServer32[];
+extern const WCHAR QUARTZ_wszThreadingModel[];
+extern const WCHAR QUARTZ_wszBoth[];
+extern const WCHAR QUARTZ_wszCLSID[];
+extern const WCHAR QUARTZ_wszFilterData[];
+extern const WCHAR QUARTZ_wszFriendlyName[];
+extern const WCHAR QUARTZ_wszInstance[];
+extern const WCHAR QUARTZ_wszMerit[];
 
-HRESULT QUARTZ_RegisterDLLServer(
-	const CLSID* pclsid,
-	LPCSTR lpFriendlyName,
-	LPCSTR lpNameOfDLL );
-HRESULT QUARTZ_UnregisterDLLServer(
-	const CLSID* pclsid );
 
-HRESULT QUARTZ_RegisterFilter(
-	const CLSID* pguidFilterCategory,
+HRESULT QUARTZ_CreateCLSIDPath(
+	WCHAR* pwszBuf, DWORD dwBufLen,
 	const CLSID* pclsid,
-	const BYTE* pbFilterData,
-	DWORD cbFilterData,
-	LPCSTR lpFriendlyName );
-HRESULT QUARTZ_UnregisterFilter(
-	const CLSID* pguidFilterCategory,
-	const CLSID* pclsid );
+	LPCWSTR lpszPathFromCLSID );
+
+HRESULT QUARTZ_OpenCLSIDKey(
+	HKEY* phkey,	/* [OUT] hKey */
+	REGSAM rsAccess,	/* [IN] access */
+	BOOL fCreate,	/* TRUE = RegCreateKey, FALSE = RegOpenKey */
+	const CLSID* pclsid,	/* CLSID */
+	LPCWSTR lpszPathFromCLSID );	/* related path from CLSID */
+
+HRESULT QUARTZ_RegisterAMovieDLLServer(
+	const CLSID* pclsid,	/* [IN] CLSID */
+	LPCWSTR lpFriendlyName,	/* [IN] Friendly name */
+	LPCWSTR lpNameOfDLL,	/* [IN] name of the registered DLL */
+	BOOL fRegister );	/* [IN] TRUE = register, FALSE = unregister */
+
+HRESULT QUARTZ_RegisterCategory(
+	const CLSID* pguidFilterCategory,	/* [IN] Category */
+	LPCWSTR lpFriendlyName,	/* [IN] friendly name */
+	DWORD dwMerit,	/* [IN] merit */
+	BOOL fRegister );	/* [IN] TRUE = register, FALSE = unregister */
+
+HRESULT QUARTZ_RegisterAMovieFilter(
+	const CLSID* pguidFilterCategory,	/* [IN] Category */
+	const CLSID* pclsid,	/* [IN] CLSID of this filter */
+	const BYTE* pbFilterData,	/* [IN] filter data(no spec) */
+	DWORD cbFilterData,	/* [IN] size of the filter data */
+	LPCWSTR lpFriendlyName,	/* [IN] friendly name */
+	LPCWSTR lpInstance,	/* [IN] instance */
+	BOOL fRegister );	/* [IN] TRUE = register, FALSE = unregister */
 
 
 #endif	/* QUARTZ_REGSVR_H */
diff --git a/dlls/quartz/sysclock.c b/dlls/quartz/sysclock.c
index fd611b8b9df..dd1e2c64393 100644
--- a/dlls/quartz/sysclock.c
+++ b/dlls/quartz/sysclock.c
@@ -29,9 +29,18 @@ static QUARTZ_IFEntry IFEntries[] =
   { &IID_IReferenceClock, offsetof(CSystemClock,refclk)-offsetof(CSystemClock,unk) },
 };
 
+
+static void QUARTZ_DestroySystemClock(IUnknown* punk)
+{
+	CSystemClock_THIS(punk,unk);
+
+	CSystemClock_UninitIReferenceClock( This );
+}
+
 HRESULT QUARTZ_CreateSystemClock(IUnknown* punkOuter,void** ppobj)
 {
 	CSystemClock*	psc;
+	HRESULT	hr;
 
 	TRACE("(%p,%p)\n",punkOuter,ppobj);
 
@@ -40,10 +49,16 @@ HRESULT QUARTZ_CreateSystemClock(IUnknown* punkOuter,void** ppobj)
 		return E_OUTOFMEMORY;
 
 	QUARTZ_IUnkInit( &psc->unk, punkOuter );
-	CSystemClock_InitIReferenceClock( psc );
+	hr = CSystemClock_InitIReferenceClock( psc );
+	if ( FAILED(hr) )
+	{
+		QUARTZ_FreeObj( psc );
+		return hr;
+	}
 
 	psc->unk.pEntries = IFEntries;
 	psc->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
+	psc->unk.pOnFinalRelease = QUARTZ_DestroySystemClock;
 
 	*ppobj = (void*)(&psc->unk);
 
diff --git a/dlls/quartz/sysclock.h b/dlls/quartz/sysclock.h
index 1e3db405ccf..2fe961386e3 100644
--- a/dlls/quartz/sysclock.h
+++ b/dlls/quartz/sysclock.h
@@ -31,7 +31,8 @@ typedef struct CSystemClock
 
 HRESULT QUARTZ_CreateSystemClock(IUnknown* punkOuter,void** ppobj);
 
-void CSystemClock_InitIReferenceClock( CSystemClock* psc );
+HRESULT CSystemClock_InitIReferenceClock( CSystemClock* psc );
+void CSystemClock_UninitIReferenceClock( CSystemClock* psc );
 
 
 #endif  /* WINE_DSHOW_SYSCLOCK_H */
-- 
GitLab