Qcap (Without v4l this time)

Maarten Lankhorst m.b.lankhorst at gmail.com
Thu May 5 12:44:53 CDT 2005


Adding stubby CaptureGraphBuilder
Adding VfwCapture and a NULL driver for it
Copied a lot of general dll functions from quartz 
(DllRegisterServer/ClassFactory etc)
-------------- next part --------------
diff -Nru wine-old/dlls/qcap/capturegraph.c wine-new/dlls/qcap/capturegraph.c
--- wine-old/dlls/qcap/capturegraph.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/capturegraph.c	2005-04-29 00:31:34.000000000 +0200
@@ -0,0 +1,196 @@
+/* Capture Graph Builder, Minimal edition..
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * TODO: Implement CaptureGraphBuilder2, and make all calls from
+ * CaptureGraphBuilder forward to it..
+ */
+
+#include "config.h"
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "qcap_private.h"
+
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "evcode.h"
+#include "strmif.h"
+#include "ddraw.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+static const ICaptureGraphBuilderVtbl Builder_Vtbl;
+
+typedef struct CaptureGraphImpl
+{
+   const ICaptureGraphBuilderVtbl * lpVtbl;
+   IGraphBuilder *mygraph;
+
+   ULONG refCount;
+   CRITICAL_SECTION csFilter;
+} CaptureGraphImpl;
+
+HRESULT CaptureGraphBuilder_create(IUnknown * pUnkOuter, LPVOID * ppv)
+{
+   CaptureGraphImpl * pCapture;
+   TRACE("(%p, %p)\n", pUnkOuter, ppv);
+   *ppv = NULL;
+   if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+   pCapture = CoTaskMemAlloc(sizeof(CaptureGraphImpl));
+   pCapture->lpVtbl = &Builder_Vtbl;
+   pCapture->refCount = 1;
+   pCapture->mygraph = NULL;
+   InitializeCriticalSection(&pCapture->csFilter);
+   *ppv = (LPVOID)pCapture;
+   return S_OK;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder * iface, REFIID riid, LPVOID * ppv)
+{
+   struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+   TRACE("(%p/%p)->(%s, %p)\n", This, iface, qcdebugstr_guid(riid), ppv);
+   *ppv = NULL;
+   if (IsEqualIID(riid, &IID_IUnknown))
+      *ppv = (LPVOID)This;
+   else if (IsEqualIID(riid, &IID_ICaptureGraphBuilder))
+      *ppv = (LPVOID)This;
+
+   if (*ppv)
+   {
+       IUnknown_AddRef((IUnknown *)(*ppv));
+       return S_OK;
+   }
+
+   FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI CaptureGraphBuilder_AddRef(ICaptureGraphBuilder * iface)
+{
+   CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+   ULONG refCount = InterlockedIncrement(&This->refCount);
+
+   TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, refCount - 1);
+   return refCount;
+}
+
+static ULONG WINAPI CaptureGraphBuilder_Release(ICaptureGraphBuilder * iface)
+{
+   CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+   ULONG refCount = InterlockedDecrement(&This->refCount);
+
+   TRACE("(%p/%p)->() Release from %ld\n", This, iface, refCount + 1);
+
+   if (!refCount) {
+      TRACE("Destroying everything..\n");
+      DeleteCriticalSection(&This->csFilter);
+      if (This->mygraph != NULL)
+        IGraphBuilder_Release((IGraphBuilder *)This->mygraph);
+      CoTaskMemFree(This);
+      return 0;
+   }
+   else return refCount;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_SetFilterGraph(ICaptureGraphBuilder * iface, IGraphBuilder *pfg)
+{
+/* The graph builder will automatically create a filter graph if you don't call this method. If you call this method after the graph builder has created its own filter graph, the call will fail. */
+   struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+   if (This->mygraph != NULL) return E_NOTIMPL;
+   This->mygraph = pfg;
+   IGraphBuilder_AddRef((IGraphBuilder *)This->mygraph);
+   TRACE("%p: %p\n", iface, pfg);
+   return S_OK;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_GetFilterGraph(ICaptureGraphBuilder * iface, IGraphBuilder **pfg)
+{
+   struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+   FIXME("%p: Make our own filtergraph if we haven't got one already - stub\n", iface);
+   if (This->mygraph == NULL) return E_NOTIMPL;
+
+   *pfg = This->mygraph;
+   IGraphBuilder_AddRef((IGraphBuilder *)This->mygraph);
+   
+   TRACE("%p: %p\n", iface, *pfg);
+   return S_OK;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder * iface, const GUID *pType, LPCOLESTR lpstrFile,IBaseFilter **ppf, IFileSinkFilter **ppSink)
+{
+   FIXME("%p: %p, %p, %p, %p - stub\n", iface, pType, lpstrFile, *ppf, *ppSink);
+   return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_FindInterface(ICaptureGraphBuilder * iface, const GUID *pCategory, IBaseFilter *pf, REFIID riid, void **ppint)
+{
+   struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+   FIXME("%p: %s %p %s %p - unwanted partial stub!\n", This, qcdebugstr_guid(pCategory), pf, qcdebugstr_guid(riid), *ppint);
+   return IBaseFilter_QueryInterface(pf, riid, ppint);
+   /* Looks for the specified interface on the filter, upstream and
+    * downstream from the filter, and, optionally, only on the output
+    * pin of the given category.
+    */
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface, const GUID *pCategory, IUnknown *pSource, IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
+{
+   FIXME("%p: stub\n", iface);
+   return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_ControlStream(ICaptureGraphBuilder * iface, const GUID *pCategory, IBaseFilter *pFilter, REFERENCE_TIME *pstart, REFERENCE_TIME *pstop, WORD wStartCookie, WORD wStopCookie)
+{
+   FIXME("%p: stub\n", iface);
+   return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder * iface, LPCOLESTR lpstr, DWORDLONG dwlSize)
+{
+   FIXME("%p: stub\n", iface);
+   return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder * iface, LPOLESTR lpwstrOld, LPOLESTR lpwstrNew, int fAllowEscAbort, IAMCopyCaptureFileProgress *pCallback)
+{
+   FIXME("%p: stub\n", iface);
+   return E_NOTIMPL;
+}
+
+static const ICaptureGraphBuilderVtbl Builder_Vtbl =
+{   
+   CaptureGraphBuilder_QueryInterface,
+   CaptureGraphBuilder_AddRef,
+   CaptureGraphBuilder_Release,
+   CaptureGraphBuilder_SetFilterGraph,
+   CaptureGraphBuilder_GetFilterGraph,
+   CaptureGraphBuilder_SetOutputFileName,
+   CaptureGraphBuilder_FindInterface,
+   CaptureGraphBuilder_RenderStream,
+   CaptureGraphBuilder_ControlStream,
+   CaptureGraphBuilder_AllocCapFile,
+   CaptureGraphBuilder_CopyCaptureFile
+};
+
diff -Nru wine-old/dlls/qcap/capture.h wine-new/dlls/qcap/capture.h
--- wine-old/dlls/qcap/capture.h	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/capture.h	2005-05-02 13:07:38.000000000 +0200
@@ -0,0 +1,45 @@
+/* DirectShow private capture header (QCAP.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and DirectDraw creation functions.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __CAPTURE_H__
+#define __CAPTURE_H__
+
+/* Initialisation */
+HRESULT Capture_Initialise(void ** pointer, IPin *pOut, USHORT card);
+
+/* Control */
+HRESULT Capture_GetMediaType(void * pBox, AM_MEDIA_TYPE ** mT);
+HRESULT Capture_SetMediaType(void * pBox, AM_MEDIA_TYPE * mT);
+HRESULT Capture_GetPropRange(void * pBox, long Property, long *pMin, long *pMax, long *pSteppingDelta, long *pDefault, long *pCapsFlags);
+HRESULT Capture_GetProp(void *pBox, long Property, long *lValue, long *Flags);
+HRESULT Capture_SetProp(void *pBox, long Property, long lValue, long Flags);
+
+/* Stream control */
+HRESULT Capture_Run(void * pBox, FILTER_STATE *state);
+HRESULT Capture_Stop(void * pBox, FILTER_STATE *state);
+HRESULT Capture_Pause(void * pBox, FILTER_STATE *state);
+
+/* Destruction */
+HRESULT Capture_Destroy(void * pBox, BOOL destroyall);
+
+#endif /* __CAPTURE_H__ */
+
diff -Nru wine-old/dlls/qcap/enumpins.c wine-new/dlls/qcap/enumpins.c
--- wine-old/dlls/qcap/enumpins.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/enumpins.c	2005-04-29 13:40:15.000000000 +0200
@@ -0,0 +1,183 @@
+/*
+ * Generic Implementation of IPin Interface
+ *
+ * Copyright 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "qcap_private.h"
+#include "pin.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "uuids.h"
+#include "vfwmsgs.h"
+#include <assert.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+typedef struct IEnumPinsImpl
+{
+    const IEnumPinsVtbl * lpVtbl;
+    ULONG refCount;
+    ENUMPINDETAILS enumPinDetails;
+    ULONG uIndex;
+} IEnumPinsImpl;
+
+static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
+
+HRESULT IEnumPinsImpl_Construct(const ENUMPINDETAILS * pDetails, IEnumPins ** ppEnum)
+{
+    IEnumPinsImpl * pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
+    TRACE("()\n");
+    if (!pEnumPins)
+    {
+        *ppEnum = NULL;
+        return E_OUTOFMEMORY;
+    }
+    pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
+    pEnumPins->refCount = 1;
+    pEnumPins->uIndex = 0;
+    CopyMemory(&pEnumPins->enumPinDetails, pDetails, sizeof(ENUMPINDETAILS));
+    *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
+    return S_OK;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
+{
+    TRACE("(%s, %p)\n", qcdebugstr_guid(riid), ppv);
+
+    *ppv = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown))
+        *ppv = (LPVOID)iface;
+    else if (IsEqualIID(riid, &IID_IEnumPins))
+        *ppv = (LPVOID)iface;
+
+    if (*ppv)
+    {
+        IUnknown_AddRef((IUnknown *)(*ppv));
+        return S_OK;
+    }
+
+    FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+
+    return E_NOINTERFACE;
+}
+static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
+{
+    IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+    ULONG refCount = InterlockedIncrement(&This->refCount);
+
+    TRACE("() -> %lu\n", refCount);
+
+    return refCount;
+}
+
+static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
+{
+    IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+    ULONG refCount = InterlockedDecrement(&This->refCount);
+
+    TRACE("() -> %lu\n", refCount);
+
+    if (!refCount)
+    {
+        CoTaskMemFree(This);
+        return 0;
+    }
+    else
+        return refCount;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
+{
+    ULONG cFetched;
+    IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+    TRACE("()\n");
+
+    cFetched = min(This->enumPinDetails.cPins, This->uIndex + cPins) - This->uIndex;
+
+    TRACE("(%lu, %p, %p)\n", cPins, ppPins, pcFetched);
+
+    if (cFetched > 0)
+    {
+        ULONG i;
+        for (i = 0; i < cFetched; i++) {
+            IPin_AddRef(This->enumPinDetails.ppPins[This->uIndex + i]);
+            ppPins[i] = This->enumPinDetails.ppPins[This->uIndex + i];
+        }
+    }
+
+    if ((cPins != 1) || pcFetched)
+        *pcFetched = cFetched;
+
+    This->uIndex += cFetched;
+
+    if (cFetched != cPins)
+        return S_FALSE;
+    return S_OK;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
+{
+    IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+    TRACE("(%lu)\n", cPins);
+
+    if (This->uIndex + cPins < This->enumPinDetails.cPins)
+    {
+        This->uIndex += cPins;
+        return S_OK;
+    }
+    return S_FALSE;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
+{
+    IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+    TRACE("IEnumPinsImpl::Reset()\n");
+
+    This->uIndex = 0;
+    return S_OK;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
+{
+    HRESULT hr;
+    IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+    TRACE("(%p)\n", ppEnum);
+
+    hr = IEnumPinsImpl_Construct(&This->enumPinDetails, ppEnum);
+    if (FAILED(hr))
+        return hr;
+    return IEnumPins_Skip(*ppEnum, This->uIndex);
+}
+
+static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
+{
+    IEnumPinsImpl_QueryInterface,
+    IEnumPinsImpl_AddRef,
+    IEnumPinsImpl_Release,
+    IEnumPinsImpl_Next,
+    IEnumPinsImpl_Skip,
+    IEnumPinsImpl_Reset,
+    IEnumPinsImpl_Clone
+};
+
diff -Nru wine-old/dlls/qcap/Makefile.in wine-new/dlls/qcap/Makefile.in
--- wine-old/dlls/qcap/Makefile.in	2004-05-14 23:37:32.000000000 +0200
+++ wine-new/dlls/qcap/Makefile.in	2005-05-01 01:56:42.000000000 +0200
@@ -3,8 +3,18 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = qcap.dll
+IMPORTS   = ole32 kernel32 advapi32 user32
+EXTRALIBS = -lstrmiids -luuid $(LIBUNICODE)
 
-C_SRCS = qcap_main.c
+C_SRCS =  \
+         capturegraph.c \
+         enumpins.c \
+         media.c \
+         null.c \
+         pin.c \
+         qcap_main.c \
+         regsvr.c \
+         vfwcapture.c
 
 RC_SRCS = version.rc
 
diff -Nru wine-old/dlls/qcap/media.c wine-new/dlls/qcap/media.c
--- wine-old/dlls/qcap/media.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/media.c	2005-05-01 01:48:09.000000000 +0200
@@ -0,0 +1,229 @@
+/*
+ * Implementation of IEnumMediaTypes Interface
+ *
+ * Copyright 2003 Robert Shearman
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *  
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */ 
+
+#include "qcap_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
+{
+    memcpy(pDest, pSrc, sizeof(AM_MEDIA_TYPE));
+    if (!pDest->pbFormat) return S_OK;
+    if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
+        return E_OUTOFMEMORY;
+    memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
+    return S_OK;
+}
+
+void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
+{
+    if (pMediaType->pbFormat)
+    {
+        CoTaskMemFree(pMediaType->pbFormat);
+        pMediaType->pbFormat = NULL;
+    }
+    if (pMediaType->pUnk)
+    {
+        IUnknown_Release(pMediaType->pUnk);
+        pMediaType->pUnk = NULL;
+    }
+    CoTaskMemFree(pMediaType);
+}
+
+BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
+{
+    TRACE("pmt1: ");
+    dump_AM_MEDIA_TYPE(pmt1);
+    TRACE("pmt2: ");
+    dump_AM_MEDIA_TYPE(pmt2);
+    return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
+            ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL)   || IsEqualGUID(&pmt2->subtype, &GUID_NULL)))   || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
+}   
+
+void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt)
+{
+    if (!pmt)
+        return;
+    TRACE("\t%s\n\t%s\n\t...\n\t%s\n", qcdebugstr_guid(&pmt->majortype), qcdebugstr_guid(&pmt->subtype), qcdebugstr_guid(&pmt->formattype));
+}
+
+typedef struct IEnumMediaTypesImpl
+{
+    const IEnumMediaTypesVtbl * lpVtbl;
+    ULONG refCount;
+    ENUMMEDIADETAILS enumMediaDetails;
+    ULONG uIndex;
+} IEnumMediaTypesImpl;
+
+static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
+
+HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum)
+{
+    ULONG i;
+    IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
+
+    if (!pEnumMediaTypes)
+    {
+        *ppEnum = NULL;
+        return E_OUTOFMEMORY;
+    }
+    pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
+    pEnumMediaTypes->refCount = 1;
+    pEnumMediaTypes->uIndex = 0;
+    pEnumMediaTypes->enumMediaDetails.cMediaTypes = pDetails->cMediaTypes;
+    pEnumMediaTypes->enumMediaDetails.pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * pDetails->cMediaTypes);
+    for (i = 0; i < pDetails->cMediaTypes; i++)
+        CopyMediaType(&pEnumMediaTypes->enumMediaDetails.pMediaTypes[i], &pDetails->pMediaTypes[i]);
+    *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
+    return S_OK;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
+{
+    TRACE("(%s, %p)\n", qcdebugstr_guid(riid), ppv);
+
+    *ppv = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown))
+        *ppv = (LPVOID)iface;
+    else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
+        *ppv = (LPVOID)iface;
+
+    if (*ppv)
+    {
+        IUnknown_AddRef((IUnknown *)(*ppv));
+        return S_OK;
+    }
+
+    FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
+{
+    IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+    ULONG refCount = InterlockedIncrement(&This->refCount);
+
+    TRACE("()\n");
+
+    return refCount;
+}
+
+static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
+{
+    IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+    ULONG refCount = InterlockedDecrement(&This->refCount);
+
+    TRACE("()\n");
+
+    if (!refCount)
+    {
+        int i;
+        for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++)
+            if (This->enumMediaDetails.pMediaTypes[i].pbFormat)
+                CoTaskMemFree(This->enumMediaDetails.pMediaTypes[i].pbFormat);
+        CoTaskMemFree(This->enumMediaDetails.pMediaTypes);
+        CoTaskMemFree(This);
+        return 0;
+    }
+    else
+        return refCount;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
+{
+    ULONG cFetched;
+    IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+    cFetched = min(This->enumMediaDetails.cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
+
+    TRACE("(%lu, %p, %p)\n", cMediaTypes, ppMediaTypes, pcFetched);
+    TRACE("Next uIndex: %lu, cFetched: %lu\n", This->uIndex, cFetched);
+
+    if (cFetched > 0)
+    {
+        ULONG i;
+        *ppMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cFetched);
+        for (i = 0; i < cFetched; i++)
+            CopyMediaType(&(*ppMediaTypes)[i], &This->enumMediaDetails.pMediaTypes[This->uIndex + i]);
+    }
+
+    if ((cMediaTypes != 1) || pcFetched)
+        *pcFetched = cFetched;
+
+    This->uIndex += cFetched;
+
+    if (cFetched != cMediaTypes)
+        return S_FALSE;
+    return S_OK;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
+{
+    IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+    TRACE("(%lu)\n", cMediaTypes);
+
+    if (This->uIndex + cMediaTypes < This->enumMediaDetails.cMediaTypes)
+    {
+        This->uIndex += cMediaTypes;
+        return S_OK;
+    }
+    return S_FALSE;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
+{
+    IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+    TRACE("()\n");
+
+    This->uIndex = 0;
+    return S_OK;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
+{
+    HRESULT hr;
+    IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+    TRACE("(%p)\n", ppEnum);
+    hr = IEnumMediaTypesImpl_Construct(&This->enumMediaDetails, ppEnum);
+
+    if (FAILED(hr))
+        return hr;
+    return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
+}
+
+static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
+{
+    IEnumMediaTypesImpl_QueryInterface,
+    IEnumMediaTypesImpl_AddRef,
+    IEnumMediaTypesImpl_Release,
+    IEnumMediaTypesImpl_Next,
+    IEnumMediaTypesImpl_Skip,
+    IEnumMediaTypesImpl_Reset,
+    IEnumMediaTypesImpl_Clone
+};
+
diff -Nru wine-old/dlls/qcap/null.c wine-new/dlls/qcap/null.c
--- wine-old/dlls/qcap/null.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/null.c	2005-05-05 14:54:42.000000000 +0200
@@ -0,0 +1,89 @@
+/* DirectShow capture services (QCAP.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the part of the vfw capture interface that
+ * does the actual capturing stuff required for capturing
+ * and setting/getting media format..
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Why on earth am I writing a copyright notice for a NULL renderer???
+ */
+
+#include "config.h"
+#if 1
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "qcap_private.h"
+#include "pin.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+HRESULT Capture_Initialise(void ** pointer, IPin *pOut, USHORT card)
+{
+   ERR("No DirectShow Video for Wine Capture support compiled\n");
+   return E_FAIL;
+}
+
+HRESULT Capture_GetMediaType(void * pBox, AM_MEDIA_TYPE ** mT)
+{
+   return E_FAIL;
+}
+
+HRESULT Capture_SetMediaType(void * pBox, AM_MEDIA_TYPE * mT)
+{
+   return E_FAIL;
+}
+
+HRESULT Capture_GetPropRange(void * pBox, long Property, long *pMin, long *pMax, long *pSteppingDelta, long *pDefault, long *pCapsFlags)
+{
+   return E_FAIL;
+}
+
+HRESULT Capture_GetProp(void *pBox, long Property, long *lValue, long *Flags)
+{
+   return E_FAIL;
+}
+
+HRESULT Capture_SetProp(void *pBox, long Property, long lValue, long Flags)
+{
+   return E_FAIL;
+}
+
+HRESULT Capture_Run(void * pBox, FILTER_STATE *state)
+{
+   return E_FAIL;
+}
+
+HRESULT Capture_Stop(void * pBox, FILTER_STATE *state)
+{
+   return E_FAIL;
+}
+
+HRESULT Capture_Pause(void * pBox, FILTER_STATE *state)
+{
+   return E_FAIL;
+}
+
+HRESULT Capture_Destroy(void * pBox, BOOL destroyall)
+{
+   return E_FAIL;
+}
+
+#endif
+
diff -Nru wine-old/dlls/qcap/pin.c wine-new/dlls/qcap/pin.c
--- wine-old/dlls/qcap/pin.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/pin.c	2005-04-30 18:44:10.000000000 +0200
@@ -0,0 +1,411 @@
+/*
+ * Generic Implementation of IPin Interface
+ *
+ * Copyright 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "qcap_private.h"
+#include "pin.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "uuids.h"
+#include "vfwmsgs.h"
+#include <assert.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+#define ALIGNDOWN(value,boundary) ((value) & ~(boundary-1))
+#define ALIGNUP(value,boundary) (ALIGNDOWN(value - 1, boundary) + boundary)
+
+static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
+{
+    /* Tempting to just do a memcpy, but the name field is
+       128 characters long! We will probably never exceed 10
+       most of the time, so we are better off copying 
+       each field manually */
+    strcpyW(pDest->achName, pSrc->achName);
+    pDest->dir = pSrc->dir;
+    pDest->pFilter = pSrc->pFilter;
+}
+
+HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin)
+{
+    HRESULT hr;
+    IPinImpl *This = (IPinImpl *)iface;
+
+/*  TRACE("(%p)\n", ppPin);*/
+
+    EnterCriticalSection(This->pCritSec);
+    {
+        if (This->pConnectedTo)
+        {
+            *ppPin = This->pConnectedTo;
+            IPin_AddRef(*ppPin);
+            hr = S_OK;
+        }
+        else
+            hr = VFW_E_NOT_CONNECTED;
+    }
+    LeaveCriticalSection(This->pCritSec);
+
+    return hr;
+}
+
+HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
+{
+    HRESULT hr;
+    IPinImpl *This = (IPinImpl *)iface;
+
+    TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
+
+    EnterCriticalSection(This->pCritSec);
+    {
+        if (This->pConnectedTo)
+        {
+            CopyMediaType(pmt, &This->mtCurrent);
+            hr = S_OK;
+        }
+        else
+        {
+            ZeroMemory(pmt, sizeof(*pmt));
+            hr = VFW_E_NOT_CONNECTED;
+        }
+    }
+    LeaveCriticalSection(This->pCritSec);
+
+    return hr;
+}
+
+HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
+{
+    IPinImpl *This = (IPinImpl *)iface;
+
+    TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
+
+    Copy_PinInfo(pInfo, &This->pinInfo);
+    IBaseFilter_AddRef(pInfo->pFilter);
+
+    return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
+{
+    IPinImpl *This = (IPinImpl *)iface;
+
+    TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir);
+
+    *pPinDir = This->pinInfo.dir;
+
+    return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id)
+{
+    IPinImpl *This = (IPinImpl *)iface;
+
+    TRACE("(%p/%p)->(%p)\n", This, iface, Id);
+
+    *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR));
+    if (!Id)
+        return E_OUTOFMEMORY;
+
+    strcpyW(*Id, This->pinInfo.achName);
+
+    return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
+{
+    IPinImpl *This = (IPinImpl *)iface;
+
+    TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
+
+    if (!This->fnQueryAccept) return S_OK;
+
+    return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE);
+}
+
+HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
+{
+    IPinImpl *This = (IPinImpl *)iface;
+
+    TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin);
+
+    return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
+}
+
+/* Function called as a helper to IPin_Connect */
+/* specific AM_MEDIA_TYPE - it cannot be NULL */
+/* NOTE: not part of standard interface */
+static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+    OutputPin *This = (OutputPin *)iface;
+    HRESULT hr;
+    IMemAllocator * pMemAlloc = NULL;
+    ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */
+
+    TRACE("(%p, %p)\n", pReceivePin, pmt);
+    dump_AM_MEDIA_TYPE(pmt);
+
+    /* FIXME: call queryacceptproc */
+    
+    This->pin.pConnectedTo = pReceivePin;
+    IPin_AddRef(pReceivePin);
+    CopyMediaType(&This->pin.mtCurrent, pmt);
+
+    hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
+
+    /* get the IMemInputPin interface we will use to deliver samples to the
+     * connected pin */
+    if (SUCCEEDED(hr))
+    {
+        hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
+
+        if (SUCCEEDED(hr))
+            hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc);
+
+        if (hr == VFW_E_NO_ALLOCATOR)
+        {
+            /* Input pin provides no allocator, use standard memory allocator */
+            hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc);
+
+            if (SUCCEEDED(hr))
+            {
+                hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, FALSE);
+            }
+        }
+
+        if (SUCCEEDED(hr))
+            hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual);
+
+        if (pMemAlloc)
+            IMemAllocator_Release(pMemAlloc);
+
+        /* break connection if we couldn't get the allocator */
+        if (FAILED(hr))
+            IPin_Disconnect(pReceivePin);
+    }
+
+    if (FAILED(hr))
+    {
+        IPin_Release(This->pin.pConnectedTo);
+        This->pin.pConnectedTo = NULL;
+        DeleteMediaType(&This->pin.mtCurrent);
+    }
+
+    TRACE(" -- %lx\n", hr);
+    return hr;
+}
+
+HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl)
+{
+    TRACE("\n");
+
+    /* Common attributes */
+    pPinImpl->pin.refCount = 1;
+    pPinImpl->pin.pConnectedTo = NULL;
+    pPinImpl->pin.fnQueryAccept = pQueryAccept;
+    pPinImpl->pin.pUserData = pUserData;
+    pPinImpl->pin.pCritSec = pCritSec;
+    Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
+
+    /* Output pin attributes */
+    pPinImpl->pMemInputPin = NULL;
+    pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific;
+    if (props)
+    {
+        memcpy(&pPinImpl->allocProps, props, sizeof(pPinImpl->allocProps));
+        if (pPinImpl->allocProps.cbAlign == 0)
+            pPinImpl->allocProps.cbAlign = 1;
+    }
+    else
+        ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps));
+
+    return S_OK;
+}
+
+HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+    HRESULT hr;
+    OutputPin *This = (OutputPin *)iface;
+
+    TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
+    dump_AM_MEDIA_TYPE(pmt);
+
+    /* If we try to connect to ourself, we will definitely deadlock.
+     * There are other cases where we could deadlock too, but this
+     * catches the obvious case */
+    assert(pReceivePin != iface);
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        /* if we have been a specific type to connect with, then we can either connect
+         * with that or fail. We cannot choose different AM_MEDIA_TYPE */
+        if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
+            hr = This->pConnectSpecific(iface, pReceivePin, pmt);
+        else
+        {
+            /* negotiate media type */
+
+            IEnumMediaTypes * pEnumCandidates;
+            AM_MEDIA_TYPE * pmtCandidate; /* Candidate media type */
+
+            if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates)))
+            {
+                hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
+
+                /* try this filter's media types first */
+                while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
+                {
+                    if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) &&
+                        (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
+                    {
+                        hr = S_OK;
+                        TRACE("o_o\n");
+                        DeleteMediaType(pmtCandidate);
+                        break;
+                    }
+                    DeleteMediaType(pmtCandidate);
+                }
+                IEnumMediaTypes_Release(pEnumCandidates);
+            }
+
+            /* then try receiver filter's media types */
+            if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
+            {
+                hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
+
+                while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
+                {
+                    if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) &&
+                        (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
+                    {
+                        hr = S_OK;
+                        DeleteMediaType(pmtCandidate);
+                        break;
+                    }
+                    DeleteMediaType(pmtCandidate);
+                } /* while */
+                IEnumMediaTypes_Release(pEnumCandidates);
+            } /* if not found */
+        } /* if negotiate media type */
+    } /* if succeeded */
+    LeaveCriticalSection(This->pin.pCritSec);
+
+    TRACE(" -- %lx\n", hr);
+    return hr;
+}
+
+HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+    ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt);
+
+    return E_UNEXPECTED;
+}
+
+HRESULT WINAPI OutputPin_Disconnect(IPin * iface)
+{
+    HRESULT hr;
+    OutputPin *This = (OutputPin *)iface;
+
+    TRACE("()\n");
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        if (This->pMemInputPin)
+        {
+            IMemInputPin_Release(This->pMemInputPin);
+            This->pMemInputPin = NULL;
+        }
+        if (This->pin.pConnectedTo)
+        {
+            IPin_Release(This->pin.pConnectedTo);
+            This->pin.pConnectedTo = NULL;
+            hr = S_OK;
+        }
+        else
+            hr = S_FALSE;
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+
+    return hr;
+}
+
+HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, DWORD dwFlags)
+{
+    HRESULT hr;
+
+    TRACE("(%p, %p, %p, %lx)\n", ppSample, tStart, tStop, dwFlags);
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        if (!This->pin.pConnectedTo)
+            hr = VFW_E_NOT_CONNECTED;
+        else
+        {
+            IMemAllocator * pAlloc = NULL;
+
+            hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
+
+            if (SUCCEEDED(hr))
+                hr = IMemAllocator_GetBuffer(pAlloc, ppSample, (REFERENCE_TIME *)tStart, (REFERENCE_TIME *)tStop, dwFlags);
+
+            if (SUCCEEDED(hr))
+                hr = IMediaSample_SetTime(*ppSample, (REFERENCE_TIME *)tStart, (REFERENCE_TIME *)tStop);
+
+            if (pAlloc)
+                IMemAllocator_Release(pAlloc);
+        }
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+
+    return hr;
+}
+
+HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample)
+{
+    HRESULT hr = S_OK;
+    IMemInputPin * pMemConnected = NULL;
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        if (!This->pin.pConnectedTo || !This->pMemInputPin)
+            hr = VFW_E_NOT_CONNECTED;
+        else
+        {
+            /* we don't have the lock held when using This->pMemInputPin,
+             * so we need to AddRef it to stop it being deleted while we are
+             * using it. */
+            pMemConnected = This->pMemInputPin;
+            IMemInputPin_AddRef(pMemConnected);
+        }
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+
+    if (SUCCEEDED(hr))
+    {
+        /* NOTE: if we are in a critical section when Receive is called
+         * then it causes some problems (most notably with the native Video
+         * Renderer) if we are re-entered for whatever reason */
+        hr = IMemInputPin_Receive(pMemConnected, pSample);
+        IMemInputPin_Release(pMemConnected);
+    }
+
+    return hr;
+}
+
diff -Nru wine-old/dlls/qcap/pin.h wine-new/dlls/qcap/pin.h
--- wine-old/dlls/qcap/pin.h	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/pin.h	2005-04-29 14:01:43.000000000 +0200
@@ -0,0 +1,81 @@
+/*
+ * IPin function declarations to allow inheritance
+ *
+ * Copyright 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* This function will process incoming samples to the pin.
+ * Any return value valid in IMemInputPin::Receive is allowed here
+ */
+typedef HRESULT (* SAMPLEPROC)(LPVOID userdata, IMediaSample * pSample);
+
+/* This function will determine whether a type is supported or not.
+ * It is allowed to return any error value (within reason), as opposed
+ * to IPin::QueryAccept which is only allowed to return S_OK or S_FALSE.
+ */
+typedef HRESULT (* QUERYACCEPTPROC)(LPVOID userdata, const AM_MEDIA_TYPE * pmt);
+
+/* This function is called prior to finalizing a connection with
+ * another pin and can be used to get things from the other pin
+ * like IMemInput interfaces.
+ */
+typedef HRESULT (* PRECONNECTPROC)(IPin * iface, IPin * pConnectPin);
+
+typedef struct IPinImpl
+{
+	const struct IPinVtbl * lpVtbl;
+	ULONG refCount;
+	LPCRITICAL_SECTION pCritSec;
+	PIN_INFO pinInfo;
+	IPin * pConnectedTo;
+	AM_MEDIA_TYPE mtCurrent;
+	ENUMMEDIADETAILS enumMediaDetails;
+	QUERYACCEPTPROC fnQueryAccept;
+	LPVOID pUserData;
+} IPinImpl;
+
+typedef struct OutputPin
+{
+	/* inheritance C style! */
+	IPinImpl pin;
+
+	IMemInputPin * pMemInputPin;
+	HRESULT (* pConnectSpecific)(IPin * iface, IPin * pReceiver, const AM_MEDIA_TYPE * pmt);
+	ALLOCATOR_PROPERTIES allocProps;
+} OutputPin;
+
+/*** Initializers ***/
+HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl);
+
+/* Common */
+HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin);
+HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo);
+HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir);
+HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id);
+HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum);
+HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin);
+
+/* Output Pin */
+HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI OutputPin_Disconnect(IPin * iface);
+HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt);
+
+HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, DWORD dwFlags);
+HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample);
+
diff -Nru wine-old/dlls/qcap/qcap_main.c wine-new/dlls/qcap/qcap_main.c
--- wine-old/dlls/qcap/qcap_main.c	2004-05-21 22:54:48.000000000 +0200
+++ wine-new/dlls/qcap/qcap_main.c	2005-05-05 09:50:10.000000000 +0200
@@ -1,7 +1,10 @@
-/*
- * Qcap implementation
+/*              DirectShow Capture Base Functions (QCAP.DLL)
  *
- * Copyright (C) 2003 Dominik Strasser
+ * Copyright 2002 Lionel Ulmer
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and DirectDraw creation functions.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -18,26 +21,226 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include "config.h"
 #include "wine/debug.h"
-#include "winerror.h"
 
+#include "qcap_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
 
+/* Currently (partial) supported:
+   - Vfw Capture Filter
+   - CaptureGraphBuilder1 (Should be forwarded to CaptureGraphBuilder2)
+
+   Native qcap also supports:
+   - Avi Mux Property Page 1
+   - Vfw Capture Filter property page
+   - Audio input mixer property page
+   - File writer
+   - Avi mux property page
+   - Audio Capture Filter
+   * Smart tee filter
+   * Infinite pin tee filter
+   * CaptureGraphBuilder2
+
+ a "*" means important, we should work on implementing it..
+ */
+static DWORD dll_ref = 0;
+
+/* For the moment, do nothing here. */
+BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
+{
+    switch(fdwReason) {
+        case DLL_PROCESS_ATTACH:
+            DisableThreadLibraryCalls(hInstDLL);
+	    break;
+	case DLL_PROCESS_DETACH:
+	    break;
+    }
+    return TRUE;
+}
+
+/******************************************************************************
+ * DirectShow ClassFactory
+ */
+typedef struct {
+    IClassFactory ITF_IClassFactory;
+
+    DWORD ref;
+    HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
+} IClassFactoryImpl;
+
+struct object_creation_info
+{
+    const CLSID *clsid;
+    HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
+};
+
+static const struct object_creation_info object_creation[] =
+{
+/* Keep VfwCapture as first, since I did a dirty trick in the class factory,
+ * which would really break if VfwCapture wasn't first..
+ */
+    { &CLSID_VfwCapture, &VfwCapture_create },
+    { &CLSID_CaptureGraphBuilder, &CaptureGraphBuilder_create }
+};
+
+static HRESULT WINAPI
+DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+    if (IsEqualGUID(riid, &IID_IUnknown)
+	|| IsEqualGUID(riid, &IID_IClassFactory))
+    {
+	IClassFactory_AddRef(iface);
+	*ppobj = This;
+	return S_OK;
+    }
+
+    WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI DSCF_AddRef(LPCLASSFACTORY iface)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if (ref == 0)
+	HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+
+static HRESULT WINAPI DSCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
+					  REFIID riid, LPVOID *ppobj)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    HRESULT hres;
+    LPUNKNOWN punk;
+    
+    TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
+
+    *ppobj = NULL;
+    hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
+    if (SUCCEEDED(hres)) {
+        hres = IUnknown_QueryInterface(punk, riid, ppobj);
+        IUnknown_Release(punk);
+    }
+    return hres;
+}
+
+static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    FIXME("(%p)->(%d),stub!\n",This,dolock);
+    return S_OK;
+}
+
+static IClassFactoryVtbl DSCF_Vtbl =
+{
+    DSCF_QueryInterface,
+    DSCF_AddRef,
+    DSCF_Release,
+    DSCF_CreateInstance,
+    DSCF_LockServer
+};
+
+/*******************************************************************************
+ * DllGetClassObject [QCAP.@]
+ * Retrieves class object from a DLL object
+ *
+ * NOTES
+ *    Docs say returns STDAPI
+ *
+ * PARAMS
+ *    rclsid [I] CLSID for the class object
+ *    riid   [I] Reference to identifier of interface for class object
+ *    ppv    [O] Address of variable to receive interface pointer for riid
+ *
+ * RETURNS
+ *    Success: S_OK
+ *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
+ *             E_UNEXPECTED
+ */
+DWORD WINAPI QCAP_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+    unsigned int i;
+    IClassFactoryImpl *factory;
+
+    TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+    
+    if ( !IsEqualGUID( &IID_IClassFactory, riid )
+	 && ! IsEqualGUID( &IID_IUnknown, riid) )
+	return E_NOINTERFACE;
+
+    for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
+    {
+	if (IsEqualGUID(object_creation[i].clsid, rclsid))
+	    break;
+    }
+
+    if (i == sizeof(object_creation)/sizeof(object_creation[0]))
+    {
+	FIXME("%s: no class found.\n", debugstr_guid(rclsid));
+	return CLASS_E_CLASSNOTAVAILABLE;
+    }
+
+    factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
+    if (factory == NULL) return E_OUTOFMEMORY;
+
+    factory->ITF_IClassFactory.lpVtbl = &DSCF_Vtbl;
+    factory->ref = 1;
+
+    factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
+
+    *ppv = &(factory->ITF_IClassFactory);
+    return S_OK;
+}
+
 /***********************************************************************
- *      DllRegisterServer (QCAP.@)
+ *              DllCanUnloadNow (QCAP.@)
  */
-HRESULT WINAPI QCAP_DllRegisterServer()
+HRESULT WINAPI QCAP_DllCanUnloadNow()
 {
-	FIXME("(): stub\n");
-	return 0;
+    return dll_ref != 0 ? S_FALSE : S_OK;
 }
 
+
+#define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+    { { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } } , #name },
+
+static struct {
+	const GUID	riid;
+	const char 	*name;
+} InterfaceDesc[] =
+{
+#include "uuids.h"
+    { { 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }, NULL }
+};
+
 /***********************************************************************
- *		DllGetClassObject (QCAP.@)
+ *              qcdebugstr_guid (internal)
+ *
+ * Gives a text version of QCap Guids
  */
-HRESULT WINAPI QCAP_DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
+const char * qcdebugstr_guid( const GUID * id )
 {
-    FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
-    return CLASS_E_CLASSNOTAVAILABLE;
+    int i;
+    char * name = NULL;
+
+    for (i=0;InterfaceDesc[i].name && !name;i++) {
+        if (IsEqualGUID(&InterfaceDesc[i].riid, id)) return InterfaceDesc[i].name;
+    }
+    return debugstr_guid(id);
 }
+
diff -Nru wine-old/dlls/qcap/qcap_private.h wine-new/dlls/qcap/qcap_private.h
--- wine-old/dlls/qcap/qcap_private.h	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/qcap_private.h	2005-04-29 00:27:34.000000000 +0200
@@ -0,0 +1,64 @@
+/*              Quartz Capture private interfaces (QCAP.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and DirectDraw creation functions.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __QCAP_PRIVATE_INCLUDED__
+#define __QCAP_PRIVATE_INCLUDED__
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "wtypes.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "dshow.h"
+
+#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
+
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv);
+HRESULT CaptureGraphBuilder_create(IUnknown * pUnkOuter, LPVOID * ppv);
+
+typedef struct tagENUMPINDETAILS
+{
+	ULONG cPins;
+	IPin ** ppPins;
+} ENUMPINDETAILS;
+
+typedef struct tagENUMEDIADETAILS
+{
+	ULONG cMediaTypes;
+	AM_MEDIA_TYPE * pMediaTypes;
+} ENUMMEDIADETAILS;
+
+HRESULT IEnumPinsImpl_Construct(const ENUMPINDETAILS * pDetails, IEnumPins ** ppEnum);
+HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum);
+
+extern const char * qcdebugstr_guid(const GUID * id);
+
+HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc);
+void DeleteMediaType(AM_MEDIA_TYPE * pmt);
+BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards);
+void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt);
+
+#endif /* __QCAP_PRIVATE_INCLUDED__ */
diff -Nru wine-old/dlls/qcap/qcap.spec wine-new/dlls/qcap/qcap.spec
--- wine-old/dlls/qcap/qcap.spec	2003-07-30 05:48:55.000000000 +0200
+++ wine-new/dlls/qcap/qcap.spec	2005-04-28 23:07:08.000000000 +0200
@@ -1,4 +1,4 @@
-@ stub DllCanUnloadNow
+@ stdcall -private DllCanUnloadNow() QCAP_DllCanUnloadNow
 @ stdcall -private DllGetClassObject(ptr ptr ptr) QCAP_DllGetClassObject
 @ stdcall -private DllRegisterServer() QCAP_DllRegisterServer
-@ stub DllUnregisterServer
+@ stdcall -private DllUnregisterServer() QCAP_DllUnregisterServer
diff -Nru wine-old/dlls/qcap/regsvr.c wine-new/dlls/qcap/regsvr.c
--- wine-old/dlls/qcap/regsvr.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/regsvr.c	2005-05-05 09:22:03.000000000 +0200
@@ -0,0 +1,934 @@
+/*
+ *	self-registerable dll functions for qcap.dll
+ *
+ * Copyright (C) 2003 John K. Hohm
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#define COBJMACROS
+#define COM_NO_WINDOWS_H
+#include <stdarg.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+
+#include "ole2.h"
+#include "uuids.h"
+#include "strmif.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+/*
+ * Near the bottom of this file are the exported DllRegisterServer and
+ * DllUnregisterServer, which make all this worthwhile.
+ */
+
+/***********************************************************************
+ *		interface for self-registering
+ */
+struct regsvr_interface
+{
+    IID const *iid;		/* NULL for end of list */
+    LPCSTR name;		/* can be NULL to omit */
+    IID const *base_iid;	/* can be NULL to omit */
+    int num_methods;		/* can be <0 to omit */
+    CLSID const *ps_clsid;	/* can be NULL to omit */
+    CLSID const *ps_clsid32;	/* can be NULL to omit */
+};
+
+static HRESULT register_interfaces(struct regsvr_interface const *list);
+static HRESULT unregister_interfaces(struct regsvr_interface const *list);
+
+struct regsvr_coclass
+{
+    CLSID const *clsid;		/* NULL for end of list */
+    LPCSTR name;		/* can be NULL to omit */
+    LPCSTR ips;			/* can be NULL to omit */
+    LPCSTR ips32;		/* can be NULL to omit */
+    LPCSTR ips32_tmodel;	/* can be NULL to omit */
+    LPCSTR progid;		/* can be NULL to omit */
+    LPCSTR viprogid;		/* can be NULL to omit */
+    LPCSTR progid_extra;	/* can be NULL to omit */
+};
+
+static HRESULT register_coclasses(struct regsvr_coclass const *list);
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
+
+struct regsvr_mediatype_parsing
+{
+    CLSID const *majortype;	/* NULL for end of list */
+    CLSID const *subtype;
+    LPCSTR line[11];		/* NULL for end of list */
+};
+
+static HRESULT register_mediatypes_parsing(struct regsvr_mediatype_parsing const *list);
+static HRESULT unregister_mediatypes_parsing(struct regsvr_mediatype_parsing const *list);
+
+struct regsvr_mediatype_extension
+{
+    CLSID const *majortype;	/* NULL for end of list */
+    CLSID const *subtype;
+    LPCSTR extension;
+};
+
+struct mediatype
+{
+    CLSID const *majortype;	/* NULL for end of list */
+    CLSID const *subtype;
+    DWORD fourcc;
+};
+
+struct pin
+{
+    DWORD flags;		/* 0xFFFFFFFF for end of list */
+    struct mediatype mediatypes[11];
+};
+
+struct regsvr_filter
+{
+    CLSID const *clsid;		/* NULL for end of list */
+    CLSID const *category;
+    WCHAR name[50];
+    DWORD merit;
+    struct pin pins[11];
+};
+
+static HRESULT register_mediatypes_extension(struct regsvr_mediatype_extension const *list);
+static HRESULT unregister_mediatypes_extension(struct regsvr_mediatype_extension const *list);
+
+static HRESULT register_filters(struct regsvr_filter const *list);
+static HRESULT unregister_filters(struct regsvr_filter const *list);
+
+/***********************************************************************
+ *		static string constants
+ */
+static WCHAR const interface_keyname[10] = {
+    'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
+static WCHAR const base_ifa_keyname[14] = {
+    'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
+    'e', 0 };
+static WCHAR const num_methods_keyname[11] = {
+    'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
+static WCHAR const ps_clsid_keyname[15] = {
+    'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
+    'i', 'd', 0 };
+static WCHAR const ps_clsid32_keyname[17] = {
+    'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
+    'i', 'd', '3', '2', 0 };
+static WCHAR const clsid_keyname[6] = {
+    'C', 'L', 'S', 'I', 'D', 0 };
+static WCHAR const curver_keyname[7] = {
+    'C', 'u', 'r', 'V', 'e', 'r', 0 };
+static WCHAR const ips_keyname[13] = {
+    'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+    0 };
+static WCHAR const ips32_keyname[15] = {
+    'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+    '3', '2', 0 };
+static WCHAR const progid_keyname[7] = {
+    'P', 'r', 'o', 'g', 'I', 'D', 0 };
+static WCHAR const viprogid_keyname[25] = {
+    'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
+    'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
+    0 };
+static char const tmodel_valuename[] = "ThreadingModel";
+static WCHAR const mediatype_name[11] = {
+    'M', 'e', 'd', 'i', 'a', ' ', 'T', 'y', 'p', 'e', 0 };
+static WCHAR const subtype_valuename[8] = {
+    'S', 'u', 'b', 't', 'y', 'p', 'e', 0 };
+static WCHAR const sourcefilter_valuename[14] = {
+    'S', 'o', 'u', 'r', 'c', 'e', ' ', 'F', 'i', 'l', 't', 'e', 'r', 0 };
+static WCHAR const extensions_keyname[11] = {
+    'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 0 };
+
+/***********************************************************************
+ *		static helper functions
+ */
+static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
+static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
+				   WCHAR const *value);
+static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
+				   char const *value);
+static LONG register_progid(WCHAR const *clsid,
+			    char const *progid, char const *curver_progid,
+			    char const *name, char const *extra);
+static LONG recursive_delete_key(HKEY key);
+static LONG recursive_delete_keyA(HKEY base, char const *name);
+static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
+
+/***********************************************************************
+ *		register_interfaces
+ */
+static HRESULT register_interfaces(struct regsvr_interface const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY interface_key;
+
+    res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
+			  KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->iid; ++list) {
+	WCHAR buf[39];
+	HKEY iid_key;
+
+	StringFromGUID2(list->iid, buf, 39);
+	res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
+			      KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
+	if (res != ERROR_SUCCESS) goto error_close_interface_key;
+
+	if (list->name) {
+	    res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
+				 (CONST BYTE*)(list->name),
+				 strlen(list->name) + 1);
+	    if (res != ERROR_SUCCESS) goto error_close_iid_key;
+	}
+
+	if (list->base_iid) {
+	    register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
+	    if (res != ERROR_SUCCESS) goto error_close_iid_key;
+	}
+
+	if (0 <= list->num_methods) {
+	    static WCHAR const fmt[3] = { '%', 'd', 0 };
+	    HKEY key;
+
+	    res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
+				  KEY_READ | KEY_WRITE, NULL, &key, NULL);
+	    if (res != ERROR_SUCCESS) goto error_close_iid_key;
+
+	    wsprintfW(buf, fmt, list->num_methods);
+	    res = RegSetValueExW(key, NULL, 0, REG_SZ,
+				 (CONST BYTE*)buf,
+				 (lstrlenW(buf) + 1) * sizeof(WCHAR));
+	    RegCloseKey(key);
+
+	    if (res != ERROR_SUCCESS) goto error_close_iid_key;
+	}
+
+	if (list->ps_clsid) {
+	    register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
+	    if (res != ERROR_SUCCESS) goto error_close_iid_key;
+	}
+
+	if (list->ps_clsid32) {
+	    register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
+	    if (res != ERROR_SUCCESS) goto error_close_iid_key;
+	}
+
+    error_close_iid_key:
+	RegCloseKey(iid_key);
+    }
+
+error_close_interface_key:
+    RegCloseKey(interface_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *		unregister_interfaces
+ */
+static HRESULT unregister_interfaces(struct regsvr_interface const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY interface_key;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
+			KEY_READ | KEY_WRITE, &interface_key);
+    if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->iid; ++list) {
+	WCHAR buf[39];
+
+	StringFromGUID2(list->iid, buf, 39);
+	res = recursive_delete_keyW(interface_key, buf);
+    }
+
+    RegCloseKey(interface_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *		register_coclasses
+ */
+static HRESULT register_coclasses(struct regsvr_coclass const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+
+    res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+			  KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+	WCHAR buf[39];
+	HKEY clsid_key;
+
+	StringFromGUID2(list->clsid, buf, 39);
+	res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+			      KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+	if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+	if (list->name) {
+	    res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
+				 (CONST BYTE*)(list->name),
+				 strlen(list->name) + 1);
+	    if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+	}
+
+	if (list->ips) {
+	    res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
+	    if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+	}
+
+	if (list->ips32) {
+	    HKEY ips32_key;
+
+	    res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
+				  KEY_READ | KEY_WRITE, NULL,
+				  &ips32_key, NULL);
+	    if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+	    res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
+				 (CONST BYTE*)list->ips32,
+				 lstrlenA(list->ips32) + 1);
+	    if (res == ERROR_SUCCESS && list->ips32_tmodel)
+		res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
+				     (CONST BYTE*)list->ips32_tmodel,
+				     strlen(list->ips32_tmodel) + 1);
+	    RegCloseKey(ips32_key);
+	    if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+	}
+
+	if (list->progid) {
+	    res = register_key_defvalueA(clsid_key, progid_keyname,
+					 list->progid);
+	    if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+	    res = register_progid(buf, list->progid, NULL,
+				  list->name, list->progid_extra);
+	    if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+	}
+
+	if (list->viprogid) {
+	    res = register_key_defvalueA(clsid_key, viprogid_keyname,
+					 list->viprogid);
+	    if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+	    res = register_progid(buf, list->viprogid, list->progid,
+				  list->name, list->progid_extra);
+	    if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+	}
+
+    error_close_clsid_key:
+	RegCloseKey(clsid_key);
+    }
+
+error_close_coclass_key:
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *		unregister_coclasses
+ */
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+			KEY_READ | KEY_WRITE, &coclass_key);
+    if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+	WCHAR buf[39];
+
+	StringFromGUID2(list->clsid, buf, 39);
+	res = recursive_delete_keyW(coclass_key, buf);
+	if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+	if (list->progid) {
+	    res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
+	    if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+	}
+
+	if (list->viprogid) {
+	    res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
+	    if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+	}
+    }
+
+error_close_coclass_key:
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *		register_mediatypes_parsing
+ */
+static HRESULT register_mediatypes_parsing(struct regsvr_mediatype_parsing const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY mediatype_key;
+    WCHAR buf[39];
+    int i;
+
+    res = RegCreateKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0, NULL, 0,
+			  KEY_READ | KEY_WRITE, NULL, &mediatype_key, NULL);
+    if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+    for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+	HKEY majortype_key = NULL;
+	HKEY subtype_key = NULL;
+
+	StringFromGUID2(list->majortype, buf, 39);
+	res = RegCreateKeyExW(mediatype_key, buf, 0, NULL, 0,
+			      KEY_READ | KEY_WRITE, NULL, &majortype_key, NULL);
+	if (res != ERROR_SUCCESS) goto error_close_keys;
+
+	StringFromGUID2(list->subtype, buf, 39);
+	res = RegCreateKeyExW(majortype_key, buf, 0, NULL, 0,
+			      KEY_READ | KEY_WRITE, NULL, &subtype_key, NULL);
+	if (res != ERROR_SUCCESS) goto error_close_keys;
+
+	StringFromGUID2(&CLSID_AsyncReader, buf, 39);
+	res = RegSetValueExW(subtype_key, sourcefilter_valuename, 0, REG_SZ, (CONST BYTE*)buf,
+			     (lstrlenW(buf) + 1) * sizeof(WCHAR));
+	if (res != ERROR_SUCCESS) goto error_close_keys;
+
+	for(i = 0; list->line[i]; i++) {
+	    char buffer[3];
+	    wsprintfA(buffer, "%d", i);
+	    res = RegSetValueExA(subtype_key, buffer, 0, REG_SZ, (CONST BYTE*)list->line[i],
+				 lstrlenA(list->line[i]));
+	    if (res != ERROR_SUCCESS) goto error_close_keys;
+	}
+
+error_close_keys:
+	if (majortype_key)
+	    RegCloseKey(majortype_key);
+	if (subtype_key)
+	    RegCloseKey(subtype_key);
+    }
+
+    RegCloseKey(mediatype_key);
+
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *		register_mediatypes_extension
+ */
+static HRESULT register_mediatypes_extension(struct regsvr_mediatype_extension const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY mediatype_key;
+    HKEY extensions_root_key = NULL;
+    WCHAR buf[39];
+
+    res = RegCreateKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0, NULL, 0,
+			  KEY_READ | KEY_WRITE, NULL, &mediatype_key, NULL);
+    if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+    res = RegCreateKeyExW(mediatype_key, extensions_keyname, 0, NULL, 0,
+			  KEY_READ | KEY_WRITE, NULL, &extensions_root_key, NULL);
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+	HKEY extension_key;
+
+	res = RegCreateKeyExA(extensions_root_key, list->extension, 0, NULL, 0,
+			      KEY_READ | KEY_WRITE, NULL, &extension_key, NULL);
+	if (res != ERROR_SUCCESS) break;
+
+	StringFromGUID2(list->majortype, buf, 39);
+	res = RegSetValueExW(extension_key, mediatype_name, 0, REG_SZ, (CONST BYTE*)buf,
+			     (lstrlenW(buf) + 1) * sizeof(WCHAR));
+	if (res != ERROR_SUCCESS) goto error_close_key;
+
+	StringFromGUID2(list->subtype, buf, 39);
+	res = RegSetValueExW(extension_key, subtype_valuename, 0, REG_SZ, (CONST BYTE*)buf,
+			     (lstrlenW(buf) + 1) * sizeof(WCHAR));
+	if (res != ERROR_SUCCESS) goto error_close_key;
+
+	StringFromGUID2(&CLSID_AsyncReader, buf, 39);
+	res = RegSetValueExW(extension_key, sourcefilter_valuename, 0, REG_SZ, (CONST BYTE*)buf,
+			     (lstrlenW(buf) + 1) * sizeof(WCHAR));
+	if (res != ERROR_SUCCESS) goto error_close_key;
+
+error_close_key:
+	RegCloseKey(extension_key);
+    }
+
+error_return:
+    RegCloseKey(mediatype_key);
+    if (extensions_root_key)
+	RegCloseKey(extensions_root_key);
+
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *		unregister_mediatypes_parsing
+ */
+static HRESULT unregister_mediatypes_parsing(struct regsvr_mediatype_parsing const *list)
+{
+    LONG res;
+    HKEY mediatype_key;
+    HKEY majortype_key;
+    WCHAR buf[39];
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0,
+			KEY_READ | KEY_WRITE, &mediatype_key);
+    if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+    if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+    for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+	StringFromGUID2(list->majortype, buf, 39);
+	res = RegOpenKeyExW(mediatype_key, buf, 0,
+			KEY_READ | KEY_WRITE, &majortype_key);
+	if (res == ERROR_FILE_NOT_FOUND) {
+	    res = ERROR_SUCCESS;
+	    continue;
+	}
+	if (res != ERROR_SUCCESS) break;
+
+	StringFromGUID2(list->subtype, buf, 39);
+	res = recursive_delete_keyW(majortype_key, buf);
+    	if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+
+	/* Removed majortype key if there is no more subtype key */
+	res = RegDeleteKeyW(majortype_key, 0);
+	if (res == ERROR_ACCESS_DENIED) res = ERROR_SUCCESS;
+
+	RegCloseKey(majortype_key);
+    }
+
+    RegCloseKey(mediatype_key);
+
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *		unregister_mediatypes_extension
+ */
+static HRESULT unregister_mediatypes_extension(struct regsvr_mediatype_extension const *list)
+{
+    LONG res;
+    HKEY mediatype_key;
+    HKEY extensions_root_key = NULL;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0,
+			KEY_READ | KEY_WRITE, &mediatype_key);
+    if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+    if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+    res = RegOpenKeyExW(mediatype_key, extensions_keyname, 0,
+			KEY_READ | KEY_WRITE, &extensions_root_key);
+    if (res == ERROR_FILE_NOT_FOUND)
+	res = ERROR_SUCCESS;
+    else if (res == ERROR_SUCCESS)
+	for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+	    res = recursive_delete_keyA(extensions_root_key, list->extension);
+	    if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+	}
+
+    RegCloseKey(mediatype_key);
+    if (extensions_root_key)
+	RegCloseKey(extensions_root_key);
+
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *		register_filters
+ */
+static HRESULT register_filters(struct regsvr_filter const *list)
+{
+    HRESULT hr;
+    IFilterMapper2* pFM2 = NULL;
+
+    CoInitialize(NULL);
+    hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pFM2);
+
+    if (SUCCEEDED(hr)) {
+	for (; SUCCEEDED(hr) && list->clsid; ++list) {
+	    REGFILTER2 rf2;
+	    REGFILTERPINS2* prfp2;
+	    int i;
+
+	    for (i = 0; list->pins[i].flags != 0xFFFFFFFF; i++) ;
+	    rf2.dwVersion = 2;
+	    rf2.dwMerit = list->merit;
+	    rf2.u.s1.cPins2 = i;
+	    rf2.u.s1.rgPins2 = prfp2 = (REGFILTERPINS2*) CoTaskMemAlloc(i*sizeof(REGFILTERPINS2));
+	    if (!prfp2) {
+		hr = E_OUTOFMEMORY;
+		break;
+	    }
+	    for (i = 0; list->pins[i].flags != 0xFFFFFFFF; i++) {
+		REGPINTYPES* lpMediatype;
+		CLSID* lpClsid;
+		int j, nbmt;
+                
+		for (nbmt = 0; list->pins[i].mediatypes[nbmt].majortype; nbmt++) ;
+		/* Allocate a single buffer for regpintypes struct and clsids */
+		lpMediatype = (REGPINTYPES*) CoTaskMemAlloc(nbmt*(sizeof(REGPINTYPES) + 2*sizeof(CLSID)));
+		if (!lpMediatype) {
+		    hr = E_OUTOFMEMORY;
+		    break;
+		}
+		lpClsid = (CLSID*) (lpMediatype + nbmt);
+		for (j = 0; j < nbmt; j++) {
+		    (lpMediatype + j)->clsMajorType = lpClsid + j*2;
+		    memcpy(lpClsid + j*2, list->pins[i].mediatypes[j].majortype, sizeof(CLSID));
+		    (lpMediatype + j)->clsMinorType = lpClsid + j*2 + 1;
+		    if (list->pins[i].mediatypes[j].subtype)
+			memcpy(lpClsid + j*2 + 1, list->pins[i].mediatypes[j].subtype, sizeof(CLSID));
+		    else {
+			/* Subtype are often a combination of major type + fourcc/tag */
+			memcpy(lpClsid + j*2 + 1, list->pins[i].mediatypes[j].majortype, sizeof(CLSID));
+			*(DWORD*)(lpClsid + j*2 + 1) = list->pins[i].mediatypes[j].fourcc;
+		    }
+		}
+		prfp2[i].dwFlags = list->pins[i].flags;
+		prfp2[i].cInstances = 0;
+		prfp2[i].nMediaTypes = j;
+		prfp2[i].lpMediaType = lpMediatype;
+		prfp2[i].nMediums = 0;
+		prfp2[i].lpMedium = NULL;
+		prfp2[i].clsPinCategory = NULL;
+	    }
+
+	    if (FAILED(hr)) {
+		ERR("failed to register with hresult 0x%lx\n", hr);
+		CoTaskMemFree(prfp2);
+		break;
+	    }
+
+	    hr = IFilterMapper2_RegisterFilter(pFM2, list->clsid, list->name, NULL, list->category, NULL, &rf2);
+
+	    while (i) {
+		CoTaskMemFree((REGPINTYPES*)prfp2[i-1].lpMediaType);
+		i--;
+	    }
+	    CoTaskMemFree(prfp2);
+	}
+    }
+
+    if (pFM2)
+	IFilterMapper2_Release(pFM2);
+
+    CoUninitialize();
+
+    return hr;
+}
+
+/***********************************************************************
+ *		unregister_filters
+ */
+static HRESULT unregister_filters(struct regsvr_filter const *list)
+{
+    HRESULT hr;
+    IFilterMapper2* pFM2;
+
+    CoInitialize(NULL);
+    
+    hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pFM2);
+
+    if (SUCCEEDED(hr)) {
+	for (; SUCCEEDED(hr) && list->clsid; ++list)
+	    hr = IFilterMapper2_UnregisterFilter(pFM2, list->category, NULL, list->clsid);
+	IFilterMapper2_Release(pFM2);
+    }
+
+    CoUninitialize();
+    
+    return hr;
+}
+
+/***********************************************************************
+ *		regsvr_key_guid
+ */
+static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
+{
+    WCHAR buf[39];
+
+    StringFromGUID2(guid, buf, 39);
+    return register_key_defvalueW(base, name, buf);
+}
+
+/***********************************************************************
+ *		regsvr_key_defvalueW
+ */
+static LONG register_key_defvalueW(
+    HKEY base,
+    WCHAR const *name,
+    WCHAR const *value)
+{
+    LONG res;
+    HKEY key;
+
+    res = RegCreateKeyExW(base, name, 0, NULL, 0,
+			  KEY_READ | KEY_WRITE, NULL, &key, NULL);
+    if (res != ERROR_SUCCESS) return res;
+    res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+			 (lstrlenW(value) + 1) * sizeof(WCHAR));
+    RegCloseKey(key);
+    return res;
+}
+
+/***********************************************************************
+ *		regsvr_key_defvalueA
+ */
+static LONG register_key_defvalueA(
+    HKEY base,
+    WCHAR const *name,
+    char const *value)
+{
+    LONG res;
+    HKEY key;
+
+    res = RegCreateKeyExW(base, name, 0, NULL, 0,
+			  KEY_READ | KEY_WRITE, NULL, &key, NULL);
+    if (res != ERROR_SUCCESS) return res;
+    res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+			 lstrlenA(value) + 1);
+    RegCloseKey(key);
+    return res;
+}
+
+/***********************************************************************
+ *		regsvr_progid
+ */
+static LONG register_progid(
+    WCHAR const *clsid,
+    char const *progid,
+    char const *curver_progid,
+    char const *name,
+    char const *extra)
+{
+    LONG res;
+    HKEY progid_key;
+
+    res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
+			  NULL, 0, KEY_READ | KEY_WRITE, NULL,
+			  &progid_key, NULL);
+    if (res != ERROR_SUCCESS) return res;
+
+    if (name) {
+	res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
+			     (CONST BYTE*)name, strlen(name) + 1);
+	if (res != ERROR_SUCCESS) goto error_close_progid_key;
+    }
+
+    if (clsid) {
+	res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
+	if (res != ERROR_SUCCESS) goto error_close_progid_key;
+    }
+
+    if (curver_progid) {
+	res = register_key_defvalueA(progid_key, curver_keyname,
+				     curver_progid);
+	if (res != ERROR_SUCCESS) goto error_close_progid_key;
+    }
+
+    if (extra) {
+	HKEY extra_key;
+
+	res = RegCreateKeyExA(progid_key, extra, 0,
+			      NULL, 0, KEY_READ | KEY_WRITE, NULL,
+			      &extra_key, NULL);
+	if (res == ERROR_SUCCESS)
+	    RegCloseKey(extra_key);
+    }
+
+error_close_progid_key:
+    RegCloseKey(progid_key);
+    return res;
+}
+
+/***********************************************************************
+ *		recursive_delete_key
+ */
+static LONG recursive_delete_key(HKEY key)
+{
+    LONG res;
+    WCHAR subkey_name[MAX_PATH];
+    DWORD cName;
+    HKEY subkey;
+
+    for (;;) {
+	cName = sizeof(subkey_name) / sizeof(WCHAR);
+	res = RegEnumKeyExW(key, 0, subkey_name, &cName,
+			    NULL, NULL, NULL, NULL);
+	if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
+	    res = ERROR_SUCCESS; /* presumably we're done enumerating */
+	    break;
+	}
+	res = RegOpenKeyExW(key, subkey_name, 0,
+			    KEY_READ | KEY_WRITE, &subkey);
+	if (res == ERROR_FILE_NOT_FOUND) continue;
+	if (res != ERROR_SUCCESS) break;
+
+	res = recursive_delete_key(subkey);
+	RegCloseKey(subkey);
+	if (res != ERROR_SUCCESS) break;
+    }
+
+    if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
+    return res;
+}
+
+/***********************************************************************
+ *		recursive_delete_keyA
+ */
+static LONG recursive_delete_keyA(HKEY base, char const *name)
+{
+    LONG res;
+    HKEY key;
+
+    res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
+    if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
+    if (res != ERROR_SUCCESS) return res;
+    res = recursive_delete_key(key);
+    RegCloseKey(key);
+    return res;
+}
+
+/***********************************************************************
+ *		recursive_delete_keyW
+ */
+static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
+{
+    LONG res;
+    HKEY key;
+
+    res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
+    if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
+    if (res != ERROR_SUCCESS) return res;
+    res = recursive_delete_key(key);
+    RegCloseKey(key);
+    return res;
+}
+
+/***********************************************************************
+ *		coclass list
+ */
+static struct regsvr_coclass const coclass_list[] = {
+    {   &CLSID_CaptureGraphBuilder,
+        "Capture Graph Builder",
+        NULL,
+        "qcap.dll",
+        "Both"
+    },
+    {   &CLSID_VfwCapture,
+        "Video for wine capture",
+        NULL,
+        "qcap.dll",
+        "Both"
+    },
+    { NULL }			/* list terminator */
+};
+
+/***********************************************************************
+ *		interface list
+ */
+
+static struct regsvr_interface const interface_list[] = {
+    { NULL }			/* list terminator */
+};
+
+/***********************************************************************
+ *		mediatype list
+ */
+
+static struct regsvr_mediatype_parsing const mediatype_parsing_list[] = {
+    { NULL }			/* list terminator */
+};
+
+/***********************************************************************
+ *		mediatype list
+ */
+
+static struct regsvr_mediatype_extension const mediatype_extension_list[] = {
+    { NULL }			/* list terminator */
+};
+
+/***********************************************************************
+ *		filter list
+ */
+
+static struct regsvr_filter const filter_list[] = {
+    { NULL }		/* list terminator */
+};
+
+/***********************************************************************
+ *		DllRegisterServer (QCAP.@)
+ */
+HRESULT WINAPI QCAP_DllRegisterServer(void)
+{
+    HRESULT hr;
+
+    TRACE("\n");
+
+    hr = register_coclasses(coclass_list);
+    if (SUCCEEDED(hr))
+	hr = register_interfaces(interface_list);
+    if (SUCCEEDED(hr))
+        hr = register_mediatypes_parsing(mediatype_parsing_list);
+    if (SUCCEEDED(hr))
+        hr = register_mediatypes_extension(mediatype_extension_list);
+    if (SUCCEEDED(hr))
+        hr = register_filters(filter_list);
+    return hr;
+}
+
+/***********************************************************************
+ *		DllUnregisterServer (QCAP.@)
+ */
+HRESULT WINAPI QCAP_DllUnregisterServer(void)
+{
+    HRESULT hr;
+
+    TRACE("\n");
+
+    hr = unregister_filters(filter_list);
+    if (SUCCEEDED(hr))
+	hr = unregister_coclasses(coclass_list);
+    if (SUCCEEDED(hr))
+	hr = unregister_interfaces(interface_list);
+    if (SUCCEEDED(hr))
+	hr = unregister_mediatypes_parsing(mediatype_parsing_list);
+    if (SUCCEEDED(hr))
+	hr = unregister_mediatypes_extension(mediatype_extension_list);
+    return hr;
+}
diff -Nru wine-old/dlls/qcap/vfwcapture.c wine-new/dlls/qcap/vfwcapture.c
--- wine-old/dlls/qcap/vfwcapture.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/vfwcapture.c	2005-05-05 14:49:51.000000000 +0200
@@ -0,0 +1,777 @@
+/* Video For Windows Steering structure
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Ugh, Now I can't tell what's worser, COM or the bugs in filtergraph, pins, enummedia and devenum..
+ * This file is only compiled if we found a working videodev.h
+ * If it doesn't exist, null.c will be compiled instead
+ */
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "config.h"
+#include "qcap_private.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+#include "pin.h"
+#include "capture.h"
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "ddraw.h"
+#include "ocidl.h"
+#include "oleauto.h"
+
+static const IBaseFilterVtbl VfwCapture_Vtbl;
+static const IAMStreamConfigVtbl IAMStreamConfig_VTable;
+static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable;
+static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable;
+static const IPinVtbl VfwPin_Vtbl;
+
+static HRESULT VfwPin_Construct(IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
+static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
+
+typedef struct VfwCapture
+{
+   const struct IBaseFilterVtbl * lpVtbl;
+   const struct IAMStreamConfigVtbl * IAMStreamConfig_vtbl;
+   const struct IAMVideoProcAmpVtbl * IAMVideoProcAmp_vtbl;
+   const struct IPersistPropertyBagVtbl * IPersistPropertyBag_vtbl;
+
+   BOOL init;
+   LPVOID myCap;
+   ULONG refCount;
+   FILTER_INFO filterInfo;
+   FILTER_STATE state;
+   CRITICAL_SECTION csFilter;
+
+   IPin * pOutputPin;
+} VfwCapture;
+
+/* VfwPin implementation */
+typedef struct VfwPinImpl
+{
+  OutputPin pin;
+
+  LPVOID myCap;
+  IKsPropertySetVtbl * KSP_VT;
+} VfwPinImpl;
+
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv)
+{
+   VfwCapture *pVfwCapture;
+   HRESULT hr;
+
+   TRACE("%p - %p\n", pUnkOuter, ppv);
+
+   if (pUnkOuter)
+      return CLASS_E_NOAGGREGATION;
+
+   pVfwCapture = CoTaskMemAlloc(sizeof(VfwCapture));
+
+   if (!pVfwCapture)
+      return E_OUTOFMEMORY;
+
+   pVfwCapture->lpVtbl = &VfwCapture_Vtbl;
+   pVfwCapture->IAMStreamConfig_vtbl = &IAMStreamConfig_VTable;
+   pVfwCapture->IAMVideoProcAmp_vtbl = &IAMVideoProcAmp_VTable;
+   pVfwCapture->IPersistPropertyBag_vtbl = &IPersistPropertyBag_VTable;
+   pVfwCapture->refCount = 1;
+   pVfwCapture->filterInfo.achName[0] = '\0';
+   pVfwCapture->filterInfo.pGraph = NULL;
+   pVfwCapture->state = State_Stopped;
+   pVfwCapture->init = FALSE;
+   InitializeCriticalSection(&pVfwCapture->csFilter);
+   hr = VfwPin_Construct((IBaseFilter *)&pVfwCapture->lpVtbl, &pVfwCapture->csFilter, &pVfwCapture->pOutputPin);
+   if (!SUCCEEDED(hr))
+   {
+      CoTaskMemFree(pVfwCapture);
+      return E_OUTOFMEMORY;
+   }
+   *ppv = (LPVOID)pVfwCapture;
+   TRACE("-- created at %p\n", pVfwCapture);
+
+   return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   TRACE("(%s, %p)\n", qcdebugstr_guid(riid), ppv);
+   *ppv = NULL;
+
+   if (IsEqualIID(riid, &IID_IUnknown))
+      *ppv = (LPVOID)This;
+   else if (IsEqualIID(riid, &IID_IPersist))
+      *ppv = (LPVOID)This;
+   else if (IsEqualIID(riid, &IID_IMediaFilter))
+      *ppv = (LPVOID)This;
+   else if (IsEqualIID(riid, &IID_IBaseFilter))
+      *ppv = (LPVOID)This;
+   else if (IsEqualIID(riid, &IID_IAMStreamConfig))
+      *ppv = (LPVOID)&(This->IAMStreamConfig_vtbl);
+   else if (IsEqualIID(riid, &IID_IAMVideoProcAmp))
+      *ppv = (LPVOID)&(This->IAMVideoProcAmp_vtbl);
+   else if (IsEqualIID(riid, &IID_IPersistPropertyBag))
+      *ppv = (LPVOID)&(This->IPersistPropertyBag_vtbl);
+
+   if (!IsEqualIID(riid, &IID_IUnknown) &&
+       !IsEqualIID(riid, &IID_IPersist) &&
+       !IsEqualIID(riid, &IID_IPersistPropertyBag) &&
+       !This->init) {
+      FIXME("Capture system not initialised when looking for %s\n"
+            "\t trying it on primary device now\n", qcdebugstr_guid(riid));
+      if (FAILED(Capture_Initialise(&This->myCap, (IPin *)This->pOutputPin, 0))); {
+         ERR("VfwCapture initialisation failed\n");
+         return E_UNEXPECTED;
+      }
+      This->init = TRUE;
+   }
+
+   if (*ppv)
+   {
+      TRACE("Returning %s interface\n", qcdebugstr_guid(riid));
+      IUnknown_AddRef((IUnknown *)(*ppv));
+      return S_OK;
+   }
+
+   FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI VfwCapture_AddRef(IBaseFilter * iface)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   ULONG refCount = InterlockedIncrement(&This->refCount);
+
+   TRACE("(%p/%p)->() New refcount: %ld\n", This, iface, refCount);
+
+   return refCount;
+}
+
+static ULONG WINAPI VfwCapture_Release(IBaseFilter * iface)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   ULONG refCount = InterlockedDecrement(&This->refCount);
+   TRACE("(%p/%p)->() New refcount: %ld\n", This, iface, refCount);
+
+   if (!refCount)
+   {
+      TRACE("(): Destroying everything!\n");
+      if (This->init) {
+         if (This->state != State_Stopped)
+            Capture_Stop(This->myCap, &This->state);
+         Capture_Destroy(This->myCap, TRUE);
+      }
+      if (((IPinImpl *)This->pOutputPin)->pConnectedTo != NULL)
+      {
+         IPin_Disconnect(((IPinImpl *)This->pOutputPin)->pConnectedTo);
+         IPin_Disconnect(This->pOutputPin);
+      }
+      IPin_Release(This->pOutputPin);
+      DeleteCriticalSection(&This->csFilter);
+      This->lpVtbl = NULL;
+      CoTaskMemFree(This);
+   }
+   return refCount;
+}
+
+/** IPersist methods **/
+
+static HRESULT WINAPI VfwCapture_GetClassID(IBaseFilter * iface, CLSID * pClsid)
+{
+   TRACE("(%p)\n", pClsid);
+   *pClsid = CLSID_VfwCapture;
+   return S_OK;
+}
+
+/** IMediaFilter methods **/
+
+static HRESULT WINAPI VfwCapture_Stop(IBaseFilter * iface)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   TRACE("()\n");
+   return Capture_Stop(This->myCap, &This->state);
+}
+
+static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   TRACE("()\n");
+   return Capture_Pause(This->myCap, &This->state);
+}
+
+static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   TRACE("(%lx%08lx)\n", (ULONG)(tStart >> 32), (ULONG)tStart);
+   return Capture_Run(This->myCap, &This->state);
+}
+
+static HRESULT WINAPI VfwCapture_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   TRACE("(%lu, %p)\n", dwMilliSecsTimeout, pState);
+   *pState = This->state;
+   return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
+{
+   TRACE("(%p)\n", pClock);
+   return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
+{
+   TRACE("(%p)\n", ppClock);
+   return S_OK;
+}
+
+/** IBaseFilter methods **/
+
+static HRESULT WINAPI VfwCapture_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
+{
+   ENUMPINDETAILS epd;
+   VfwCapture *This = (VfwCapture *)iface;
+
+   TRACE("(%p)\n", ppEnum);
+
+   epd.cPins = 1;
+   epd.ppPins = &This->pOutputPin;
+   return IEnumPinsImpl_Construct(&epd, ppEnum);
+}
+
+static HRESULT WINAPI VfwCapture_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
+{
+   FIXME("(%s, %p) - stub\n", debugstr_w(Id), ppPin);
+   return E_NOTIMPL;
+}
+
+static HRESULT WINAPI VfwCapture_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+
+   TRACE("(%p)\n", pInfo);
+
+   strcpyW(pInfo->achName, This->filterInfo.achName);
+   pInfo->pGraph = This->filterInfo.pGraph;
+
+   if (pInfo->pGraph)
+        IFilterGraph_AddRef(pInfo->pGraph);
+   return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+
+   TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
+
+   if (pName)
+       strcpyW(This->filterInfo.achName, pName);
+   else
+       *This->filterInfo.achName = 0;
+   This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
+
+   return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
+{
+   FIXME("(%p) - stub\n", pVendorInfo);
+   return E_NOTIMPL;
+}
+
+static const IBaseFilterVtbl VfwCapture_Vtbl =
+{   
+   VfwCapture_QueryInterface,
+   VfwCapture_AddRef,
+   VfwCapture_Release,
+   VfwCapture_GetClassID,
+   VfwCapture_Stop,
+   VfwCapture_Pause,
+   VfwCapture_Run,
+   VfwCapture_GetState,
+   VfwCapture_SetSyncSource,
+   VfwCapture_GetSyncSource,
+   VfwCapture_EnumPins,
+   VfwCapture_FindPin,
+   VfwCapture_QueryFilterInfo,
+   VfwCapture_JoinFilterGraph,
+   VfwCapture_QueryVendorInfo
+};
+
+/* AMStreamConfig interface, we only need to implement {G,S}etFormat */
+static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig * iface, REFIID riid, LPVOID * ppv)
+{
+   ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface);
+   TRACE("%p --> %s\n", This, qcdebugstr_guid(riid));
+   if (IsEqualIID(riid, &IID_IUnknown) ||
+       IsEqualIID(riid, &IID_IAMStreamConfig))
+   {
+       *ppv = (LPVOID)iface;
+       return S_OK;
+   }
+
+   FIXME("No interface for iid %s\n", qcdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI AMStreamConfig_AddRef(IAMStreamConfig * iface)
+{
+   ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface);
+   TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
+   return IUnknown_AddRef((IUnknown *)This);
+}
+
+static ULONG WINAPI AMStreamConfig_Release(IAMStreamConfig * iface)
+{
+   ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface);
+   TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
+   return IUnknown_Release((IUnknown *)This);
+}
+
+static HRESULT WINAPI AMStreamConfig_SetFormat(IAMStreamConfig *iface,
+                                              AM_MEDIA_TYPE *pmt) {
+   HRESULT hr;
+   ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface);
+
+   TRACE("(%p): %p->%p\n", iface, pmt, pmt->pbFormat);
+
+   if (This->state != State_Stopped)
+   {
+      TRACE("Returning not stopped error\n");
+      return VFW_E_NOT_STOPPED;
+   }
+
+   dump_AM_MEDIA_TYPE(pmt);
+
+   if (((IPinImpl *)This->pOutputPin)->pConnectedTo != NULL) {
+      hr = IPin_QueryAccept(((IPinImpl *)This->pOutputPin)->pConnectedTo, pmt);
+      TRACE("Would accept: %ld\n", hr);
+      if (hr == S_FALSE)
+         return VFW_E_INVALIDMEDIATYPE;
+   }
+
+   hr = Capture_SetMediaType(This->myCap, pmt);
+   if (SUCCEEDED(hr) && hr == S_OK && This->filterInfo.pGraph != NULL &&
+                      ((IPinImpl *)This->pOutputPin)->pConnectedTo != NULL) {
+      hr = IFilterGraph_Reconnect(This->filterInfo.pGraph, This->pOutputPin);
+      if (SUCCEEDED(hr))
+         TRACE("Reconnection completed, with new media format..\n");
+   }
+   TRACE("Returning: %ld\n", hr);
+   return hr;
+}
+
+static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface,
+                                              AM_MEDIA_TYPE **pmt) {
+   ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface);
+
+   TRACE("%p -> (%p)\n", iface, pmt);
+   return Capture_GetMediaType(This->myCap, pmt);
+}
+
+static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface, int *piCount, int *piSize)
+{
+   FIXME("%p: %p %p - stub, intentional\n", iface, piCount, piSize);
+   return E_NOTIMPL; /* Not implemented for this interface */
+}
+
+static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
+int iIndex, AM_MEDIA_TYPE **pmt, BYTE *pSCC)
+{
+   FIXME("%p: %d %p %p - stub, intentional\n", iface, iIndex, pmt, pSCC);
+   return E_NOTIMPL; /* Not implemented for this interface */
+}
+
+static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
+{
+   AMStreamConfig_QueryInterface,
+   AMStreamConfig_AddRef,
+   AMStreamConfig_Release,
+   AMStreamConfig_SetFormat,
+   AMStreamConfig_GetFormat,
+   AMStreamConfig_GetNumberOfCapabilities,
+   AMStreamConfig_GetStreamCaps
+};
+
+static HRESULT WINAPI AMVideoProcAmp_QueryInterface(IAMVideoProcAmp * iface, REFIID riid, LPVOID * ppv)
+{
+   if (IsEqualIID(riid, &IID_IUnknown) ||
+       IsEqualIID(riid, &IID_IAMVideoProcAmp))
+   {
+       *ppv = (LPVOID)iface;
+       return S_OK;
+   }
+
+   FIXME("No interface for iid %s\n", qcdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface)
+{
+   ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface);
+   TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
+   return IUnknown_AddRef((IUnknown *)This);
+}
+
+static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface)
+{
+   ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface);
+   TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
+   return IUnknown_Release((IUnknown *)This);
+}
+
+static HRESULT WINAPI AMVideoProcAmp_GetRange(IAMVideoProcAmp * iface, long Property, long *pMin, long *pMax, long *pSteppingDelta, long *pDefault, long *pCapsFlags)
+{
+   ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface);
+   return Capture_GetPropRange(This->myCap, Property, pMin, pMax, pSteppingDelta, pDefault, pCapsFlags);
+}
+
+static HRESULT WINAPI AMVideoProcAmp_Set(IAMVideoProcAmp * iface, long Property, long lValue, long Flags)
+{
+   ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface);
+   return Capture_SetProp(This->myCap, Property, lValue, Flags);
+}
+
+static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp * iface, long Property, long *lValue, long *Flags)
+{
+   ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface);
+   return Capture_GetProp(This->myCap, Property, lValue, Flags);
+}
+
+static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable =
+{
+   AMVideoProcAmp_QueryInterface,
+   AMVideoProcAmp_AddRef,
+   AMVideoProcAmp_Release,
+   AMVideoProcAmp_GetRange,
+   AMVideoProcAmp_Set,
+   AMVideoProcAmp_Get,
+};
+
+static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag * iface, REFIID riid, LPVOID * ppv)
+{
+   ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface);
+   if (IsEqualIID(riid, &IID_IUnknown) ||
+       IsEqualIID(riid, &IID_IPersist) ||
+       IsEqualIID(riid, &IID_IPersistPropertyBag))
+   {
+      *ppv = (LPVOID)iface;
+      return S_OK;
+   }
+   if (IsEqualIID(riid, &IID_IBaseFilter)) {
+      FIXME("Native devenum asks for IBaseFilter, should I do this?\n");
+      *ppv = (LPVOID)This;
+      IUnknown_AddRef((IUnknown *)This);
+      return S_OK;
+   }
+
+   FIXME("No interface for iid %s\n", qcdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface)
+{
+   ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface);
+   TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
+   return IUnknown_AddRef((IUnknown *)This);
+}
+
+static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface)
+{
+   ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface);
+   TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
+   return IUnknown_Release((IUnknown *)This);
+}
+
+static HRESULT WINAPI PPB_GetClassID(IPersistPropertyBag * iface, CLSID * pClassID)
+{
+   ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface);
+   FIXME("%p - stub\n", This);
+   return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface)
+{
+   ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface);
+   FIXME("%p - stub\n", This);
+   return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PPB_Load(IPersistPropertyBag * iface, IPropertyBag *pPropBag, IErrorLog *pErrorLog)
+{
+   ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface);
+   HRESULT hr;
+   VARIANT var;
+   const OLECHAR VFWIndex[] = {'V','F','W','I','n','d','e','x',0};
+   V_VT(&var) = VT_I4;
+
+   TRACE("%p/%p-> (%p, %p)\n", iface, This, pPropBag, pErrorLog);
+
+   hr = IPropertyBag_Read(pPropBag, (LPCOLESTR)VFWIndex, &var, pErrorLog);
+
+   if (SUCCEEDED(hr)) {
+      hr = Capture_Initialise(&This->myCap, This->pOutputPin, (USHORT)var.__VARIANT_NAME_1.__VARIANT_NAME_2.__VARIANT_NAME_3.ulVal);
+      ((VfwPinImpl *)This->pOutputPin)->myCap = This->myCap;
+      if (SUCCEEDED(hr))
+        This->init = TRUE;
+   }
+
+   return hr;
+}
+
+static HRESULT WINAPI PPB_Save(IPersistPropertyBag * iface, IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
+{
+   ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface);
+   FIXME("%p - stub\n", This);
+   return E_NOTIMPL;
+}
+
+static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable =
+{
+   PPB_QueryInterface,
+   PPB_AddRef,
+   PPB_Release,
+   PPB_GetClassID,
+   PPB_InitNew,
+   PPB_Load,
+   PPB_Save
+};
+
+/* IKsPropertySet interface */
+static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet * iface, REFIID riid, LPVOID * ppv)
+{
+   if (IsEqualIID(riid, &IID_IUnknown) ||
+       IsEqualIID(riid, &IID_IKsPropertySet))
+   {
+       *ppv = (LPVOID)iface;
+       return S_OK;
+   }
+
+   FIXME("No interface for iid %s\n", qcdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
+{
+   ICOM_THIS_MULTI(VfwPinImpl, KSP_VT, iface);
+   TRACE("%p --> Forwarding to VfwPin (%p)\n", iface, This);
+   return IUnknown_AddRef((IUnknown *)This);
+}
+
+static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
+{
+   ICOM_THIS_MULTI(VfwPinImpl, KSP_VT, iface);
+   TRACE("%p --> Forwarding to VfwPin (%p)\n", iface, This);
+   return IUnknown_Release((IUnknown *)This);
+}
+
+static HRESULT WINAPI KSP_Set(IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData)
+{
+   FIXME("%p: stub\n", iface);
+   return E_NOTIMPL;
+}
+
+static HRESULT WINAPI KSP_Get(IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD *pcbReturned)
+{
+   TRACE("()\n");
+   if (!IsEqualIID(guidPropSet, &AMPROPSETID_Pin))
+      return E_PROP_SET_UNSUPPORTED;
+   if (pPropData == NULL && pcbReturned == NULL)
+      return E_POINTER;
+   if (pcbReturned)
+      *pcbReturned = sizeof(GUID);
+   if (pPropData == NULL)
+      return S_OK;
+   if (cbPropData < sizeof(GUID))
+      return E_UNEXPECTED;
+   *(GUID *)pPropData = PIN_CATEGORY_PREVIEW;
+   FIXME("() Not adding a pin with PIN_CATEGORY_CAPTURE for a reason..\n");
+   return S_OK;
+}
+
+static HRESULT WINAPI KSP_QuerySupported(IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport)
+{
+   FIXME("%p: stub\n", iface);
+   return E_NOTIMPL;
+}
+
+static IKsPropertySetVtbl KSP_VTable =
+{
+   KSP_QueryInterface,
+   KSP_AddRef,
+   KSP_Release,
+   KSP_Set,
+   KSP_Get,
+   KSP_QuerySupported
+};
+
+static HRESULT VfwPin_Construct(IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
+{
+   ALLOCATOR_PROPERTIES ap;
+   VfwPinImpl * pPinImpl;
+   PIN_INFO piOutput;
+
+   pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
+   if (!pPinImpl)
+      return E_OUTOFMEMORY;
+
+/*What we put here for props is overridden by the Capture_Run when committing*/
+   ap.cBuffers = 3;
+   ap.cbBuffer = 230400;
+   ap.cbAlign = 1;
+   ap.cbPrefix = 0;
+
+   piOutput.dir = PINDIR_OUTPUT;
+   piOutput.pFilter = pBaseFilter;
+   strcpyW(piOutput.achName, wszOutputPinName);
+
+   if (SUCCEEDED(OutputPin_Init(&piOutput, &ap, pBaseFilter, NULL, pCritSec, &pPinImpl->pin)))
+   {
+      pPinImpl->KSP_VT = &KSP_VTable;
+      pPinImpl->pin.pin.lpVtbl = &VfwPin_Vtbl;
+      *ppPin = (IPin *)(&pPinImpl->pin.pin.lpVtbl);
+      return S_OK;
+   }
+   return E_FAIL;
+}
+
+static HRESULT WINAPI VfwPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
+{
+   VfwPinImpl *This = (VfwPinImpl *)iface;
+   TRACE("%s %p\n", qcdebugstr_guid(riid), ppv);
+   *ppv = NULL;
+   if (IsEqualIID(riid, &IID_IUnknown))
+      *ppv = (LPVOID)This;
+   else if (IsEqualIID(riid, &IID_IPin))
+      *ppv = (LPVOID)This;
+   else if (IsEqualIID(riid, &IID_IKsPropertySet))
+      *ppv = (LPVOID)&(This->KSP_VT);
+
+   if (*ppv)
+   {
+      IUnknown_AddRef((IUnknown *)(*ppv));
+      return S_OK;
+   }
+
+   FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI VfwPin_AddRef(IPin * iface)
+{
+    VfwPinImpl *This = (VfwPinImpl *)iface;
+    ULONG refCount = InterlockedIncrement(&This->pin.pin.refCount);
+
+    TRACE("() -> new refcount: %lu\n", refCount);
+
+    return refCount;
+}
+
+static ULONG WINAPI VfwPin_Release(IPin * iface)
+{
+   VfwPinImpl *This = (VfwPinImpl *)iface;
+   ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
+   TRACE("() -> new refcount: %lu\n", refCount);
+
+   if (!refCount)
+   {
+      CoTaskMemFree(This);
+      return 0;
+   }
+   return refCount;
+}
+
+static HRESULT WINAPI VfwPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
+{
+   ENUMMEDIADETAILS emd;
+   AM_MEDIA_TYPE *pmt;
+   HRESULT hr;
+
+   VfwPinImpl *This = (VfwPinImpl *)iface;
+   emd.cMediaTypes = 1;
+   hr = Capture_GetMediaType(This->myCap, &pmt);
+   emd.pMediaTypes = pmt;
+   if (SUCCEEDED(hr)) hr = IEnumMediaTypesImpl_Construct(&emd, ppEnum);
+   TRACE("%p -- %lx\n", This, hr);
+   DeleteMediaType(pmt);
+   return hr;
+}
+
+static HRESULT WINAPI VfwPin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
+{
+    TRACE("(%p)->(%p, %p)\n", iface, apPin, cPin);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI VfwPin_EndOfStream(IPin * iface)
+{
+    TRACE("()\n");
+    return E_UNEXPECTED;
+}
+
+static HRESULT WINAPI VfwPin_BeginFlush(IPin * iface)
+{
+    TRACE("(%p)->()\n", iface);
+    return E_UNEXPECTED;
+}
+
+static HRESULT WINAPI VfwPin_EndFlush(IPin * iface)
+{
+    TRACE("(%p)->()\n", iface);
+    return E_UNEXPECTED;
+}
+
+static HRESULT WINAPI VfwPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
+{
+    TRACE("(%p)->(%lx%08lx, %lx%08lx, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
+    return E_UNEXPECTED;
+}
+
+static const IPinVtbl VfwPin_Vtbl =
+{
+   VfwPin_QueryInterface,
+   VfwPin_AddRef,
+   VfwPin_Release,
+   OutputPin_Connect,
+   OutputPin_ReceiveConnection,
+   OutputPin_Disconnect,
+   IPinImpl_ConnectedTo,
+   IPinImpl_ConnectionMediaType,
+   IPinImpl_QueryPinInfo,
+   IPinImpl_QueryDirection,
+   IPinImpl_QueryId,
+   IPinImpl_QueryAccept,
+   VfwPin_EnumMediaTypes,
+   VfwPin_QueryInternalConnections,
+   VfwPin_EndOfStream, 
+   VfwPin_BeginFlush,
+   VfwPin_EndFlush,
+   VfwPin_NewSegment
+};  
+


More information about the wine-patches mailing list