Wine msn webcam patch (Attempt 2)

Maarten Lankhorst m.b.lankhorst at gmail.com
Sat Apr 9 09:31:18 CDT 2005


I've been trying to get msn webcam to work again, and I found out that 
WINEDEBUG=+quartz gives a crash when msn creates a pin, and then does 
some stuff with it, I can only presume some TRACE or WARNING causes the 
error, but the effect is I can't use those commands, this patch 
currently allows MSN preview screen to become gray, but it's not 
actually sending any information (not even fake images) to msn's webcam 
pin, if someone can find where exactly it crashes, it would help a lot, 
and make it a lot easier for me to actually implement a working webcam 
(Right now it will probably only work for msn messenger, but I can 
imagine other programs will work with this too in a future version)
This file makes changes to qcap, but they are not needed for the process 
as far as I know

DLL Overrides:
"devenum" = "builtin"
"quartz" = "builtin"

just make sure to do regsvr32 devenum and regsvr32 quartz AFTER you 
applied the patches..
-------------- next part --------------
diff -Nru wine-old/dlls/devenum/createdevenum.c wine-new/dlls/devenum/createdevenum.c
--- wine-old/dlls/devenum/createdevenum.c	2005-01-25 11:56:39.000000000 +0100
+++ wine-new/dlls/devenum/createdevenum.c	2005-04-09 16:10:47.000000000 +0200
@@ -117,6 +117,7 @@
 
     if (IsEqualGUID(clsidDeviceClass, &CLSID_AudioRendererCategory) ||
         IsEqualGUID(clsidDeviceClass, &CLSID_AudioInputDeviceCategory) ||
+        IsEqualGUID(clsidDeviceClass, &CLSID_VideoInputDeviceCategory) ||
         IsEqualGUID(clsidDeviceClass, &CLSID_MidiRendererCategory))
     {
         hbasekey = HKEY_CURRENT_USER;
@@ -142,6 +143,7 @@
     {
         if (IsEqualGUID(clsidDeviceClass, &CLSID_AudioRendererCategory) ||
             IsEqualGUID(clsidDeviceClass, &CLSID_AudioInputDeviceCategory) ||
+            IsEqualGUID(clsidDeviceClass, &CLSID_VideoInputDeviceCategory) ||
             IsEqualGUID(clsidDeviceClass, &CLSID_MidiRendererCategory))
         {
              HRESULT hr = DEVENUM_CreateSpecialCategories();
@@ -413,6 +415,7 @@
                 CoTaskMemFree(pTypes);
 	    }
 	}
+        res = DEVENUM_CreateAMCategoryKey(&CLSID_VideoInputDeviceCategory);
     }
 
     if (pMapper)
diff -Nru wine-old/dlls/devenum/devenum_main.c wine-new/dlls/devenum/devenum_main.c
--- wine-old/dlls/devenum/devenum_main.c	2004-12-07 15:37:11.000000000 +0100
+++ wine-new/dlls/devenum/devenum_main.c	2005-04-09 16:10:47.000000000 +0200
@@ -122,7 +122,7 @@
 	{&CLSID_AudioCompressorCategory, acmcat, TRUE},
 	{&CLSID_VideoCompressorCategory, vidcat, TRUE},
 	{&CLSID_LegacyAmFilterCategory, filtcat, TRUE},
-	{&CLSID_VideoInputDeviceCategory, vfwcat, FALSE},
+	{&CLSID_VideoInputDeviceCategory, vfwcat, TRUE},
 	{&CLSID_AudioInputDeviceCategory, wavein, FALSE},
 	{&CLSID_AudioRendererCategory, waveout, FALSE},
 	{&CLSID_MidiRendererCategory, midiout, FALSE},
@@ -156,7 +156,7 @@
 
         pMapper = (IFilterMapper2*)mapvptr;
 
-        IFilterMapper2_CreateCategory(pMapper, &CLSID_VideoInputDeviceCategory, MERIT_DO_NOT_USE, friendlyvidcap);
+        IFilterMapper2_CreateCategory(pMapper, &CLSID_VideoInputDeviceCategory, MERIT_NORMAL, friendlyvidcap);
         IFilterMapper2_CreateCategory(pMapper, &CLSID_LegacyAmFilterCategory, MERIT_NORMAL, friendlydshow);
         IFilterMapper2_CreateCategory(pMapper, &CLSID_VideoCompressorCategory, MERIT_DO_NOT_USE, friendlyvidcomp);
         IFilterMapper2_CreateCategory(pMapper, &CLSID_AudioInputDeviceCategory, MERIT_DO_NOT_USE, friendlyaudcap);
diff -Nru wine-old/dlls/qcap/main.c wine-new/dlls/qcap/main.c
--- wine-old/dlls/qcap/main.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/main.c	2005-04-09 16:11:33.000000000 +0200
@@ -0,0 +1,244 @@
+/* DirectShow Capture Functions (QCap.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ * Based on quartz' dll
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and capture 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
+ */
+
+#include "config.h"
+#include "wine/debug.h"
+
+#include "qcap_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+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[] =
+{
+};
+
+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;
+}
+
+/***********************************************************************
+ *              DllCanUnloadNow (QCAP.@)
+ */
+HRESULT WINAPI QCAP_DllCanUnloadNow()
+{
+    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 }
+};
+
+/***********************************************************************
+ *              qcdebugstr_guid (internal)
+ *
+ * Gives a text version of Capture GUIDs if possible
+ */
+const char * qcdebugstr_guid( const GUID * id )
+{
+    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);
+}
+
+/***********************************************************************
+ *              qcdebugstr_State (internal)
+ *
+ * Gives a text version of the FILTER_STATE enumeration
+ */
+const char * qcdebugstr_State(FILTER_STATE state)
+{
+    switch (state)
+    {
+    case State_Stopped:
+        return "State_Stopped";
+    case State_Running:
+        return "State_Running";
+    case State_Paused:
+        return "State_Paused";
+    default:
+        return "State_Unknown";
+    }
+}
+
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-04-09 16:11:33.000000000 +0200
@@ -3,8 +3,11 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = qcap.dll
+IMPORTS   = msvfw32 ole32 oleaut32 user32 advapi32 kernel32
+EXTRALIBS = -lstrmiids -luuid $(LIBUNICODE)
+EXTRAINCL =
 
-C_SRCS = qcap_main.c
+C_SRCS = main.c regsvr.c capturegraph.c
 
 RC_SRCS = version.rc
 
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	1970-01-01 01:00:00.000000000 +0100
@@ -1,43 +0,0 @@
-/*
- * Qcap implementation
- *
- * Copyright (C) 2003 Dominik Strasser
- *
- * 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 "wine/debug.h"
-#include "winerror.h"
-
-
-WINE_DEFAULT_DEBUG_CHANNEL(qcap);
-
-/***********************************************************************
- *      DllRegisterServer (QCAP.@)
- */
-HRESULT WINAPI QCAP_DllRegisterServer()
-{
-	FIXME("(): stub\n");
-	return 0;
-}
-
-/***********************************************************************
- *		DllGetClassObject (QCAP.@)
- */
-HRESULT WINAPI QCAP_DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
-{
-    FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
-    return CLASS_E_CLASSNOTAVAILABLE;
-}
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-09 16:11:33.000000000 +0200
@@ -0,0 +1,41 @@
+/* DirectShow private interfaces (QCap.DLL)
+ * All classes & functions are related to capture
+ *
+ * Copyright 2005
+ *
+ * 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"
+
+const char * qcdebugstr_guid( const GUID * id );
+
+#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-09 16:11:33.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-04-09 16:11:34.000000000 +0200
@@ -0,0 +1,922 @@
+/*
+ * self-registerable dll functions for qcap.dll
+ *
+ * Copyright (C) 2003 John K. Hohm
+ * Modified by Maarten Lankhorst to work with V4W (Video for wine)
+ *
+ * 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[] = {
+    { 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/quartz/capturegraph.c wine-new/dlls/quartz/capturegraph.c
--- wine-old/dlls/quartz/capturegraph.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/quartz/capturegraph.c	2005-04-09 16:11:36.000000000 +0200
@@ -0,0 +1,202 @@
+/* Copyright 2005 Maarten Lankhorst, Goal is to get MSN's webcam function to work..
+ *
+ * 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 "config.h"
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "quartz_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(quartz);
+
+static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
+
+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, qzdebugstr_guid(riid), ppv);
+   *ppv = NULL;
+   if (IsEqualIID(riid, &IID_IUnknown))
+      *ppv = (LPVOID)This;
+   else if (IsEqualIID(riid, &IID_ICaptureGraphBuilder))
+   {
+      *ppv = (LPVOID)This;
+      TRACE("Asking for myself?\n");
+   }
+
+   if (*ppv)
+   {
+       IUnknown_AddRef((IUnknown *)(*ppv));
+       return S_OK;
+   }
+
+   FIXME("No interface for %s!\n", qzdebugstr_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) {
+      FIXME("Release IGraphFilter or w/e\n");
+      DeleteCriticalSection(&This->csFilter);
+      This->lpVtbl = NULL;
+      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_FAIL;
+   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\n", iface);
+   if (This->mygraph == NULL) return E_FAIL;
+
+   *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_FAIL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_FindInterface(ICaptureGraphBuilder * iface, const GUID *pCategory, IBaseFilter *pf, REFIID riid, void **ppint)
+{
+   struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+   TRACE("%p: %s .. %p .. %s .. %p - unwanted untested unguaranteed unwarranted unreliable stub workaround!\n", iface, qzdebugstr_guid(pCategory), pf, qzdebugstr_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. */
+}
+
+/* [call_as(FindInterface)] HRESULT RemoteFindInterface(
+        [in, unique] const GUID *pCategory,
+        [in] IBaseFilter *pf,
+        [in] REFIID riid,
+        [out] IUnknown **ppint);
+   ^- What is this? */
+
+static HRESULT WINAPI CaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface, const GUID *pCategory, IUnknown *pSource, IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
+{
+   FIXME("%p: .. Stub? !!! -- SHOULD NORMALLY WORK!!..\n", iface);
+   return E_FAIL;
+}
+
+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_FAIL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder * iface, LPCOLESTR lpstr, DWORDLONG dwlSize)
+{
+   FIXME("%p: .. Stub? !!! ..\n", iface);
+   return E_FAIL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder * iface, LPOLESTR lpwstrOld, LPOLESTR lpwstrNew, int fAllowEscAbort, IAMCopyCaptureFileProgress *pCallback)
+{
+   FIXME("%p: .. Stub? !!! ..\n", iface);
+   return E_FAIL;
+}
+
+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/quartz/filesource.c wine-new/dlls/quartz/filesource.c
--- wine-old/dlls/quartz/filesource.c	2005-01-06 20:36:47.000000000 +0100
+++ wine-new/dlls/quartz/filesource.c	2005-04-09 16:11:35.000000000 +0200
@@ -663,17 +663,6 @@
     FileSource_GetCurFile
 };
 
-
-/* the dwUserData passed back to user */
-typedef struct DATAREQUEST
-{
-    IMediaSample * pSample; /* sample passed to us by user */
-    DWORD_PTR dwUserData; /* user data passed to us */
-    OVERLAPPED ovl; /* our overlapped structure */
-
-    struct DATAREQUEST * pNext; /* next data request in list */
-} DATAREQUEST;
-
 void queue(DATAREQUEST * pHead, DATAREQUEST * pItem)
 {
     DATAREQUEST * pCurrent;
diff -Nru wine-old/dlls/quartz/filtergraph.c wine-new/dlls/quartz/filtergraph.c
--- wine-old/dlls/quartz/filtergraph.c	2005-03-02 11:12:12.000000000 +0100
+++ wine-new/dlls/quartz/filtergraph.c	2005-04-09 16:11:35.000000000 +0200
@@ -40,7 +40,6 @@
 #include "evcode.h"
 #include "wine/unicode.h"
 
-
 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
 
 typedef struct {
diff -Nru wine-old/dlls/quartz/main.c wine-new/dlls/quartz/main.c
--- wine-old/dlls/quartz/main.c	2005-03-02 13:23:22.000000000 +0100
+++ wine-new/dlls/quartz/main.c	2005-04-09 16:11:35.000000000 +0200
@@ -71,7 +71,9 @@
     { &CLSID_AVIDec, AVIDec_create },
     { &CLSID_SystemClock, &QUARTZ_CreateSystemClock },
     { &CLSID_ACMWrapper, &ACMWrapper_create },
-    { &CLSID_WAVEParser, &WAVEParser_create }
+    { &CLSID_VfwCapture, &VfwCapture_create },
+    { &CLSID_WAVEParser, &WAVEParser_create },
+    { &CLSID_CaptureGraphBuilder, &CaptureGraphBuilder_create }
 };
 
 static HRESULT WINAPI
diff -Nru wine-old/dlls/quartz/Makefile.in wine-new/dlls/quartz/Makefile.in
--- wine-old/dlls/quartz/Makefile.in	2005-02-10 18:13:18.000000000 +0100
+++ wine-new/dlls/quartz/Makefile.in	2005-04-09 16:11:35.000000000 +0200
@@ -28,6 +28,8 @@
 	systemclock.c \
 	transform.c \
 	videorenderer.c \
+	v4wsource.c \
+	capturegraph.c \
 	waveparser.c
 
 RC_SRCS = version.rc
diff -Nru wine-old/dlls/quartz/quartz_private.h wine-new/dlls/quartz/quartz_private.h
--- wine-old/dlls/quartz/quartz_private.h	2005-02-10 18:13:18.000000000 +0100
+++ wine-new/dlls/quartz/quartz_private.h	2005-04-09 16:11:35.000000000 +0200
@@ -52,6 +52,8 @@
 HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv);
 HRESULT ACMWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv);
 HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv);
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv);
+HRESULT CaptureGraphBuilder_create(IUnknown * pUnkOuter, LPVOID * ppv);
 
 HRESULT EnumMonikerImpl_Create(IMoniker ** ppMoniker, ULONG nMonikerCount, IEnumMoniker ** ppEnum);
 
@@ -80,4 +82,14 @@
 BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards);
 void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt);
 
+typedef struct DATAREQUEST
+{
+    IMediaSample * pSample; /* sample passed to us by user */
+    DWORD_PTR dwUserData; /* user data passed to us */
+    OVERLAPPED ovl; /* our overlapped structure */
+
+    struct DATAREQUEST * pNext; /* next data request in list */
+} DATAREQUEST;
+
+void queue(DATAREQUEST * pHead, DATAREQUEST * pItem);
 #endif /* __QUARTZ_PRIVATE_INCLUDED__ */
diff -Nru wine-old/dlls/quartz/regsvr.c wine-new/dlls/quartz/regsvr.c
--- wine-old/dlls/quartz/regsvr.c	2005-02-10 18:13:18.000000000 +0100
+++ wine-new/dlls/quartz/regsvr.c	2005-04-09 16:11:35.000000000 +0200
@@ -922,6 +922,18 @@
 	"quartz.dll",
 	"Both"
     },
+    {   &CLSID_VfwCapture,
+        "Video for wine capture interface",
+        NULL,
+        "quartz.dll",
+        "Both"
+    },
+    {   &CLSID_CaptureGraphBuilder,
+        "Capture Graph Builder",
+        NULL,
+        "quartz.dll",
+        "Both"
+    },
     { NULL }			/* list terminator */
 };
 
@@ -1112,6 +1124,18 @@
 	    { 0xFFFFFFFF },
 	}
     },
+    {   &CLSID_VfwCapture,
+        &CLSID_VideoInputDeviceCategory,
+        {'V','i','d','e','o',' ','F','o','r',' ','W','i','n','e',' ','(','V','4','W',')', 0},
+        0x800000,
+        {   {   REG_PINFLAG_B_OUTPUT,
+                {   { &MEDIATYPE_Stream, &GUID_NULL },
+                    { NULL }
+                },
+            },
+            { 0xFFFFFFFF },
+        }
+    }, /* This creates a fake device for us with an ugly name */
     { NULL }		/* list terminator */
 };
 
diff -Nru wine-old/dlls/quartz/v4wsource.c wine-new/dlls/quartz/v4wsource.c
--- wine-old/dlls/quartz/v4wsource.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/quartz/v4wsource.c	2005-04-09 16:11:36.000000000 +0200
@@ -0,0 +1,703 @@
+/* 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
+ *
+ * LETS SING IT ALL TOGETHER NOW! ON MY MARK!
+ * COM SUCKS ASS!
+ */
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "quartz_private.h"
+#include "control_private.h"
+#include "pin.h"
+
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "fourcc.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "ddraw.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+
+static const IBaseFilterVtbl VfwCapture_Vtbl;
+static const IAMStreamConfigVtbl IAMStreamConfig_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;
+
+   ULONG refCount;
+   FILTER_INFO filterInfo;
+   FILTER_STATE state;
+   CRITICAL_SECTION csFilter;
+
+   IPin * pOutputPin;
+   AM_MEDIA_TYPE * pmt;
+} VfwCapture;
+
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv)
+{
+   VfwCapture *pVfwCapture;
+   HRESULT hr;
+
+   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->refCount = 1;
+   pVfwCapture->filterInfo.achName[0] = '\0';
+   pVfwCapture->filterInfo.pGraph = NULL;
+   InitializeCriticalSection(&pVfwCapture->csFilter);
+   hr = VfwPin_Construct((IBaseFilter *)&pVfwCapture->lpVtbl, &pVfwCapture->csFilter, &pVfwCapture->pOutputPin);
+   if (!SUCCEEDED(hr))
+   {
+      CoTaskMemFree(pVfwCapture);
+      return E_OUTOFMEMORY;
+   }
+
+   pVfwCapture->pmt = NULL;
+
+   *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", qzdebugstr_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);
+
+   if (*ppv)
+   {
+      IUnknown_AddRef((IUnknown *)(*ppv));
+      return S_OK;
+   }
+
+   FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI VfwCapture_AddRef(IBaseFilter * iface)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   ULONG refCount = InterlockedIncrement(&This->refCount);
+
+   TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, refCount - 1);
+
+   return refCount;
+}
+
+static ULONG WINAPI VfwCapture_Release(IBaseFilter * iface)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   ULONG refCount = InterlockedDecrement(&This->refCount);
+   TRACE("(%p/%p)->() Release from %ld\n", This, iface, refCount + 1);
+
+   if (!refCount)
+   {
+      if (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");
+   This->state = State_Stopped;
+   return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   TRACE("()\n");
+   This->state = State_Paused;
+   return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   TRACE("(%lx%08lx)\n", (ULONG)(tStart >> 32), (ULONG)tStart);
+   This->state = State_Running;
+   return S_OK;
+}
+
+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)
+{
+/* VfwCapture *This = (VfwCapture *)iface; */
+   TRACE("(%p)\n", pClock);
+   return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
+{
+/* VfwCapture *This = (VfwCapture *)iface; */
+   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 = This->pOutputPin ? 1 : 0;
+   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)\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)
+{
+   FIXME("%p: stub, not worth the effort\n", iface);
+   return S_OK;
+}
+
+static ULONG WINAPI AMStreamConfig_AddRef(IAMStreamConfig * iface)
+{
+   FIXME("%p: stub, not worth the effort\n", iface);
+   return 1;
+}
+
+static ULONG WINAPI AMStreamConfig_Release(IAMStreamConfig * iface)
+{
+   FIXME("%p: stub, not worth the effort\n", iface);
+   return 1;
+}
+
+static HRESULT WINAPI AMStreamConfig_SetFormat(IAMStreamConfig *iface,
+                                              AM_MEDIA_TYPE *pmt) {
+   ERR("%p: %p stub !!\n", iface, pmt);
+   return E_NOTIMPL;
+}
+
+static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface,
+                                              AM_MEDIA_TYPE **pmt) {
+   ERR("%p: %p stub !!\n", iface, pmt);
+   // FIXME: The stuff below is just there so it contains something
+
+   VIDEOINFOHEADER *pvi;
+
+   pmt[0] = CoTaskMemAlloc(sizeof (AM_MEDIA_TYPE));
+   memcpy (&pmt[0]->formattype, &FORMAT_VideoInfo, sizeof (GUID));
+   memcpy (&pmt[0]->majortype, &MEDIATYPE_Video, sizeof (GUID));
+   memcpy (&pmt[0]->subtype, &MEDIASUBTYPE_RGB24, sizeof (GUID));
+   pmt[0]->bTemporalCompression = 0;
+   pmt[0]->bFixedSizeSamples = 1;
+   pmt[0]->lSampleSize = 1;
+
+   pmt[0]->cbFormat = sizeof(VIDEOINFOHEADER);
+   pmt[0]->pbFormat = CoTaskMemAlloc(pmt[0]->cbFormat);
+   ZeroMemory(pmt[0]->pbFormat, pmt[0]->cbFormat);
+   pvi = (VIDEOINFOHEADER *)pmt[0]->pbFormat;
+   pvi->rcSource.right = 640; pvi->rcSource.bottom = 480;
+   pvi->rcTarget.right = 640; pvi->rcTarget.bottom = 480;
+   pvi->dwBitRate = 10;
+   pvi->dwBitErrorRate = 0;
+   pvi->AvgTimePerFrame = (LONGLONG)(10000000.0 / 25); // 25 is hardcoded
+
+   // FIXME: The stuff below is just there so it contains something
+
+   pvi->bmiHeader.biWidth = 640;
+   pvi->bmiHeader.biHeight = 480;
+   pvi->bmiHeader.biBitCount = 24;
+   pvi->bmiHeader.biCompression = BI_RGB;
+   pvi->bmiHeader.biSizeImage = 0;
+   pvi->bmiHeader.biXPelsPerMeter = 640;
+   pvi->bmiHeader.biYPelsPerMeter = 480;
+   pvi->bmiHeader.biClrUsed = 0;
+   pvi->bmiHeader.biClrImportant = 0;
+
+   return S_OK;
+}
+
+typedef struct _VIDEO_STREAM_CONFIG_CAPS {
+   GUID guid;
+   ULONG VideoStandard;
+   SIZE InputSize;
+   SIZE MinCroppingSize;
+   SIZE MaxCroppingSize;
+   int CropGranularityX;
+   int CropGranularityY;
+   int CropAlignX;
+   int CropAlignY;
+   SIZE MinOutputSize;
+   SIZE MaxOutputSize;
+   int OutputGranularityX;
+   int OutputGranularityY;
+   int StretchTapsX;
+   int StretchTapsY;
+   int ShrinkTapsX;
+   int ShrinkTapsY;
+   LONGLONG MinFrameInterval;
+   LONGLONG MaxFrameInterval;
+   LONG MinBitsPerSecond;
+   LONG MaxBitsPerSecond;
+} VIDEO_STREAM_CONFIG_CAPS;
+
+static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface, int *piCount, int *piSize)
+{
+   TRACE("%p: %p %p - stub! Should be harmless\n", iface, piCount, piSize);
+   *piCount = 1;
+   *piSize = sizeof(VIDEO_STREAM_CONFIG_CAPS);
+   return S_OK; /* Not implemented for this interface, but who cares =) */
+}
+
+static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
+int iIndex, AM_MEDIA_TYPE **pmt, BYTE *pSCC)
+{
+   TRACE("%p: %d %p %p\n", iface, iIndex, pmt, pSCC);
+
+   VIDEOINFOHEADER *pvi;
+   VIDEO_STREAM_CONFIG_CAPS *vsc;
+
+   pmt[0] = CoTaskMemAlloc(sizeof (AM_MEDIA_TYPE));
+   memcpy (&pmt[0]->formattype, &FORMAT_VideoInfo, sizeof (GUID));
+   memcpy (&pmt[0]->majortype, &MEDIATYPE_Video, sizeof (GUID));
+   memcpy (&pmt[0]->subtype, &MEDIASUBTYPE_RGB24, sizeof (GUID));
+   pmt[0]->bTemporalCompression = 0;
+   pmt[0]->bFixedSizeSamples = 1;
+   pmt[0]->lSampleSize = 1;
+
+   // FIXME: The stuff below is just there so it contains something
+
+   pmt[0]->cbFormat = sizeof(VIDEOINFOHEADER);
+   pmt[0]->pbFormat = CoTaskMemAlloc(pmt[0]->cbFormat);
+   ZeroMemory(pmt[0]->pbFormat, pmt[0]->cbFormat);
+   pvi = (VIDEOINFOHEADER *)pmt[0]->pbFormat;
+   pvi->rcSource.right = 640; pvi->rcSource.bottom = 480;
+   pvi->rcTarget.right = 640; pvi->rcTarget.bottom = 480;
+   pvi->dwBitRate = 10;
+   pvi->dwBitErrorRate = 0;
+   pvi->AvgTimePerFrame = (LONGLONG)(10000000.0 / 25); // 25 is hardcoded
+
+   // FIXME: The stuff below is just there so it contains something
+
+   pvi->bmiHeader.biWidth = 640;
+   pvi->bmiHeader.biHeight = 480;
+   pvi->bmiHeader.biBitCount = 24;
+   pvi->bmiHeader.biCompression = BI_RGB;
+   pvi->bmiHeader.biSizeImage = 0;
+   pvi->bmiHeader.biXPelsPerMeter = 640;
+   pvi->bmiHeader.biYPelsPerMeter = 480;
+   pvi->bmiHeader.biClrUsed = 0;
+   pvi->bmiHeader.biClrImportant = 0;
+
+   // FIXME: Blahblahblah
+
+   vsc = (VIDEO_STREAM_CONFIG_CAPS *)pSCC;
+   memcpy (&vsc->guid, &FORMAT_VideoInfo, sizeof (GUID));
+   vsc->VideoStandard = 0;
+   vsc->InputSize.cx = 640; vsc->InputSize.cy = 480;
+   vsc->MinCroppingSize.cx = 320; vsc->MinCroppingSize.cy = 240;
+   vsc->MaxCroppingSize.cx = 640; vsc->MaxCroppingSize.cy = 480;
+   vsc->CropGranularityX = 10;
+   vsc->CropGranularityY = 10;
+   vsc->CropAlignX = 0;
+   vsc->CropAlignY = 0;
+   vsc->MinOutputSize.cx = 320; vsc->MinOutputSize.cy = 240;
+   vsc->MaxOutputSize.cx = 640; vsc->MaxOutputSize.cy = 480;
+   vsc->OutputGranularityX = 10;
+   vsc->OutputGranularityY = 10;
+   vsc->StretchTapsX = 1;
+   vsc->StretchTapsY = 1;
+   vsc->ShrinkTapsX = 1;
+   vsc->ShrinkTapsY = 1;
+   vsc->MinFrameInterval = (LONGLONG)(10000000.0 / 25);
+   vsc->MaxFrameInterval = (LONGLONG)(10000000.0 / 25);
+   vsc->MinBitsPerSecond = 24;
+   vsc->MaxBitsPerSecond = 24;
+
+   return S_OK; /* Not implemented for this interface */
+}
+
+static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
+{
+   AMStreamConfig_QueryInterface,
+   AMStreamConfig_AddRef,
+   AMStreamConfig_Release,
+   AMStreamConfig_SetFormat,
+   AMStreamConfig_GetFormat,
+   AMStreamConfig_GetNumberOfCapabilities,
+   AMStreamConfig_GetStreamCaps
+};
+
+/* IKsPropertySet interface */
+static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet * iface, REFIID riid, LPVOID * ppv)
+{
+   TRACE("%p: stub, not worth the effort\n", iface);
+   return S_OK;
+}
+
+static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
+{
+   TRACE("%p: stub, not worth the effort\n", iface);
+   return 1;
+}
+
+static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
+{
+   TRACE("%p: stub, not worth the effort\n", iface);
+   return 1;
+}
+
+static HRESULT WINAPI KSP_Set(IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData)
+{
+   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 (dwPropID != AMPROPERTY_PIN_CATEGORY)
+      return E_PROP_ID_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;
+   TRACE("() Returning CaP\n");
+   return S_OK;
+}
+
+static HRESULT WINAPI KSP_QuerySupported(IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport)
+{
+   TRACE("%p: stub\n", iface);
+   return E_NOTIMPL;
+}
+
+static IKsPropertySetVtbl KSP_VTable =
+{
+   KSP_QueryInterface,
+   KSP_AddRef,
+   KSP_Release,
+   KSP_Set,
+   KSP_Get,
+   KSP_QuerySupported
+};
+
+/* VfwPin implementation */
+typedef struct VfwPinImpl
+{
+   OutputPin pin;
+
+   IKsPropertySetVtbl * KSP_VT;
+   HANDLE hEvent;
+   BOOL bFlushing;
+   DATAREQUEST * pHead; /* head of data request list */
+   CRITICAL_SECTION csList; /* critical section to protect operations on list */
+} VfwPinImpl;
+
+static HRESULT AcceptProcAFR(LPVOID iface, const AM_MEDIA_TYPE *pmt)
+{
+   VfwPinImpl *This = (VfwPinImpl *)iface;
+   FIXME("%p: %p\n", This, pmt);
+   return S_FALSE;
+}
+
+static HRESULT VfwPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+   OutputPin *This = (OutputPin *)iface;
+   HRESULT hr;
+   WCHAR *fuckay;
+
+   TRACE("(%p, %p)\n", pReceivePin, pmt);
+    /* FIXME: call queryacceptproc */
+   This->pin.pConnectedTo = pReceivePin;
+   IPin_AddRef(pReceivePin);
+   CopyMediaType(&This->pin.mtCurrent, pmt);
+   IPin_QueryId(pReceivePin, (LPWSTR *)&fuckay);
+   dump_AM_MEDIA_TYPE(pmt);
+
+   FIXME("Before crash: %p %p %p - %s\n", pReceivePin, iface, pmt, debugstr_w(fuckay));
+   ERR("This *WILL* crash if WINEDEBUG contains quartz.. SOMEONE PLEASE HELP ME OUT!");
+   hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
+
+   if (FAILED(hr))
+   {
+      ERR("Failed!");
+      IPin_Release(This->pin.pConnectedTo);
+      This->pin.pConnectedTo = NULL;
+   }
+
+   FIXME(" -- %lx\n", hr);
+   return hr;
+}
+
+static HRESULT VfwPin_Construct(IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
+{
+   VfwPinImpl * pPinImpl;
+   PIN_INFO piOutput;
+
+   pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
+   if (!pPinImpl)
+      return E_OUTOFMEMORY;
+
+   piOutput.dir = PINDIR_OUTPUT;
+   piOutput.pFilter = pBaseFilter;
+   strcpyW(piOutput.achName, wszOutputPinName);
+
+   if (SUCCEEDED(OutputPin_Init(&piOutput, NULL, pBaseFilter, AcceptProcAFR, pCritSec, &pPinImpl->pin)))
+   {
+      ERR("Success\n");
+      pPinImpl->KSP_VT = &KSP_VTable;
+      pPinImpl->pin.pin.lpVtbl = &VfwPin_Vtbl;
+      pPinImpl->hEvent = CreateEventW(NULL, 0, 0, NULL);
+      pPinImpl->bFlushing = FALSE;
+      pPinImpl->pHead = NULL;
+      pPinImpl->pin.pConnectSpecific = VfwPin_ConnectSpecific;
+      InitializeCriticalSection(&pPinImpl->csList);
+      *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", qzdebugstr_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", qzdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI VfwPin_Release(IPin * iface)
+{
+   VfwPinImpl *This = (VfwPinImpl *)iface;
+   ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
+   TRACE("()\n");
+
+   if (!refCount)
+   {
+      DATAREQUEST * pCurrent;
+      DATAREQUEST * pNext;
+      for (pCurrent = This->pHead; pCurrent; pCurrent = pNext)
+      {
+          pNext = pCurrent->pNext;
+          CoTaskMemFree(pCurrent);
+      }
+      CloseHandle(This->hEvent);
+      CoTaskMemFree(This);
+      return 0;
+   }
+   return refCount;
+}
+
+static HRESULT WINAPI VfwPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
+{
+   ENUMMEDIADETAILS emd;
+   AM_MEDIA_TYPE q[1];
+   int x = 0;
+
+   VfwPinImpl *This = (VfwPinImpl *)iface;
+   FIXME("(%p) - stub!\n", ppEnum);
+   emd.cMediaTypes = 1;
+   for (; x < 1; x++) {
+      VIDEOINFOHEADER *pvi;
+      CopyMemory(&q[x].majortype, &MEDIATYPE_Video, sizeof (GUID));
+      CopyMemory(&q[x].subtype, &MEDIASUBTYPE_RGB24, sizeof (GUID));
+      q[x].bFixedSizeSamples = TRUE;
+      q[x].bTemporalCompression = FALSE;
+      q[x].lSampleSize = 0;
+      CopyMemory(&q[x].formattype, &FORMAT_VideoInfo, sizeof (GUID));
+      q[x].cbFormat = sizeof(VIDEOINFOHEADER);
+      q[x].pbFormat = CoTaskMemAlloc(q[x].cbFormat);
+      pvi = (VIDEOINFOHEADER *)q[x].pbFormat;
+      pvi->rcSource.right = 640; pvi->rcSource.bottom = 480;
+      pvi->rcTarget.right = 640; pvi->rcTarget.bottom = 480;
+      pvi->dwBitRate = 10;
+      pvi->dwBitErrorRate = 0;
+      pvi->AvgTimePerFrame = (LONGLONG)(10000000.0 / 25);
+      pvi->bmiHeader.biWidth = 640;
+      pvi->bmiHeader.biPlanes = 1;
+      pvi->bmiHeader.biHeight = 480;
+      pvi->bmiHeader.biBitCount = 24;
+      pvi->bmiHeader.biCompression = BI_RGB;
+      pvi->bmiHeader.biSizeImage = 1000000;
+      pvi->bmiHeader.biXPelsPerMeter = 640;
+      pvi->bmiHeader.biYPelsPerMeter = 480;
+      pvi->bmiHeader.biClrUsed = 65536;
+      pvi->bmiHeader.biClrImportant = 0;
+   }
+   emd.pMediaTypes = q;
+   return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
+}
+
+static const IPinVtbl VfwPin_Vtbl =
+{
+   VfwPin_QueryInterface,
+   IPinImpl_AddRef,
+   VfwPin_Release,
+   OutputPin_Connect,
+   OutputPin_ReceiveConnection,
+   IPinImpl_Disconnect,
+   IPinImpl_ConnectedTo,
+   IPinImpl_ConnectionMediaType,
+   IPinImpl_QueryPinInfo,
+   IPinImpl_QueryDirection,
+   IPinImpl_QueryId,
+   IPinImpl_QueryAccept,
+   VfwPin_EnumMediaTypes,
+   IPinImpl_QueryInternalConnections,
+   OutputPin_EndOfStream, 
+   OutputPin_BeginFlush,
+   OutputPin_EndFlush,
+   OutputPin_NewSegment
+};  
+
diff -Nru wine-old/include/axextend.idl wine-new/include/axextend.idl
--- wine-old/include/axextend.idl	2003-07-01 06:33:35.000000000 +0200
+++ wine-new/include/axextend.idl	2005-04-09 16:12:13.000000000 +0200
@@ -69,6 +69,23 @@
 interface IQualityControl;
 interface ISeekingPassThru;
 
+/*****************************************************************************
+ * IAMStreamConfig interface
+ */
+[
+    object,
+    uuid(c6e13340-30ac-11d0-a18c-00a0c9118956),
+    pointer_default(unique)
+]
+interface IAMStreamConfig : IUnknown
+{
+    HRESULT SetFormat( [in] AM_MEDIA_TYPE *pmt);
+    HRESULT GetFormat( [in] AM_MEDIA_TYPE **pmt);
+    HRESULT GetNumberOfCapabilities( [out] int *piCount, [out] int *piSize);
+    HRESULT GetStreamCaps( [in] int iIndex, [out] AM_MEDIA_TYPE **pmt,
+                          [out] BYTE *pSCC);
+}
+
 typedef struct
 {
     CLSID Clsid;


More information about the wine-devel mailing list