diff --git a/dlls/msvideo/.cvsignore b/dlls/msvideo/.cvsignore
index a38e69ce5801cb8f19cd04eb5fe745d413639c87..e32d4aa315be1e946383fa15a758a9f6895d6a9c 100644
--- a/dlls/msvideo/.cvsignore
+++ b/dlls/msvideo/.cvsignore
@@ -1,3 +1,4 @@
+*.glue.c
 *.spec.c
 *.spec.glue.s
 Makefile
diff --git a/dlls/msvideo/Makefile.in b/dlls/msvideo/Makefile.in
index 6d26edb5e5843b4f21adb85da6aa3cd233d49066..66a669e114411ae1d4996a52404b5eecd1087c9e 100644
--- a/dlls/msvideo/Makefile.in
+++ b/dlls/msvideo/Makefile.in
@@ -8,7 +8,10 @@ ALTNAMES  = msvideo
 IMPORTS   = winmm
 
 C_SRCS = \
-	msvideo_main.c
+	msvideo_main.c \
+	drawdib.c
+
+GLUE = msvideo_main.c
 
 @MAKE_DLL_RULES@
 
diff --git a/dlls/msvideo/drawdib.c b/dlls/msvideo/drawdib.c
new file mode 100644
index 0000000000000000000000000000000000000000..e7c9517283c39c92b1605415ac8df4947d13cc68
--- /dev/null
+++ b/dlls/msvideo/drawdib.c
@@ -0,0 +1,450 @@
+/* 
+ * Copyright 2000 Bradley Baetz
+ *
+ * Fixme: Some flags are ignored
+ * Should be doing buffering when requested
+ * Handle palettes
+ */
+
+#include "windef.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winbase.h"
+#include "debugtools.h"
+#include "driver.h"
+#include "vfw.h"
+#include "windef.h"
+
+DEFAULT_DEBUG_CHANNEL(msvideo);
+typedef struct {
+	HDC hdc;
+	INT dxDst;
+	INT dyDst;
+	LPBITMAPINFOHEADER lpbi;
+	INT dxSrc;
+	INT dySrc;
+	HPALETTE hpal;				/* Palette to use for the DIB */
+	BOOL begun;					/* DrawDibBegin has been called */
+	LPBITMAPINFOHEADER lpbiOut;	/* Output format */
+	HIC hic;					/* HIC for decompression */
+	HDC hMemDC;					/* DC for buffering */
+	HBITMAP hOldDib;			/* Original Dib */
+	HBITMAP hDib;				/* DibSection */
+	LPVOID lpvbits;				/* Buffer for holding decompressed dib */
+} WINE_HDD;
+
+/***********************************************************************
+ *		DrawDibOpen		[MSVFW32.10]
+ */
+HDRAWDIB VFWAPI DrawDibOpen(void) {
+	HDRAWDIB hdd;
+
+	TRACE("(void)\n");
+	hdd = GlobalAlloc16(GHND,sizeof(WINE_HDD));
+	TRACE("=> %d\n",hdd);
+	return hdd;
+}
+
+/***********************************************************************
+ *		DrawDibOpen		[MSVIDEO.102]
+ */
+HDRAWDIB16 VFWAPI DrawDibOpen16(void) {
+	return (HDRAWDIB16)DrawDibOpen();
+}
+
+/***********************************************************************
+ *		DrawDibClose		[MSVFW32.5]
+ */
+BOOL VFWAPI DrawDibClose(HDRAWDIB hdd) {
+	WINE_HDD *whdd = GlobalLock16(hdd);
+
+	TRACE("(0x%08lx)\n",(DWORD)hdd);
+
+	if (!whdd)
+		return FALSE;
+
+	if (whdd->begun)
+		DrawDibEnd(hdd);
+
+	GlobalUnlock16(hdd);
+	GlobalFree16(hdd);
+	return TRUE;
+}
+
+/***********************************************************************
+ *		DrawDibClose		[MSVIDEO.103]
+ */
+BOOL16 VFWAPI DrawDibClose16(HDRAWDIB16 hdd) {
+	return DrawDibClose(hdd);
+}
+
+/***********************************************************************
+ *		DrawDibEnd		[MSVFW32.7]
+ */
+BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd) {
+	BOOL ret = TRUE;
+	WINE_HDD *whdd = GlobalLock16(hdd);
+	
+	TRACE("(0x%08lx)\n",(DWORD)hdd);
+
+	whdd->hpal = 0; /* Do not free this */
+	whdd->hdc = 0;
+	if (whdd->lpbi) {
+		HeapFree(GetProcessHeap(),0,whdd->lpbi);
+		whdd->lpbi = NULL;
+	}
+	if (whdd->lpbiOut) {
+		HeapFree(GetProcessHeap(),0,whdd->lpbiOut);
+		whdd->lpbiOut = NULL;
+	}
+
+	whdd->begun = FALSE;
+
+	/*if (whdd->lpvbits)
+	  HeapFree(GetProcessHeap(),0,whdd->lpvbuf);*/
+
+	if (whdd->hMemDC) {
+		SelectObject(whdd->hMemDC,whdd->hOldDib);
+		DeleteDC(whdd->hMemDC);
+	}
+
+	if (whdd->hDib)
+		DeleteObject(whdd->hDib);
+	
+	if (whdd->hic) {
+		ICDecompressEnd(whdd->hic);
+		ICClose(whdd->hic);
+	}
+
+	whdd->lpvbits = NULL;
+
+	GlobalUnlock16(hdd);
+	return ret;
+}
+
+/***********************************************************************
+ *		DrawDibEnd		[MSVIDEO.105]
+ */
+BOOL16 VFWAPI DrawDibEnd16(HDRAWDIB16 hdd) {
+	return DrawDibEnd(hdd);
+}
+
+/***********************************************************************
+ *              DrawDibBegin            [MSVFW32.3]
+ */
+BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
+						 HDC      hdc,
+						 INT      dxDst,
+						 INT      dyDst,
+						 LPBITMAPINFOHEADER lpbi,
+						 INT      dxSrc,
+						 INT      dySrc,
+						 UINT     wFlags) {
+	BOOL ret = TRUE;
+	WINE_HDD *whdd;
+
+	TRACE("(%d,0x%lx,%d,%d,%p,%d,%d,0x%08lx)\n",
+		hdd,(DWORD)hdc,dxDst,dyDst,lpbi,dxSrc,dySrc,(DWORD)wFlags
+	);
+
+	if (wFlags)
+		FIXME("wFlags == 0x%08lx not handled\n",(DWORD)wFlags);
+
+	whdd = (WINE_HDD*)GlobalLock16(hdd);
+	
+	if (whdd->begun)
+		DrawDibEnd(hdd);
+
+	if (lpbi->biCompression) {
+		DWORD size;
+
+		whdd->hic = ICOpen(ICTYPE_VIDEO,lpbi->biCompression,ICMODE_DECOMPRESS);
+		if (!whdd->hic) {
+			ERR("Could not open IC. biCompression == 0x%08lx\n",lpbi->biCompression);
+			ret = FALSE;
+		}
+
+		if (ret) {
+			size = ICDecompressGetFormat(whdd->hic,lpbi,NULL);
+			if (size == ICERR_UNSUPPORTED) {
+				FIXME("Codec doesn't support GetFormat, giving up.\n");
+				ret = FALSE;
+			}
+		}
+
+		if (ret) {
+			whdd->lpbiOut = HeapAlloc(GetProcessHeap(),0,size);
+
+			if (ICDecompressGetFormat(whdd->hic,lpbi,whdd->lpbiOut) != ICERR_OK)
+				ret = FALSE;
+		}
+
+		if (ret) {
+			/* FIXME: Use Ex functions if available? */
+			if (ICDecompressBegin(whdd->hic,lpbi,whdd->lpbiOut) != ICERR_OK)
+				ret = FALSE;
+
+			TRACE("biSizeImage == %ld\n",whdd->lpbiOut->biSizeImage);
+			TRACE("biCompression == %ld\n",whdd->lpbiOut->biCompression);
+			TRACE("biBitCount == %d\n",whdd->lpbiOut->biBitCount);
+		}
+	} else {
+		/* No compression */
+		TRACE("Not compressed!\n");
+		whdd->lpbiOut = HeapAlloc(GetProcessHeap(),0,lpbi->biSize);
+		memcpy(whdd->lpbiOut,lpbi,lpbi->biSize);
+	}
+
+	if (ret) {
+		/*whdd->lpvbuf = HeapAlloc(GetProcessHeap(),0,whdd->lpbiOut->biSizeImage);*/
+		
+		whdd->hMemDC = CreateCompatibleDC(hdc);
+		TRACE("Creating: %ld,%p\n",whdd->lpbiOut->biSize,whdd->lpvbits);
+		whdd->hDib = CreateDIBSection(whdd->hMemDC,(BITMAPINFO *)whdd->lpbiOut,DIB_RGB_COLORS,&(whdd->lpvbits),0,0);
+		if (!whdd->hDib) {
+			TRACE("Error: %ld\n",GetLastError());
+		}
+		TRACE("Created: %d,%p\n",whdd->hDib,whdd->lpvbits);
+		whdd->hOldDib = SelectObject(whdd->hMemDC,whdd->hDib);
+	}
+
+	if (ret) {
+		whdd->hdc = hdc;
+		whdd->dxDst = dxDst;
+		whdd->dyDst = dyDst;
+		whdd->lpbi = HeapAlloc(GetProcessHeap(),0,lpbi->biSize);
+		memcpy(whdd->lpbi,lpbi,lpbi->biSize);
+		whdd->dxSrc = dxSrc;
+		whdd->dySrc = dySrc;
+		whdd->begun = TRUE;
+		whdd->hpal = 0;
+	} else {
+		if (whdd->hic)
+			ICClose(whdd->hic);
+		if (whdd->lpbiOut) {
+			HeapFree(GetProcessHeap(),0,whdd->lpbiOut);
+			whdd->lpbiOut = NULL;
+		}
+	}
+
+	GlobalUnlock16(hdd);
+
+	return ret;
+}
+
+/************************************************************************
+ *		DrawDibBegin		[MSVIDEO.104]
+ */
+BOOL16 VFWAPI DrawDibBegin16(HDRAWDIB16 hdd,
+						   HDC16      hdc,
+						   INT16      dxDst,
+						   INT16      dyDst,
+						   LPBITMAPINFOHEADER lpbi,
+						   INT16      dxSrc,
+						   INT16      dySrc,
+						   UINT16     wFlags) {
+	return DrawDibBegin(hdd,hdc,dxDst,dyDst,lpbi,dxSrc,dySrc,wFlags);
+}
+
+/**********************************************************************
+ *		DrawDibDraw		[MSVFW32.6]
+ */
+BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd,             
+						HDC hdc,
+						INT xDst,
+						INT yDst,
+						INT dxDst,
+						INT dyDst,
+						LPBITMAPINFOHEADER lpbi,
+						LPVOID lpBits,
+						INT xSrc,
+						INT ySrc,
+						INT dxSrc,
+						INT dySrc,
+						UINT wFlags) {
+	WINE_HDD *whdd;
+	BOOL ret = TRUE;
+
+	TRACE("(%d,0x%lx,%d,%d,%d,%d,%p,%p,%d,%d,%d,%d,0x%08lx)\n",
+		  hdd,(DWORD)hdc,xDst,yDst,dxDst,dyDst,lpbi,lpBits,xSrc,ySrc,dxSrc,dySrc,(DWORD)wFlags
+	);
+
+	if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME))
+		FIXME("wFlags == 0x%08lx not handled\n",(DWORD)wFlags);
+
+	if (!lpBits) {
+		/* Undocumented? */
+		lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(lpbi->biClrUsed*sizeof(RGBQUAD));
+	}
+
+	whdd = GlobalLock16(hdd);
+
+#define CHANGED(x) (whdd->##x != ##x)
+
+	if ((!whdd->begun) || (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc)) || (!(wFlags & DDF_SAME_DRAW) &&
+		 (CHANGED(lpbi) || CHANGED(dxSrc) || CHANGED(dySrc) || CHANGED(dxDst) || CHANGED(dyDst)))) {
+		TRACE("Something changed!\n");
+		ret = DrawDibBegin(hdd,hdc,dxDst,dyDst,lpbi,dxSrc,dySrc,0);
+	}
+
+#undef CHANGED
+
+    if ((dxDst == -1) && (dyDst == -1)) {
+		dxDst = dxSrc;
+		dyDst = dySrc;
+	}
+
+	if (lpbi->biCompression) {
+		DWORD flags = 0;
+		
+		TRACE("Compression == 0x%08lx\n",lpbi->biCompression);
+		
+		if (wFlags & DDF_NOTKEYFRAME)
+		  flags |= ICDECOMPRESS_NOTKEYFRAME;
+		
+		ICDecompress(whdd->hic,flags,lpbi,lpBits,whdd->lpbiOut,whdd->lpvbits);
+	} else {
+		memcpy(whdd->lpvbits,lpBits,lpbi->biSizeImage);
+	}
+
+	SelectPalette(hdc,whdd->hpal,FALSE);
+
+	StretchBlt(whdd->hdc,xDst,yDst,dxDst,dyDst,whdd->hMemDC,xSrc,ySrc,dxSrc,dySrc,SRCCOPY);
+
+	GlobalUnlock16(hdd);
+	return ret;
+}
+
+/**********************************************************************
+ *		DrawDibDraw		[MSVIDEO.106]
+ */
+BOOL16 VFWAPI DrawDibDraw16(HDRAWDIB16 hdd,             
+						  HDC16 hdc,
+						  INT16 xDst,
+						  INT16 yDst,
+						  INT16 dxDst,
+						  INT16 dyDst,
+						  LPBITMAPINFOHEADER lpbi,
+						  LPVOID lpBits,
+						  INT16 xSrc,
+						  INT16 ySrc,
+						  INT16 dxSrc,
+						  INT16 dySrc,
+						  UINT16 wFlags) {
+	return DrawDibDraw(hdd,hdc,xDst,yDst,dxDst,dyDst,lpbi,lpBits,xSrc,ySrc,dxSrc,dySrc,wFlags);
+}
+
+/*************************************************************************
+ *		DrawDibStart		[MSVFW32.14]
+ */
+BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
+	FIXME("(0x%08lx,%ld), stub\n",(DWORD)hdd,rate);
+	return TRUE;
+}
+
+/*************************************************************************
+ *		DrawDibStart		[MSVIDEO.118]
+ */
+BOOL16 VFWAPI DrawDibStart16(HDRAWDIB16 hdd, DWORD rate) {
+	return DrawDibStart(hdd,rate);
+}
+
+/*************************************************************************
+ *		DrawDibStop		[MSVFW32.15]
+ */
+BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
+	FIXME("(0x%08lx), stub\n",(DWORD)hdd);
+	return TRUE;
+}
+
+/*************************************************************************
+ *		DrawDibStop		[MSVIDEO.119]
+ */
+BOOL16 DrawDibStop16(HDRAWDIB16 hdd) {
+	return DrawDibStop(hdd);
+}
+
+/***********************************************************************
+ *              DrawDibSetPalette       [MSVFW32.13]   
+ */
+BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal) {
+	WINE_HDD *whdd;
+
+	TRACE("(0x%08lx,0x%08lx)\n",(DWORD)hdd,(DWORD)hpal);
+
+	whdd = GlobalLock16(hdd);
+	whdd->hpal = hpal;
+	
+	if (whdd->begun) {
+		SelectPalette(whdd->hdc,hpal,0);
+		RealizePalette(whdd->hdc);
+	}
+	GlobalUnlock16(hdd);
+	return TRUE;
+}
+
+/***********************************************************************
+ *              DrawDibSetPalette       [MSVIDEO.110]
+ */
+BOOL16 VFWAPI DrawDibSetPalette16(HDRAWDIB16 hdd, HPALETTE16 hpal) {
+	return DrawDibSetPalette(hdd,hpal);
+}
+
+/***********************************************************************
+ *              DrawDibGetPalette       [MSVFW32.9]   
+ */
+HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd) {
+	WINE_HDD *whdd;
+	HPALETTE ret;
+
+	TRACE("(0x%08lx)\n",(DWORD)hdd);
+
+	whdd = GlobalLock16(hdd);
+	ret = whdd->hpal;
+	GlobalUnlock16(hdd);
+	return ret;
+}
+
+/***********************************************************************
+ *              DrawDibGetPalette       [MSVIDEO.108]]   
+ */
+HPALETTE16 VFWAPI DrawDibGetPalette16(HDRAWDIB16 hdd) {
+	return (HPALETTE16)DrawDibGetPalette(hdd);
+}
+
+/***********************************************************************
+ *              DrawDibRealize          [MSVFW32.12]
+ */
+UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground) {
+	WINE_HDD *whdd;
+	HPALETTE oldPal;
+	UINT ret = 0;
+
+	FIXME("(%d,0x%08lx,%d), stub\n",hdd,(DWORD)hdc,fBackground);
+	
+	whdd = GlobalLock16(hdd);
+
+	if (!whdd || !(whdd->begun)) {
+		ret = 0;
+		goto out;
+	}
+	
+	if (!whdd->hpal)
+		whdd->hpal = CreateHalftonePalette(hdc);
+
+	oldPal = SelectPalette(hdc,whdd->hpal,fBackground);
+	ret = RealizePalette(hdc);
+	
+ out:
+	GlobalUnlock16(hdd);
+
+	TRACE("=> %u\n",ret);
+	return ret;
+}
+
+/***********************************************************************
+ *              DrawDibRealize          [MSVIDEO.112]
+ */
+UINT16 VFWAPI DrawDibRealize16(HDRAWDIB16 hdd, HDC16 hdc, BOOL16 fBackground) {
+	return (UINT16)DrawDibRealize(hdd,hdc,fBackground);
+}
diff --git a/dlls/msvideo/msvfw32.spec b/dlls/msvideo/msvfw32.spec
index 15f61dc4c3962796f609f52850a139fd0b7887e5..761940127a94ef0df41c964392d56c233fb131cc 100644
--- a/dlls/msvideo/msvfw32.spec
+++ b/dlls/msvideo/msvfw32.spec
@@ -10,16 +10,16 @@ import	winmm.dll
   3 stdcall DrawDibBegin(long long long long ptr long long long) DrawDibBegin
   4 stub    DrawDibChangePalette
   5 stdcall DrawDibClose(long) DrawDibClose
-  6 stub    DrawDibDraw
-  7 stub    DrawDibEnd
+  6 stdcall DrawDibDraw(long long long long long long ptr ptr long long long long long) DrawDibDraw
+  7 stdcall DrawDibEnd(long) DrawDibEnd
   8 stub    DrawDibGetBuffer
-  9 stub    DrawDibGetPalette
+  9 stdcall DrawDibGetPalette(long) DrawDibGetPalette
  10 stdcall DrawDibOpen() DrawDibOpen
  11 stub    DrawDibProfileDisplay
  12 stdcall DrawDibRealize(long long long) DrawDibRealize
  13 stdcall DrawDibSetPalette(long long) DrawDibSetPalette
- 14 stub    DrawDibStart
- 15 stub    DrawDibStop
+ 14 stdcall DrawDibStart(long long) DrawDibStart
+ 15 stdcall DrawDibStop(long) DrawDibStop
  16 stub    DrawDibTime
  17 stub    GetOpenFileNamePreview
  18 stub    GetOpenFileNamePreviewA
diff --git a/dlls/msvideo/msvideo.spec b/dlls/msvideo/msvideo.spec
index 73e30595cb12a2be298b418d857e1f7c61ad24e9..be95db57aa7024ac5f434606e117073b315459d5 100644
--- a/dlls/msvideo/msvideo.spec
+++ b/dlls/msvideo/msvideo.spec
@@ -26,36 +26,36 @@ type win16
 52 stub VIDEOSTREAMALLOCHDRANDBUFFER
 53 stub VIDEOSTREAMFREEHDRANDBUFFER
 60 stub VIDEOMESSAGE
-102 stub DRAWDIBOPEN
-103 stub DRAWDIBCLOSE
-104 stub DRAWDIBBEGIN
-105 stub DRAWDIBEND
-106 stub DRAWDIBDRAW
-108 stub DRAWDIBGETPALETTE
-110 stub DRAWDIBSETPALETTE
+102 pascal16 DrawDibOpen() DrawDibOpen16
+103 pascal16 DrawDibClose(word) DrawDibClose16
+104 pascal16 DrawDibBegin(word word s_word s_word ptr s_word s_word word) DrawDibBegin16
+105 pascal16 DrawDibEnd(word) DrawDibEnd16
+106 pascal16 DrawDibDraw(word word s_word s_word s_word s_word ptr ptr s_word s_word s_word s_word word) DrawDibDraw16
+108 pascal16 DrawDibGetPalette(word) DrawDibGetPalette16
+110 pascal16 DrawDibSetPalette(word word) DrawDibSetPalette16
 111 stub DRAWDIBCHANGEPALETTE
-112 stub DRAWDIBREALIZE
+112 pascal16 DrawDibRealize(word word word) DrawDibRealize16
 113 stub DRAWDIBTIME
 114 stub DRAWDIBPROFILEDISPLAY
 115 stub STRETCHDIB
-118 stub DRAWDIBSTART
-119 stub DRAWDIBSTOP
+118 pascal16 DrawDibStart(word long) DrawDibStart16
+119 pascal16 DrawDibStop(word) DrawDibStop16
 120 stub DRAWDIBGETBUFFER
-200 stub ICINFO
+200 pascal16 ICInfo(long long segptr) ICInfo16
 201 stub ICINSTALL
 202 stub ICREMOVE
-203 stub ICOPEN
-204 stub ICCLOSE
-205 stub ICSENDMESSAGE
-206 stub ICOPENFUNCTION
-207 stub _ICMESSAGE
-212 stub ICGETINFO
-213 stub ICLOCATE
-224 stub _ICCOMPRESS
-230 stub _ICDECOMPRESS
-232 stub _ICDRAWBEGIN
-234 stub _ICDRAW
-239 stub ICGETDISPLAYFORMAT
+203 pascal16 ICOpen(long long word) ICOpen16
+204 pascal ICClose(word) ICClose16
+205 pascal ICSendMessage(word word long long) ICSendMessage16
+206 pascal16 ICOpenFunction(long long word segptr) ICOpenFunction16
+207 pascal _ICMessage() ICMessage16
+212 pascal ICGetInfo(word segptr long) ICGetInfo16
+213 pascal16 ICLocate(long long ptr ptr word) ICLocate16
+224 cdecl _ICCompress(word long segptr segptr segptr segptr segptr segptr long long long segptr segptr) ICCompress16
+230 cdecl _ICDecompress(word long segptr segptr segptr segptr) ICDecompress16
+232 cdecl _ICDrawBegin(word long word word word s_word s_word s_word s_word segptr s_word s_word s_word s_word long long) ICDrawBegin16
+234 cdecl _ICDraw(word long segptr segptr long long) ICDraw16
+239 pascal16 ICGetDisplayFormat(word ptr ptr s_word s_word s_word) ICGetDisplayFormat16
 240 stub ICIMAGECOMPRESS
 241 stub ICIMAGEDECOMPRESS
 242 stub ICCOMPRESSORCHOOSE
diff --git a/dlls/msvideo/msvideo_main.c b/dlls/msvideo/msvideo_main.c
index 993b9aa2799903de2c03cf2ec11d91546453add4..71e1cb1edd945fa98ed665cb5ef6e66f99b39ae7 100644
--- a/dlls/msvideo/msvideo_main.c
+++ b/dlls/msvideo/msvideo_main.c
@@ -1,6 +1,12 @@
 /*
  * Copyright 1998 Marcus Meissner
+ * Copyright 2000 Bradley Baetz 
+ *
+ * FIXME: This all assumes 32 bit codecs
+ *		Win95 appears to prefer 32 bit codecs, even from 16 bit code.
+ *		There is the ICOpenFunction16 to worry about still, though.
  */
+
 #include <stdio.h>
 #include <string.h>
 
@@ -12,24 +18,33 @@
 #include "wine/winestring.h"
 #include "driver.h"
 #include "debugtools.h"
+#include "ldt.h"
+#include "heap.h"
+#include "stackframe.h"
+
+DEFAULT_DEBUG_CHANNEL(msvideo);
 
-DEFAULT_DEBUG_CHANNEL(msvideo)
+/* ### start build ### */
+extern LONG CALLBACK MSVIDEO_CallTo16_long_lwwll(FARPROC16,LONG,WORD,WORD,LONG,LONG);
+/* ### stop build ### */
+
+LPVOID MSVIDEO_MapMsg16To32(UINT msg, LPDWORD lParam1, LPDWORD lParam2);
+void MSVIDEO_UnmapMsg16To32(UINT msg, LPVOID lpv, LPDWORD lParam1, LPDWORD lParam2);
+LRESULT MSVIDEO_SendMessage(HIC hic, UINT msg, DWORD lParam1, DWORD lParam2, BOOL bFrom32);
 
 /***********************************************************************
  *		VideoForWindowsVersion		[MSVFW.2][MSVIDEO.2]
  * Returns the version in major.minor form.
  * In Windows95 this returns 0x040003b6 (4.950)
  */
-DWORD WINAPI
-VideoForWindowsVersion(void) {
+DWORD WINAPI VideoForWindowsVersion(void) {
 	return 0x040003B6; /* 4.950 */
 }
 
 /***********************************************************************
  *		VideoCapDriverDescAndVer	[MSVIDEO.22]
  */
-DWORD WINAPI
-VideoCapDriverDescAndVer(WORD nr,LPVOID buf1,WORD buf1len,LPVOID buf2,WORD buf2len) {
+DWORD WINAPI VideoCapDriverDescAndVer(WORD nr,LPVOID buf1,WORD buf1len,LPVOID buf2,WORD buf2len) {
 	FIXME("(%d,%p,%d,%p,%d), stub!\n",nr,buf1,buf1len,buf2,buf2len);
 	return 0;
 }
@@ -41,12 +56,11 @@ VideoCapDriverDescAndVer(WORD nr,LPVOID buf1,WORD buf1len,LPVOID buf2,WORD buf2l
  * Get information about an installable compressor. Return TRUE if there
  * is one.
  */
-BOOL WINAPI
-ICInfo(
+BOOL VFWAPI ICInfo(
 	DWORD fccType,		/* [in] type of compressor ('vidc') */
 	DWORD fccHandler,	/* [in] <n>th compressor */
-	ICINFO *lpicinfo	/* [out] information about compressor */
-) {
+				   ICINFO *lpicinfo)	/* [out] information about compressor */
+{
 	char	type[5],buf[2000];
 
 	memcpy(type,&fccType,4);type[4]=0;
@@ -70,20 +84,37 @@ ICInfo(
 	return FALSE;
 }
 
+BOOL16 VFWAPI ICInfo16(DWORD fccType, DWORD fccHandler, ICINFO16* /*SEGPTR*/ lpicinfo) {
+	BOOL16 ret;
+	LPVOID lpv;
+	DWORD lParam = (DWORD)lpicinfo;
+	DWORD size = ((ICINFO*)(PTR_SEG_TO_LIN(lpicinfo)))->dwSize;
+
+	/* Use the mapping functions to map the ICINFO structure */
+	lpv = MSVIDEO_MapMsg16To32(ICM_GETINFO,&lParam,&size);
+
+	ret = ICInfo(fccType,fccHandler,(ICINFO*)lParam);
+
+	MSVIDEO_UnmapMsg16To32(ICM_GETINFO,lpv,&lParam,&size);
+	
+	return ret;
+}
+
 /***********************************************************************
  *		ICOpen				[MSVFW.37]
  * Opens an installable compressor. Return special handle.
  */
-HIC WINAPI
-ICOpen(DWORD fccType,DWORD fccHandler,UINT wMode) {
+HIC VFWAPI ICOpen(DWORD fccType,DWORD fccHandler,UINT wMode) {
 	char		type[5],handler[5],codecname[20];
 	ICOPEN		icopen;
 	HDRVR		hdrv;
+	HIC16		hic;
 	WINE_HIC	*whic;
 
 	memcpy(type,&fccType,4);type[4]=0;
 	memcpy(handler,&fccHandler,4);handler[4]=0;
 	TRACE("(%s,%s,0x%08lx)\n",type,handler,(DWORD)wMode);
+
 	sprintf(codecname,"%s.%s",type,handler);
 
 	/* Well, lParam2 is in fact a LPVIDEO_OPEN_PARMS, but it has the 
@@ -104,39 +135,86 @@ ICOpen(DWORD fccType,DWORD fccHandler,UINT wMode) {
 	    if (!hdrv)
 		    return 0;
 	}
-	whic = HeapAlloc(GetProcessHeap(),0,sizeof(WINE_HIC));
+	/* The handle should be a valid 16-bit handle as well */
+	hic = GlobalAlloc16(GHND,sizeof(WINE_HIC));
+	whic = (WINE_HIC*)GlobalLock16(hic);
 	whic->hdrv	= hdrv;
 	whic->driverproc= NULL;
-	whic->private	= ICSendMessage((HIC)whic,DRV_OPEN,0,(LPARAM)&icopen);
-	return (HIC)whic;
+	whic->private	= 0;
+	GlobalUnlock16(hic);
+	TRACE("=> 0x%08lx\n",(DWORD)hic);
+	return hic;
 }
 
-/***********************************************************************
- *		ICOpenFunction			[MSVFW.38]
- */
-HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode,
-FARPROC lpfnHandler) {
-	char		type[5],handler[5];
-	HIC		hic;
+HIC MSVIDEO_OpenFunc(DWORD fccType, DWORD fccHandler, UINT wMode, FARPROC lpfnHandler, BOOL bFrom32) {
+	char	type[5],handler[5],codecname[20];
+	HIC16	hic;
+	ICOPEN*  icopen = SEGPTR_NEW(ICOPEN);
 	WINE_HIC	*whic;
 
 	memcpy(type,&fccType,4);type[4]=0;
 	memcpy(handler,&fccHandler,4);handler[4]=0;
-	FIXME("(%s,%s,%d,%p), stub!\n",type,handler,wMode,lpfnHandler);
-	hic = ICOpen(fccType,fccHandler,wMode);
+	TRACE("(%s,%s,%d,%p,%d)\n",type,handler,wMode,lpfnHandler,bFrom32?32:16);
+	
+	icopen->fccType		= fccType;
+	icopen->fccHandler	= fccHandler;
+	icopen->dwSize		= sizeof(ICOPEN);
+	icopen->dwFlags		= wMode;
+	
+	sprintf(codecname,"%s.%s",type,handler);
+
+	hic = GlobalAlloc16(GHND,sizeof(WINE_HIC));
 	if (!hic)
-		return hic;
-	whic = (WINE_HIC*)hic;
+		return 0;
+	whic = GlobalLock16(hic);
 	whic->driverproc = lpfnHandler;
+	
+	whic->private = bFrom32;
+	
+	/* Now try opening/loading the driver. Taken from DRIVER_AddToList */
+	/* What if the function is used more than once? */
+	
+	if (MSVIDEO_SendMessage(hic,DRV_LOAD,0L,0L,bFrom32) != DRV_SUCCESS) {
+		WARN("DRV_LOAD failed for hic 0x%08lx\n",(DWORD)hic);
+		GlobalFree16(hic);
+		return 0;
+	}
+	if (MSVIDEO_SendMessage(hic,DRV_ENABLE,0L,0L,bFrom32) != DRV_SUCCESS) {
+		WARN("DRV_ENABLE failed for hic 0x%08lx\n",(DWORD)hic);
+		GlobalFree16(hic);
+		return 0;
+	}
+	whic->hdrv = MSVIDEO_SendMessage(hic,DRV_OPEN,0,(LPARAM)(SEGPTR_GET(icopen)),FALSE);
+	if (whic->hdrv == 0) {
+		WARN("DRV_OPEN failed for hic 0x%08lx\n",(DWORD)hic);
+		GlobalFree16(hic);
+		return 0;
+	}
+
+	GlobalUnlock16(hic);
+	TRACE("=> 0x%08lx\n",(DWORD)hic);
 	return hic;
 }
 
+/***********************************************************************
+ *		ICOpenFunction			[MSVFW.38]
+ */
+HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, FARPROC lpfnHandler) {
+	return MSVIDEO_OpenFunc(fccType,fccHandler,wMode,lpfnHandler,TRUE);
+}
+
+HIC16 VFWAPI ICOpen16(DWORD fccType, DWORD fccHandler, UINT16 wMode) {
+	return (HIC16)ICOpen(fccType, fccHandler, wMode);
+}
+
+HIC16 VFWAPI ICOpenFunction16(DWORD fccType, DWORD fccHandler, UINT16 wMode, FARPROC16 lpfnHandler) {
+	return MSVIDEO_OpenFunc(fccType, fccHandler, wMode, lpfnHandler,FALSE);
+}
 
 /***********************************************************************
  *		ICGetInfo			[MSVFW.30]
  */
-LRESULT WINAPI
-ICGetInfo(HIC hic,ICINFO *picinfo,DWORD cb) {
+LRESULT VFWAPI ICGetInfo(HIC hic,ICINFO *picinfo,DWORD cb) {
 	LRESULT		ret;
 
 	TRACE("(0x%08lx,%p,%ld)\n",(DWORD)hic,picinfo,cb);
@@ -145,32 +223,43 @@ ICGetInfo(HIC hic,ICINFO *picinfo,DWORD cb) {
 	return ret;
 }
 
+LRESULT VFWAPI ICGetInfo16(HIC16 hic, ICINFO16 *picinfo,DWORD cb) {
+	LRESULT		ret;
+
+	TRACE("(0x%08lx,%p,%ld)\n",(DWORD)hic,picinfo,cb);
+	ret = ICSendMessage16(hic,ICM_GETINFO,(DWORD)picinfo,cb);
+	TRACE("	-> 0x%08lx\n",ret);
+	return ret;
+}
+
 /***********************************************************************
  *		ICLocate			[MSVFW.35]
  */
-HIC  VFWAPI
-ICLocate(
+HIC VFWAPI ICLocate(
 	DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn,
-	LPBITMAPINFOHEADER lpbiOut, WORD wMode
-) {
+	LPBITMAPINFOHEADER lpbiOut, WORD wMode)
+{
 	char	type[5],handler[5];
 	HIC	hic;
 	DWORD	querymsg;
+	LPSTR pszBuffer;
+
+	TRACE("(0x%08lx,0x%08lx,%p,%p,0x%04x)\n", fccType, fccHandler, lpbiIn, lpbiOut, wMode);
 
 	switch (wMode) {
 	case ICMODE_FASTCOMPRESS:
 	case ICMODE_COMPRESS: 
 		querymsg = ICM_COMPRESS_QUERY;
 		break;
-	case ICMODE_DECOMPRESS:
 	case ICMODE_FASTDECOMPRESS:
+	case ICMODE_DECOMPRESS:
 		querymsg = ICM_DECOMPRESS_QUERY;
 		break;
 	case ICMODE_DRAW:
 		querymsg = ICM_DRAW_QUERY;
 		break;
 	default:
-		FIXME("Unknown mode (%d)\n",wMode);
+		WARN("Unknown mode (%d)\n",wMode);
 		return 0;
 	}
 
@@ -181,24 +270,60 @@ ICLocate(
 			return hic;
 		ICClose(hic);
 	}
-	type[4]='\0';memcpy(type,&fccType,4);
-	handler[4]='\0';memcpy(handler,&fccHandler,4);
+
+	type[4]='.';memcpy(type,&fccType,4);
+	handler[4]='.';memcpy(handler,&fccHandler,4);
+
+	/* Now try each driver in turn. 32 bit codecs only. */
+	/* FIXME: Move this to an init routine? */
+	
+	pszBuffer = (LPSTR)HeapAlloc(GetProcessHeap(),0,1024);
+	if (GetPrivateProfileSectionA("drivers32",pszBuffer,1024,"system.ini")) {
+		char* s = pszBuffer;
+		while (*s) {
+			if (!lstrncmpiA(type,s,5)) {
+				char *s2 = s;
+				while (*s2 != '\0' && *s2 != '.') s2++;
+				if (*s2) {
+					HIC h;
+
+					*s2++ = '\0';
+					h = ICOpen(fccType,*(DWORD*)s2,wMode);
+					if (h) {
+						if (!ICSendMessage(h,querymsg,(DWORD)lpbiIn,(DWORD)lpbiOut))
+							return h;
+						ICClose(h);
+					}
+				}
+			}
+			s += lstrlenA(s) + 1;
+		}
+	}
+	HeapFree(GetProcessHeap(),0,pszBuffer);
+	
 	if (fccType==streamtypeVIDEO) {
 		hic = ICLocate(ICTYPE_VIDEO,fccHandler,lpbiIn,lpbiOut,wMode);
 		if (hic)
 			return hic;
 	}
-	FIXME("(%s,%s,%p,%p,0x%04x),unhandled!\n",type,handler,lpbiIn,lpbiOut,wMode);
+
+	type[4] = handler[4] = '\0';
+	FIXME("(%.4s,%.4s,%p,%p,0x%04x),unhandled!\n",type,handler,lpbiIn,lpbiOut,wMode);
 	return 0;
 }
 
+HIC16 VFWAPI ICLocate16(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn,
+						LPBITMAPINFOHEADER lpbiOut, WORD wFlags) {
+	return (HIC16)ICLocate(fccType, fccHandler, lpbiIn, lpbiOut, wFlags);
+}
+
 /***********************************************************************
  *		ICGetDisplayFormat			[MSVFW.29]
  */
 HIC VFWAPI ICGetDisplayFormat(
 	HIC hic,LPBITMAPINFOHEADER lpbiIn,LPBITMAPINFOHEADER lpbiOut,
-	INT depth,INT dx,INT dy
-) {
+	INT depth,INT dx,INT dy)
+{
 	HIC	tmphic = hic; 
 	LRESULT	lres;
 
@@ -214,7 +339,7 @@ HIC VFWAPI ICGetDisplayFormat(
 	lres = ICDecompressQuery(tmphic,lpbiIn,NULL);
 	if (lres)
 		goto errout; /* no, sorry */
-	ICDecompressGetFormat(hic,lpbiIn,lpbiOut);
+	ICDecompressGetFormat(tmphic,lpbiIn,lpbiOut);
 	*lpbiOut=*lpbiIn;
 	lpbiOut->biCompression = 0;
 	lpbiOut->biSize = sizeof(*lpbiOut);
@@ -226,18 +351,25 @@ HIC VFWAPI ICGetDisplayFormat(
 		ReleaseDC(0,hdc);
 		if (depth==15)	depth = 16;
 		if (depth<8)	depth =  8;
-		/* more constraints and tests */
 	}
 	if (lpbiIn->biBitCount == 8)
 		depth = 8;
 	
-	return hic;
+	TRACE("=> 0x%08lx\n",(DWORD)tmphic);
+	return tmphic;
 errout:
 	if (hic!=tmphic)
 		ICClose(tmphic);
+
+	TRACE("=> 0\n");
 	return 0;
 }
 
+HIC16 VFWAPI ICGetDisplayFormat16(HIC16 hic, LPBITMAPINFOHEADER lpbiIn,
+								  LPBITMAPINFOHEADER lpbiOut, INT16 depth, INT16 dx, INT16 dy) {
+	return (HIC16)ICGetDisplayFormat(hic,lpbiIn,lpbiOut,depth,dx,dy);
+}
+
 /***********************************************************************
  *		ICCompress			[MSVFW.23]
  */
@@ -246,10 +378,12 @@ ICCompress(
 	HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiOutput,LPVOID lpData,
 	LPBITMAPINFOHEADER lpbiInput,LPVOID lpBits,LPDWORD lpckid,
 	LPDWORD lpdwFlags,LONG lFrameNum,DWORD dwFrameSize,DWORD dwQuality,
-	LPBITMAPINFOHEADER lpbiPrev,LPVOID lpPrev
-) {
+	LPBITMAPINFOHEADER lpbiPrev,LPVOID lpPrev)
+{
 	ICCOMPRESS	iccmp;
 
+	TRACE("(0x%08lx,%ld,%p,%p,%p,%p,...)\n",(DWORD)hic,dwFlags,lpbiOutput,lpData,lpbiInput,lpBits);
+
 	iccmp.dwFlags		= dwFlags;
 
 	iccmp.lpbiOutput	= lpbiOutput;
@@ -264,15 +398,50 @@ ICCompress(
 	iccmp.dwQuality		= dwQuality;
 	iccmp.lpbiPrev		= lpbiPrev;
 	iccmp.lpPrev		= lpPrev;
-	return ICSendMessage(hic,ICM_COMPRESS,(LPARAM)&iccmp,sizeof(iccmp));
+	return ICSendMessage(hic,ICM_COMPRESS,(DWORD)&iccmp,sizeof(iccmp));
+}
+
+DWORD VFWAPIV ICCompress16(HIC16 hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiOutput, LPVOID lpData,
+						   LPBITMAPINFOHEADER lpbiInput, LPVOID lpBits, LPDWORD lpckid,
+						   LPDWORD lpdwFlags, LONG lFrameNum, DWORD dwFrameSize, DWORD dwQuality,
+						   LPBITMAPINFOHEADER lpbiPrev, LPVOID lpPrev) {
+
+	DWORD ret;
+	ICCOMPRESS *iccmp = SEGPTR_NEW(ICCOMPRESS);
+
+	TRACE("(0x%08lx,%ld,%p,%p,%p,%p,...)\n",(DWORD)hic,dwFlags,lpbiOutput,lpData,lpbiInput,lpBits);
+
+	iccmp->dwFlags		= dwFlags;
+
+	iccmp->lpbiOutput	= lpbiOutput;
+	iccmp->lpOutput		= lpData;
+	iccmp->lpbiInput		= lpbiInput;
+	iccmp->lpInput		= lpBits;
+
+	iccmp->lpckid		= lpckid;
+	iccmp->lpdwFlags		= lpdwFlags;
+	iccmp->lFrameNum		= lFrameNum;
+	iccmp->dwFrameSize	= dwFrameSize;
+	iccmp->dwQuality		= dwQuality;
+	iccmp->lpbiPrev		= lpbiPrev;
+	iccmp->lpPrev		= lpPrev;
+	ret = ICSendMessage16(hic,ICM_COMPRESS,(DWORD)SEGPTR_GET(iccmp),sizeof(ICCOMPRESS));
+	SEGPTR_FREE(iccmp);
+	return ret;
 }
 
 /***********************************************************************
  *		ICDecompress			[MSVFW.26]
  */
-DWORD VFWAPIV 
-ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,LPVOID lpData,LPBITMAPINFOHEADER  lpbi,LPVOID lpBits) {
+DWORD VFWAPIV  ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,
+				LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits)
+{
 	ICDECOMPRESS	icd;
+	DWORD ret;
+
+	TRACE("(0x%08lx,%ld,%p,%p,%p,%p)\n",(DWORD)hic,dwFlags,lpbiFormat,lpData,lpbi,lpBits);
+
+	TRACE("lpBits[0] == %ld\n",((LPDWORD)lpBits)[0]);
 
 	icd.dwFlags	= dwFlags;
 	icd.lpbiInput	= lpbiFormat;
@@ -281,74 +450,455 @@ ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,LPVOID lpData,L
 	icd.lpbiOutput	= lpbi;
 	icd.lpOutput	= lpBits;
 	icd.ckid	= 0;
-	return ICSendMessage(hic,ICM_DECOMPRESS,(LPARAM)&icd,sizeof(icd));
+	ret = ICSendMessage(hic,ICM_DECOMPRESS,(DWORD)&icd,sizeof(ICDECOMPRESS));
+
+	TRACE("lpBits[0] == %ld\n",((LPDWORD)lpBits)[0]);
+
+	TRACE("-> %ld\n",ret);
+
+	return ret;
 }
 
-/***********************************************************************
- *		ICSendMessage			[MSVFW.40]
- */
-LRESULT VFWAPI
-ICSendMessage(HIC hic,UINT msg,DWORD lParam1,DWORD lParam2) {
+DWORD VFWAPIV ICDecompress16(HIC16 hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiFormat,
+							 LPVOID lpData, LPBITMAPINFOHEADER lpbi, LPVOID lpBits) {
+
+	ICDECOMPRESS *icd = SEGPTR_NEW(ICDECOMPRESS);
+	DWORD ret;
+	
+	TRACE("(0x%08lx,%ld,%p,%p,%p,%p)\n",(DWORD)hic,dwFlags,lpbiFormat,lpData,lpbi,lpBits);
+
+	icd->dwFlags = dwFlags;
+	icd->lpbiInput = lpbiFormat;
+	icd->lpInput = lpData;
+	icd->lpbiOutput = lpbi;
+	icd->lpOutput = lpBits;
+	icd->ckid = 0;
+
+	ret = ICSendMessage16(hic,ICM_DECOMPRESS,(DWORD)SEGPTR_GET(icd),sizeof(ICDECOMPRESS));
+
+	SEGPTR_FREE(icd);
+	return ret;
+}
+
+#define COPY(x,y) (##x##->##y = ##x##16->##y);
+#define COPYPTR(x,y) (##x##->##y = PTR_SEG_TO_LIN(##x##16->##y));
+
+LPVOID MSVIDEO_MapICDEX16To32(LPDWORD lParam) {
+	LPVOID ret;
+
+	ICDECOMPRESSEX *icdx = HeapAlloc(GetProcessHeap(),0,sizeof(ICDECOMPRESSEX));
+	ICDECOMPRESSEX16 *icdx16 = (ICDECOMPRESSEX16*)PTR_SEG_TO_LIN(*lParam);
+	ret = icdx16;
+	
+	COPY(icdx,dwFlags);
+	COPYPTR(icdx,lpbiSrc);
+	COPYPTR(icdx,lpSrc);
+	COPYPTR(icdx,lpbiDst);
+	COPYPTR(icdx,lpDst);
+	COPY(icdx,xDst);
+	COPY(icdx,yDst);
+	COPY(icdx,dxDst);
+	COPY(icdx,dyDst);
+	COPY(icdx,xSrc);
+	COPY(icdx,ySrc);
+	COPY(icdx,dxSrc);
+	COPY(icdx,dySrc);
+	
+	*lParam = (DWORD)(icdx);
+	return ret;
+}
+
+LPVOID MSVIDEO_MapMsg16To32(UINT msg, LPDWORD lParam1, LPDWORD lParam2) {
+	LPVOID ret = 0;
+	
+	TRACE("Mapping %d\n",msg);
+
+	switch (msg) {
+	case DRV_LOAD:
+	case DRV_ENABLE:
+	case DRV_CLOSE:
+	case DRV_DISABLE:
+	case DRV_FREE:
+	case ICM_ABOUT:
+	case ICM_CONFIGURE:
+	case ICM_COMPRESS_END:
+	case ICM_DECOMPRESS_END:
+	case ICM_DECOMPRESSEX_END:
+	case ICM_SETQUALITY:
+		break;
+	case DRV_OPEN:
+	case ICM_GETDEFAULTQUALITY:
+	case ICM_GETQUALITY:
+		*lParam1 = (DWORD)PTR_SEG_TO_LIN(*lParam1);
+		break;
+	case ICM_GETINFO:
+		{
+			ICINFO *ici = HeapAlloc(GetProcessHeap(),0,sizeof(ICINFO));
+			ICINFO16 *ici16;
+
+			ici16 = (ICINFO16*)PTR_SEG_TO_LIN(*lParam1);
+			ret = ici16;
+
+			ici->dwSize = sizeof(ICINFO);
+			COPY(ici,fccType);
+			COPY(ici,fccHandler);
+			COPY(ici,dwFlags);
+			COPY(ici,dwVersion);
+			COPY(ici,dwVersionICM);
+			lstrcpynAtoW(ici->szName,ici16->szName,16);
+			lstrcpynAtoW(ici->szDescription,ici16->szDescription,128);
+			lstrcpynAtoW(ici->szDriver,ici16->szDriver,128);
+
+			*lParam1 = (DWORD)(ici);
+			*lParam2 = sizeof(ICINFO);
+		}
+		break;
+	case ICM_COMPRESS:
+		{
+			ICCOMPRESS *icc = HeapAlloc(GetProcessHeap(),0,sizeof(ICCOMPRESS));
+			ICCOMPRESS *icc16;
+
+			icc16 = (ICCOMPRESS*)PTR_SEG_TO_LIN(*lParam1);
+			ret = icc16;
+
+			COPY(icc,dwFlags);
+			COPYPTR(icc,lpbiOutput);
+			COPYPTR(icc,lpOutput);
+			COPYPTR(icc,lpbiInput);
+			COPYPTR(icc,lpInput);
+			COPYPTR(icc,lpckid);
+			COPYPTR(icc,lpdwFlags);
+			COPY(icc,lFrameNum);
+			COPY(icc,dwFrameSize);
+			COPY(icc,dwQuality);
+			COPYPTR(icc,lpbiPrev);
+			COPYPTR(icc,lpPrev);
+			
+			*lParam1 = (DWORD)(icc);
+			*lParam2 = sizeof(ICCOMPRESS);
+		}
+		break;
+	case ICM_DECOMPRESS:
+		{
+			ICDECOMPRESS *icd = HeapAlloc(GetProcessHeap(),0,sizeof(ICDECOMPRESS));
+			ICDECOMPRESS *icd16; /* Same structure except for the pointers */
+			
+			icd16 = (ICDECOMPRESS*)PTR_SEG_TO_LIN(*lParam1);
+			ret = icd16;
+			
+			COPY(icd,dwFlags);
+			COPYPTR(icd,lpbiInput);
+			COPYPTR(icd,lpInput);
+			COPYPTR(icd,lpbiOutput);
+			COPYPTR(icd,lpOutput);
+			COPY(icd,ckid);
+			
+			*lParam1 = (DWORD)(icd);
+			*lParam2 = sizeof(ICDECOMPRESS);
+		}
+		break;
+	case ICM_COMPRESS_BEGIN:
+	case ICM_COMPRESS_GET_FORMAT:
+	case ICM_COMPRESS_GET_SIZE:
+	case ICM_COMPRESS_QUERY:
+	case ICM_DECOMPRESS_GET_FORMAT:
+	case ICM_DECOMPRESS_QUERY:
+	case ICM_DECOMPRESS_BEGIN:
+	case ICM_DECOMPRESS_SET_PALETTE:
+	case ICM_DECOMPRESS_GET_PALETTE:
+		*lParam1 = (DWORD)PTR_SEG_TO_LIN(*lParam1);
+		*lParam2 = (DWORD)PTR_SEG_TO_LIN(*lParam2);
+		break;
+	case ICM_DECOMPRESSEX_QUERY:
+		if ((*lParam2 != sizeof(ICDECOMPRESSEX16)) && (*lParam2 != 0))
+			WARN("*lParam2 has unknown value %p\n",(ICDECOMPRESSEX16*)*lParam2);
+		/* FIXME: *lParm2 is meant to be 0 or an ICDECOMPRESSEX16*, but is sizeof(ICDECOMRPESSEX16)
+		 * This is because of ICMessage(). Special case it?
+		 {
+		 LPVOID* addr = HeapAlloc(GetProcessHeap(),0,2*sizeof(LPVOID));
+		 addr[0] = MSVIDEO_MapICDEX16To32(lParam1);
+		 if (*lParam2)
+		 addr[1] = MSVIDEO_MapICDEX16To32(lParam2);
+		 else
+		 addr[1] = 0;
+		 
+		 ret = addr;
+		 }
+		 break;*/
+	case ICM_DECOMPRESSEX_BEGIN:
+	case ICM_DECOMPRESSEX:
+		ret = MSVIDEO_MapICDEX16To32(lParam1);
+		*lParam2 = sizeof(ICDECOMPRESSEX);
+		break;
+	case ICM_DRAW_BEGIN:
+		{
+			ICDRAWBEGIN *icdb = HeapAlloc(GetProcessHeap(),0,sizeof(ICDRAWBEGIN));
+			ICDRAWBEGIN16 *icdb16 = (ICDRAWBEGIN16*)PTR_SEG_TO_LIN(*lParam1);
+			ret = icdb16;
+
+			COPY(icdb,dwFlags);
+			COPY(icdb,hpal);
+			COPY(icdb,hwnd);
+			COPY(icdb,hdc);
+			COPY(icdb,xDst);
+			COPY(icdb,yDst);
+			COPY(icdb,dxDst);
+			COPY(icdb,dyDst);
+			COPYPTR(icdb,lpbi);
+			COPY(icdb,xSrc);
+			COPY(icdb,ySrc);
+			COPY(icdb,dxSrc);
+			COPY(icdb,dySrc);
+			COPY(icdb,dwRate);
+			COPY(icdb,dwScale);
+
+			*lParam1 = (DWORD)(icdb);
+			*lParam2 = sizeof(ICDRAWBEGIN);
+		}
+		break;
+	case ICM_DRAW_SUGGESTFORMAT:
+		{
+			ICDRAWSUGGEST *icds = HeapAlloc(GetProcessHeap(),0,sizeof(ICDRAWSUGGEST));
+			ICDRAWSUGGEST16 *icds16 = (ICDRAWSUGGEST16*)PTR_SEG_TO_LIN(*lParam1);
+			
+			ret = icds16;
+
+			COPY(icds,dwFlags);
+			COPYPTR(icds,lpbiIn);
+			COPYPTR(icds,lpbiSuggest);
+			COPY(icds,dxSrc);
+			COPY(icds,dySrc);
+			COPY(icds,dxDst);
+			COPY(icds,dyDst);
+			COPY(icds,hicDecompressor);
+
+			*lParam1 = (DWORD)(icds);
+			*lParam2 = sizeof(ICDRAWSUGGEST);
+		}
+		break;
+	case ICM_DRAW:
+		{
+			ICDRAW *icd = HeapAlloc(GetProcessHeap(),0,sizeof(ICDRAW));
+			ICDRAW *icd16 = (ICDRAW*)PTR_SEG_TO_LIN(*lParam1);
+			ret = icd16;
+
+			COPY(icd,dwFlags);
+			COPYPTR(icd,lpFormat);
+			COPYPTR(icd,lpData);
+			COPY(icd,cbData);
+			COPY(icd,lTime);
+
+			*lParam1 = (DWORD)(icd);
+			*lParam2 = sizeof(ICDRAW);
+		}
+		break;
+	default:
+		FIXME("%d is not yet handled. Expect a crash.\n",msg);
+	}
+	return ret;
+}
+
+#undef COPY
+#undef COPYPTR
+
+void MSVIDEO_UnmapMsg16To32(UINT msg, LPVOID data16, LPDWORD lParam1, LPDWORD lParam2) {
+	TRACE("Unmapping %d\n",msg);
+
+#define UNCOPY(x,y) (##x##16->##y = ##x##->##y);
+
+	switch (msg) {
+	case ICM_GETINFO:
+		{
+			ICINFO *ici = (ICINFO*)(*lParam1);
+			ICINFO16 *ici16 = (ICINFO16*)data16;
+
+			UNCOPY(ici,fccType);
+			UNCOPY(ici,fccHandler);
+			UNCOPY(ici,dwFlags);
+			UNCOPY(ici,dwVersion);
+			UNCOPY(ici,dwVersionICM);
+			lstrcpynWtoA(ici16->szName,ici->szName,16);
+			lstrcpynWtoA(ici16->szDescription,ici->szDescription,128);
+			/* This just gives garbage for some reason - BB
+			   lstrcpynWtoA(ici16->szDriver,ici->szDriver,128);*/
+
+			HeapFree(GetProcessHeap(),0,ici);
+		}
+		break;
+	case ICM_DECOMPRESS_QUERY:
+		/*{
+		  LPVOID* x = data16;
+		  HeapFree(GetProcessHeap(),0,x[0]);
+		  if (x[1])
+		  HeapFree(GetProcessHeap(),0,x[1]);
+		  }
+		  break;*/
+	case ICM_COMPRESS:
+	case ICM_DECOMPRESS:
+	case ICM_DECOMPRESSEX_QUERY:
+	case ICM_DECOMPRESSEX_BEGIN:
+	case ICM_DECOMPRESSEX:
+	case ICM_DRAW_BEGIN:
+	case ICM_DRAW_SUGGESTFORMAT:
+	case ICM_DRAW:
+		HeapFree(GetProcessHeap(),0,data16);
+		break;
+	default:
+		ERR("Unmapping unmapped msg %d\n",msg);
+	}
+#undef UNCOPY		
+}
+
+LRESULT MSVIDEO_SendMessage(HIC hic,UINT msg,DWORD lParam1,DWORD lParam2, BOOL bFrom32) {
 	LRESULT		ret;
-	WINE_HIC	*whic = (WINE_HIC*)hic;
+	WINE_HIC	*whic = GlobalLock16(hic);
+	LPVOID data16 = 0;
+	BOOL bDrv32;
 
-#define XX(x) case x: TRACE("(0x%08lx,"#x",0x%08lx,0x%08lx)\n",(DWORD)hic,lParam1,lParam2);break;
+#define XX(x) case x: TRACE("(0x%08lx,"#x",0x%08lx,0x%08lx,%d)\n",(DWORD)hic,lParam1,lParam2,bFrom32?32:16);break;
 
 	switch (msg) {
-	XX(ICM_ABOUT)
-	XX(ICM_GETINFO)
-	XX(ICM_COMPRESS_FRAMES_INFO)
-	XX(ICM_COMPRESS_GET_FORMAT)
-	XX(ICM_COMPRESS_GET_SIZE)
-	XX(ICM_COMPRESS_QUERY)
-	XX(ICM_COMPRESS_BEGIN)
-	XX(ICM_COMPRESS)
-	XX(ICM_COMPRESS_END)
-	XX(ICM_DECOMPRESS_GET_FORMAT)
-	XX(ICM_DECOMPRESS_QUERY)
-	XX(ICM_DECOMPRESS_BEGIN)
-	XX(ICM_DECOMPRESS)
-	XX(ICM_DECOMPRESS_END)
-	XX(ICM_DECOMPRESS_SET_PALETTE)
-	XX(ICM_DECOMPRESS_GET_PALETTE)
-	XX(ICM_DRAW_QUERY)
-	XX(ICM_DRAW_BEGIN)
-	XX(ICM_DRAW_GET_PALETTE)
-	XX(ICM_DRAW_START)
-	XX(ICM_DRAW_STOP)
-	XX(ICM_DRAW_END)
-	XX(ICM_DRAW_GETTIME)
-	XX(ICM_DRAW)
-	XX(ICM_DRAW_WINDOW)
-	XX(ICM_DRAW_SETTIME)
-	XX(ICM_DRAW_REALIZE)
-	XX(ICM_DRAW_FLUSH)
-	XX(ICM_DRAW_RENDERBUFFER)
-	XX(ICM_DRAW_START_PLAY)
-	XX(ICM_DRAW_STOP_PLAY)
-	XX(ICM_DRAW_SUGGESTFORMAT)
-	XX(ICM_DRAW_CHANGEPALETTE)
-	XX(ICM_GETBUFFERSWANTED)
-	XX(ICM_GETDEFAULTKEYFRAMERATE)
-	XX(ICM_DECOMPRESSEX_BEGIN)
-	XX(ICM_DECOMPRESSEX_QUERY)
-	XX(ICM_DECOMPRESSEX)
-	XX(ICM_DECOMPRESSEX_END)
-	XX(ICM_SET_STATUS_PROC)
+		/* DRV_* */
+		XX(DRV_LOAD);
+		XX(DRV_ENABLE);
+		XX(DRV_OPEN);
+		XX(DRV_CLOSE);
+		XX(DRV_DISABLE);
+		XX(DRV_FREE);
+		/* ICM_RESERVED+X */
+		XX(ICM_ABOUT);
+		XX(ICM_CONFIGURE);
+		XX(ICM_GET);
+		XX(ICM_GETINFO);
+		XX(ICM_GETDEFAULTQUALITY);
+		XX(ICM_GETQUALITY);
+		XX(ICM_GETSTATE);
+		XX(ICM_SETQUALITY);
+		XX(ICM_SET);
+		XX(ICM_SETSTATE);
+		/* ICM_USER+X */
+		XX(ICM_COMPRESS_FRAMES_INFO);
+		XX(ICM_COMPRESS_GET_FORMAT);
+		XX(ICM_COMPRESS_GET_SIZE);
+		XX(ICM_COMPRESS_QUERY);
+		XX(ICM_COMPRESS_BEGIN);
+		XX(ICM_COMPRESS);
+		XX(ICM_COMPRESS_END);
+		XX(ICM_DECOMPRESS_GET_FORMAT);
+		XX(ICM_DECOMPRESS_QUERY);
+		XX(ICM_DECOMPRESS_BEGIN);
+		XX(ICM_DECOMPRESS);
+		XX(ICM_DECOMPRESS_END);
+		XX(ICM_DECOMPRESS_SET_PALETTE);
+		XX(ICM_DECOMPRESS_GET_PALETTE);
+		XX(ICM_DRAW_QUERY);
+		XX(ICM_DRAW_BEGIN);
+		XX(ICM_DRAW_GET_PALETTE);
+		XX(ICM_DRAW_START);
+		XX(ICM_DRAW_STOP);
+		XX(ICM_DRAW_END);
+		XX(ICM_DRAW_GETTIME);
+		XX(ICM_DRAW);
+		XX(ICM_DRAW_WINDOW);
+		XX(ICM_DRAW_SETTIME);
+		XX(ICM_DRAW_REALIZE);
+		XX(ICM_DRAW_FLUSH);
+		XX(ICM_DRAW_RENDERBUFFER);
+		XX(ICM_DRAW_START_PLAY);
+		XX(ICM_DRAW_STOP_PLAY);
+		XX(ICM_DRAW_SUGGESTFORMAT);
+		XX(ICM_DRAW_CHANGEPALETTE);
+		XX(ICM_GETBUFFERSWANTED);
+		XX(ICM_GETDEFAULTKEYFRAMERATE);
+		XX(ICM_DECOMPRESSEX_BEGIN);
+		XX(ICM_DECOMPRESSEX_QUERY);
+		XX(ICM_DECOMPRESSEX);
+		XX(ICM_DECOMPRESSEX_END);
+		XX(ICM_SET_STATUS_PROC);
 	default:
-		FIXME("(0x%08lx,0x%08lx,0x%08lx,0x%08lx)\n",(DWORD)hic,(DWORD)msg,lParam1,lParam2);
+		FIXME("(0x%08lx,0x%08lx,0x%08lx,0x%08lx,%i) unknown message\n",(DWORD)hic,(DWORD)msg,lParam1,lParam2,bFrom32?32:16);
+	}
+
+#undef XX
+
+	if (whic->driverproc) { /* IC is a function */
+		bDrv32 = whic->private;
+	} else {
+		bDrv32 = ((GetDriverFlags(whic->hdrv) & (WINE_GDF_EXIST|WINE_GDF_16BIT)) == WINE_GDF_EXIST);
 	}
-#if 0
+
+	if (!bFrom32) {
+		if (bDrv32)
+			data16 = MSVIDEO_MapMsg16To32(msg,&lParam1,&lParam2);
+	} else {
+		if (!bDrv32) {
+			ERR("Can't do 32->16 mappings\n");
+			ret = -1;
+			goto out;
+		}
+	}
+	
 	if (whic->driverproc) {
-		FIXME("(0x%08lx,0x%08lx,0x%08lx,0x%08lx), calling %p\n",(DWORD)hic,(DWORD)msg,lParam1,lParam2,whic->driverproc);
-		ret = whic->driverproc(whic->hdrv,1,msg,lParam1,lParam2);
-	} else
-#endif
+		if (bDrv32) {
+			ret = whic->driverproc(whic->hdrv,hic,msg,lParam1,lParam2);
+		} else {
+			ret = MSVIDEO_CallTo16_long_lwwll((FARPROC16)whic->driverproc,whic->hdrv,hic,msg,lParam1,lParam2);
+		}
+	} else {
 		ret = SendDriverMessage(whic->hdrv,msg,lParam1,lParam2);
+	}
+
+	if (data16)
+		MSVIDEO_UnmapMsg16To32(msg,data16,&lParam1,&lParam2);
+ 
+ out:
+	GlobalUnlock16(hic);
+	
 	TRACE("	-> 0x%08lx\n",ret);
 	return ret;
 }
 
+/***********************************************************************
+ *		ICSendMessage			[MSVFW.40]
+ */
+LRESULT VFWAPI ICSendMessage(HIC hic, UINT msg, DWORD lParam1, DWORD lParam2) {
+	return MSVIDEO_SendMessage(hic,msg,lParam1,lParam2,TRUE);
+}
+
+LRESULT VFWAPI ICSendMessage16(HIC16 hic, UINT16 msg, DWORD lParam1, DWORD lParam2) {
+	return MSVIDEO_SendMessage(hic,msg,lParam1,lParam2,FALSE);
+}
+
+LRESULT VFWAPIV ICMessage16(void) {
+	HIC16 hic;
+	UINT16 msg;
+	UINT16 cb;
+	LPWORD lpData;
+	LRESULT ret;
+	UINT16 i;
+
+	VA_LIST16 valist;
+	
+	VA_START16(valist);
+	hic = VA_ARG16(valist, HIC16);
+	msg = VA_ARG16(valist, UINT16);
+	cb  = VA_ARG16(valist, UINT16);
+
+	lpData = SEGPTR_ALLOC(cb);
+
+	TRACE("0x%08lx, %u, %u, ...)\n",(DWORD)hic,msg,cb);
+
+	for(i=0;i<cb/sizeof(WORD);i++) {
+		lpData[i] = VA_ARG16(valist, WORD);
+	}
+		
+	VA_END16(valist);
+	ret = ICSendMessage16(hic, msg, (DWORD)(SEGPTR_GET(lpData)), (DWORD)cb);
+
+	SEGPTR_FREE(lpData);
+	return ret;
+}
+
 /***********************************************************************
  *		ICDrawBegin		[MSVFW.28]
  */
@@ -369,8 +919,13 @@ DWORD	VFWAPIV	ICDrawBegin(
         INT			dySrc,
         DWORD			dwRate,	/* frames/second = (dwRate/dwScale) */
         DWORD			dwScale) {
+	
 	ICDRAWBEGIN	icdb;
 
+	TRACE("(0x%08lx,%ld,0x%08lx,0x%08lx,0x%08lx,%u,%u,%u,%u,%p,%u,%u,%u,%u,%ld,%ld)\n",
+		  (DWORD)hic, dwFlags, (DWORD)hpal, (DWORD)hwnd, (DWORD)hdc, xDst, yDst, dxDst, dyDst,
+		  lpbi, xSrc, ySrc, dxSrc, dySrc, dwRate, dwScale);
+
 	icdb.dwFlags = dwFlags;
 	icdb.hpal = hpal;
 	icdb.hwnd = hwnd;
@@ -386,97 +941,117 @@ DWORD	VFWAPIV	ICDrawBegin(
 	icdb.dySrc = dySrc;
 	icdb.dwRate = dwRate;
 	icdb.dwScale = dwScale;
-	return ICSendMessage(hic,ICM_DRAW_BEGIN,(LPARAM)&icdb,sizeof(icdb));
+	return ICSendMessage(hic,ICM_DRAW_BEGIN,(DWORD)&icdb,sizeof(icdb));
+}
+
+DWORD VFWAPIV ICDrawBegin16(
+							HIC16			hic,
+							DWORD			dwFlags,/* flags */
+							HPALETTE16		hpal,	/* palette to draw with */
+							HWND16			hwnd,	/* window to draw to */
+							HDC16			hdc,	/* HDC to draw to */
+							INT16			xDst,	/* destination rectangle */
+							INT16			yDst,
+							INT16			dxDst,
+							INT16			dyDst,
+						 	LPBITMAPINFOHEADER /*SEGPTR*/ lpbi,	/* format of frame to draw */
+							INT16			xSrc,	/* source rectangle */
+							INT16			ySrc,
+							INT16			dxSrc,
+							INT16			dySrc,
+							DWORD			dwRate,	/* frames/second = (dwRate/dwScale) */
+							DWORD			dwScale) {
+
+	DWORD ret;
+	ICDRAWBEGIN16* icdb = SEGPTR_NEW(ICDRAWBEGIN16); /* SEGPTR for mapper to deal with */
+
+	TRACE("(0x%08lx,%ld,0x%08lx,0x%08lx,0x%08lx,%u,%u,%u,%u,%p,%u,%u,%u,%u,%ld,%ld)\n",
+		  (DWORD)hic, dwFlags, (DWORD)hpal, (DWORD)hwnd, (DWORD)hdc, xDst, yDst, dxDst, dyDst,
+		  lpbi, xSrc, ySrc, dxSrc, dySrc, dwRate, dwScale);
+
+	icdb->dwFlags = dwFlags;
+	icdb->hpal = hpal;
+	icdb->hwnd = hwnd;
+	icdb->hdc = hdc;
+	icdb->xDst = xDst;
+	icdb->yDst = yDst;
+	icdb->dxDst = dxDst;
+	icdb->dyDst = dyDst;
+	icdb->lpbi = lpbi; /* Keep this as SEGPTR for the mapping code to deal with */
+	icdb->xSrc = xSrc;
+	icdb->ySrc = ySrc;
+	icdb->dxSrc = dxSrc;
+	icdb->dySrc = dySrc;
+	icdb->dwRate = dwRate;
+	icdb->dwScale = dwScale;
+	
+	ret = (DWORD)ICSendMessage16(hic,ICM_DRAW_BEGIN,(DWORD)SEGPTR_GET(icdb),sizeof(ICDRAWBEGIN16));
+	SEGPTR_FREE(icdb);
+	return ret;
 }
 
 /***********************************************************************
  *		ICDraw			[MSVFW.27]
  */
-DWORD VFWAPIV ICDraw(
-	HIC hic,DWORD dwFlags,LPVOID lpFormat,LPVOID lpData,DWORD cbData,
-	LONG lTime
-) {
+DWORD VFWAPIV ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime) {
 	ICDRAW	icd;
 
+	TRACE("(0x%09lx,%ld,%p,%p,%ld,%ld)\n",(DWORD)hic,dwFlags,lpFormat,lpData,cbData,lTime);
+
 	icd.dwFlags = dwFlags;
 	icd.lpFormat = lpFormat;
 	icd.lpData = lpData;
 	icd.cbData = cbData;
 	icd.lTime = lTime;
-	return ICSendMessage(hic,ICM_DRAW,(LPARAM)&icd,sizeof(icd));
-}
 
-/***********************************************************************
- *		ICClose			[MSVFW.22]
- */
-LRESULT WINAPI ICClose(HIC hic) {
-	WINE_HIC	*whic = (WINE_HIC*)hic;
-	TRACE("(%d).\n",hic);
-	/* FIXME: correct? */
-	CloseDriver(whic->hdrv,0,0);
-	HeapFree(GetProcessHeap(),0,whic);
-	return 0;
+	return ICSendMessage(hic,ICM_DRAW,(DWORD)&icd,sizeof(icd));
 }
 
-/***********************************************************************
- *		DrawDibOpen		[MSVFW.10]
- */
-HDRAWDIB VFWAPI
-DrawDibOpen( void ) {
-	FIXME("stub!\n");
-	return 0xdead;
-}
+DWORD VFWAPIV ICDraw16(HIC16 hic, DWORD dwFlags, LPVOID /*SEGPTR*/ lpFormat,
+					   LPVOID /*SEGPTR*/ lpData, DWORD cbData, LONG lTime) {
 
-/***********************************************************************
- *		DrawDibClose		[MSVFW.5]
- */
-BOOL VFWAPI
-DrawDibClose( HDRAWDIB hDib ) {
-       FIXME("stub!\n");
-       return TRUE;
-}
+	ICDRAW* icd = SEGPTR_NEW(ICDRAW); /* SEGPTR for mapper to deal with */
 
-/***********************************************************************
- *		DrawDibBegin		[MSVFW.3]
- */
-BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
-                                    HDC      hdc,
-                                    INT      dxDst,
-                                    INT      dyDst,
-                                    LPBITMAPINFOHEADER lpbi,
-                                    INT      dxSrc,
-                                    INT      dySrc,
-                                    UINT     wFlags) {
-	FIXME("(%d,0x%lx,%d,%d,%p,%d,%d,0x%08lx), stub!\n",
-		hdd,(DWORD)hdc,dxDst,dyDst,lpbi,dxSrc,dySrc,(DWORD)wFlags
-	);
-	return TRUE;
-}
+	TRACE("(0x%08lx,0x%08lx,%p,%p,%ld,%ld)\n",(DWORD)hic,dwFlags,lpFormat,lpData,cbData,lTime);
+	icd->dwFlags = dwFlags;
+	icd->lpFormat = lpFormat;
+	icd->lpData = lpData;
+	icd->cbData = cbData;
+	icd->lTime = lTime;
 
+	return ICSendMessage16(hic,ICM_DRAW,(DWORD)SEGPTR_GET(icd),sizeof(ICDRAW));
+}
 
 /***********************************************************************
- *		DrawDibSetPalette	[MSVFW.13]
+ *		ICClose			[MSVFW.22]
  */
-BOOL VFWAPI
-DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal) {
-	FIXME("(%d,%d),stub!\n",hdd,hpal);
-	return TRUE;
+LRESULT WINAPI ICClose(HIC hic) {
+	WINE_HIC *whic = GlobalLock16(hic);
+	TRACE("(0x%08lx)\n",(DWORD)hic);
+	if (whic->driverproc) {
+		ICSendMessage16(hic,DRV_CLOSE,0,0);
+		ICSendMessage16(hic,DRV_DISABLE,0,0);
+		ICSendMessage16(hic,DRV_FREE,0,0);
+	} else {
+		CloseDriver(whic->hdrv,0,0);
 }
 
-/***********************************************************************
- *		DrawDibRealize		[MSVFW.12]
- */
-UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground) {
-	FIXME("(0x%08lx,0x%08lx,%d),stub!\n",(DWORD)hdd,(DWORD)hdc,fBackground);
+	GlobalUnlock16(hic);
+	GlobalFree16(hic);
 	return 0;
 }
 
+LRESULT WINAPI ICClose16(HIC16 hic) {
+	return ICClose(hic);
+}
+
 /***********************************************************************
  *		MCIWndCreateA		[MSVFW.44 & MSVFW.45]
  */
 HWND VFWAPIV MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance,
                       DWORD dwStyle,LPCSTR szFile)
-{	FIXME("%x %x %lx %s\n",hwndParent, hInstance, dwStyle, szFile);
+{
+	FIXME("%x %x %lx %s\n",hwndParent, hInstance, dwStyle, szFile);
 	return 0;
 }
 
@@ -485,6 +1060,7 @@ HWND VFWAPIV MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance,
  */
 HWND VFWAPIV MCIWndCreateW(HWND hwndParent, HINSTANCE hInstance,
                       DWORD dwStyle,LPCWSTR szFile)
-{	FIXME("%x %x %lx %s\n",hwndParent, hInstance, dwStyle, debugstr_w(szFile));
+{
+	FIXME("%x %x %lx %s\n",hwndParent, hInstance, dwStyle, debugstr_w(szFile));
 	return 0;
 }
diff --git a/include/vfw.h b/include/vfw.h
index 1dc9eb69027879995c1d08bab201aa159c654fc3..9ef93d19a10175d85c61dd20ac55bd2c000c1250 100644
--- a/include/vfw.h
+++ b/include/vfw.h
@@ -10,13 +10,9 @@
 #define VFWAPI	WINAPI
 #define VFWAPIV	WINAPIV
 
+typedef HANDLE16 HDRAWDIB16;
 typedef HANDLE HDRAWDIB;
 
-BOOL        VFWAPI DrawDibBegin(HDRAWDIB hdd, HDC hdc, INT dxDest, INT dyDest, LPBITMAPINFOHEADER lpbi, INT dxSrc, INT dySrc, UINT wFlags);
-BOOL        VFWAPI DrawDibClose(HDRAWDIB hdd);
-HDRAWDIB    VFWAPI DrawDibOpen(void);
-UINT        VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground);
-BOOL        VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal);
 HWND        VFWAPIV MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance, DWORD dwStyle, LPCSTR szFile);
 HWND        VFWAPIV MCIWndCreateW(HWND hwndParent, HINSTANCE hInstance, DWORD dwStyle, LPCWSTR szFile);
 #define     MCIWndCreate WINELIB_NAME_AW(MCIWndCreate)
@@ -42,7 +38,7 @@ typedef struct IAVIStream IAVIStream,*PAVISTREAM;
 typedef struct IAVIFile IAVIFile,*PAVIFILE;
 typedef struct IGetFrame IGetFrame,*PGETFRAME;
 
-/* Installable Compressor M? */
+/* Installable Compressor Manager */
 
 DECLARE_HANDLE(HIC);
 
@@ -162,6 +158,11 @@ typedef struct tagWINE_HIC {
 
 /* structs */
 
+/* NOTE: Only the 16 bit structs are packed. Structs that are packed anyway
+ * have not been changed. If a structure is later extended, you may need to create
+ * two versions of it.
+ */
+
 typedef struct {
 	DWORD	dwSize;		/* 00: size */
 	DWORD	fccType;	/* 04: type 'vidc' usually */
@@ -278,6 +279,25 @@ typedef struct {
 					/* 238: */
 } ICINFO;
 
+#include "pshpack1.h"
+
+typedef struct {
+	DWORD dwSize;
+	DWORD fccType;
+	DWORD fccHandler;
+	DWORD dwFlags;
+	DWORD dwVersion;
+	DWORD dwVersionICM;
+	/*
+	 * under Win16, normal chars are used
+	 */
+	CHAR szName[16];
+	CHAR szDescription[128];
+	CHAR szDriver[128];
+} ICINFO16;
+
+#include "poppack.h"
+
 /* ICINFO.dwFlags */
 #define	VIDCF_QUALITY		0x0001  /* supports quality */
 #define	VIDCF_CRUNCH		0x0002  /* supports crunching to a frame size */
@@ -343,8 +363,29 @@ typedef struct {
     INT		dySrc;
 } ICDECOMPRESSEX;
 
-DWORD VFWAPIV ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits);
+#include "pshpack1.h"
+
+typedef struct {
+    DWORD		dwFlags;
+    LPBITMAPINFOHEADER	lpbiSrc;
+    LPVOID		lpSrc;
+    LPBITMAPINFOHEADER	lpbiDst;
+    LPVOID		lpDst;
+
+    INT16  	xDst;       /* destination rectangle */
+    INT16	yDst;
+    INT16  	dxDst;
+    INT16  	dyDst;
+
+    INT16	xSrc;       /* source rectangle */
+    INT16  	ySrc;
+	INT16	dxSrc;
+    INT16  	dySrc;
+} ICDECOMPRESSEX16;
 
+#include "poppack.h"
+
+DWORD VFWAPIV ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits);
 
 #define ICDecompressBegin(hic, lpbiInput, lpbiOutput) 	\
     ICSendMessage(						\
@@ -389,11 +430,37 @@ DWORD VFWAPIV ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,L
 BOOL	VFWAPI	ICInfo(DWORD fccType, DWORD fccHandler, ICINFO * lpicinfo);
 LRESULT	VFWAPI	ICGetInfo(HIC hic,ICINFO *picinfo, DWORD cb);
 HIC	VFWAPI	ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode);
+HIC16 VFWAPI ICOpen16(DWORD fccType, DWORD fccHangler, UINT16 wMode);
 HIC	VFWAPI	ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, FARPROC lpfnHandler);
 
 LRESULT VFWAPI ICClose(HIC hic);
 LRESULT	VFWAPI	ICSendMessage(HIC hic, UINT msg, DWORD dw1, DWORD dw2);
+LRESULT VFWAPI ICSendMessage16(HIC16 hic, UINT16 msg, DWORD dw1, DWORD dw2);
 HIC	VFWAPI ICLocate(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, WORD wFlags);
+HIC16 VFWAPI ICLocate16(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, WORD wFlags);
+
+/* As passed to ICM_DRAW_SUGGESTFORMAT */
+typedef struct {
+	DWORD dwFlags;
+	LPBITMAPINFOHEADER lpbiIn;
+	LPBITMAPINFOHEADER lpbiSuggest;
+	INT dxSrc;
+	INT dySrc;
+	INT dxDst;
+	INT dyDst;
+	HIC hicDecompressor;
+} ICDRAWSUGGEST;
+
+typedef struct {
+	DWORD dwFlags;
+	LPBITMAPINFOHEADER lpbiIn;
+	LPBITMAPINFOHEADER lpbiSuggest;
+	INT16 dxSrc;
+	INT16 dySrc;
+	INT16 dxDst;
+	INT16 dyDst;
+	HIC16 hicDecompressor;
+} ICDRAWSUGGEST16;
 
 DWORD	VFWAPIV	ICDrawBegin(
         HIC			hic,
@@ -414,7 +481,26 @@ DWORD	VFWAPIV	ICDrawBegin(
         DWORD			dwScale
 );
 
-/* as passed to ICM_DRAW_BEGIN (FIXME: correct only for Win32?)  */
+DWORD	VFWAPIV	ICDrawBegin16(
+        HIC16			hic,
+        DWORD			dwFlags,/* flags */
+        HPALETTE16		hpal,	/* palette to draw with */
+        HWND16			hwnd,	/* window to draw to */
+        HDC16			hdc,	/* HDC to draw to */
+		INT16			xDst,	/* destination rectangle */
+        INT16			yDst,
+        INT16			dxDst,
+        INT16			dyDst,
+        LPBITMAPINFOHEADER	lpbi,	/* format of frame to draw */
+        INT16			xSrc,	/* source rectangle */
+        INT16			ySrc,
+        INT16			dxSrc,
+        INT16			dySrc,
+        DWORD			dwRate,	/* frames/second = (dwRate/dwScale) */
+        DWORD			dwScale
+);
+
+/* as passed to ICM_DRAW_BEGIN */
 typedef struct {
 	DWORD		dwFlags;
 	HPALETTE	hpal;
@@ -433,6 +519,28 @@ typedef struct {
 	DWORD		dwScale;
 } ICDRAWBEGIN;
 
+#include "pshpack1.h"
+
+typedef struct {
+	DWORD		dwFlags;
+	HPALETTE16	hpal;
+	HWND16		hwnd;
+	HDC16		hdc;
+	INT16		xDst;
+	INT16		yDst;
+	INT16		dxDst;
+	INT16		dyDst;
+	LPBITMAPINFOHEADER	lpbi;
+	INT16		xSrc;
+	INT16		ySrc;
+	INT16		dxSrc;
+	INT16		dySrc;
+	DWORD		dwRate;
+	DWORD		dwScale;
+} ICDRAWBEGIN16;
+
+#include "poppack.h"
+
 #define ICDRAW_HURRYUP      0x80000000L   /* don't draw just buffer (hurry up!) */
 #define ICDRAW_UPDATE       0x40000000L   /* don't draw just update screen */
 #define ICDRAW_PREROLL      0x20000000L   /* this frame is before real start */
@@ -815,5 +923,55 @@ ICOM_DEFINE(IGetFrame,IUnknown)
 #define AVIERR_USERABORT	MAKE_AVIERR(198)
 #define AVIERR_ERROR		MAKE_AVIERR(199)
 
+/********************************************
+ * DrawDib declarations
+ */
+
+HDRAWDIB VFWAPI DrawDibOpen( void );
+UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground);
+
+BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
+						 HDC hdc,
+						 INT dxDst,
+						 INT dyDst,
+						 LPBITMAPINFOHEADER lpbi,
+						 INT dxSrc,
+						 INT dySrc,
+						 UINT wFlags);
+
+BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd,
+						HDC hdc,
+						INT xDst,
+						INT yDst,
+						INT dxDst,
+						INT dyDst,
+						LPBITMAPINFOHEADER lpbi,
+						LPVOID lpBits,
+						INT xSrc,
+						INT ySrc,
+						INT dxSrc,
+						INT dySrc,
+						UINT wFlags);
+
+/* DrawDibDraw flags */
+
+#define DDF_UPDATE				0x0002
+#define DDF_SAME_HDC			0x0004
+#define DDF_SAME_DRAW			0x0008
+#define DDF_DONTDRAW			0x0010
+#define DDF_ANIMATE				0x0020
+#define DDF_BUFFER				0x0040
+#define DDF_JUSTDRAWIT			0x0080
+#define DDF_FULLSCREEN			0x0100
+#define DDF_BACKGROUNDPAL		0x0200
+#define DDF_NOTKEYFRAME			0x0400
+#define DDF_HURRYUP				0x0800
+#define DDF_HALFTONE			0x1000
+
+BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal);
+HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd);
+
+BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd);
+BOOL VFWAPI DrawDibClose(HDRAWDIB hdd);
 
 #endif /* __WINE_VFW_H */
diff --git a/tools/winapi_check/win16/msvideo.api b/tools/winapi_check/win16/msvideo.api
index b3fa0fc21774376f1897d916f8ec4c37dfc78883..deb26e1d4bf3168d9c86f52f5668656ca0dddfba 100644
--- a/tools/winapi_check/win16/msvideo.api
+++ b/tools/winapi_check/win16/msvideo.api
@@ -1,11 +1,28 @@
 %long
 
 DWORD
+LONG
+LRESULT
 
 %ptr
 
+LPBITMAPINFOHEADER
+LPDWORD
 LPVOID
 
 %word
 
+BOOL16
+INT16
+HDC16
+HDRAWDIB16
+HIC16
+HPALETTE16
+HWND16
+UINT16
 WORD
+
+%segptr
+
+ICINFO16 *
+FARPROC16
diff --git a/tools/winapi_check/win32/msvfw32.api b/tools/winapi_check/win32/msvfw32.api
index 61a54d7669a7925faa91b5e9cbeb073af019ce98..9c129ab3f933b7aafe2a1140add03c49af392a26 100644
--- a/tools/winapi_check/win32/msvfw32.api
+++ b/tools/winapi_check/win32/msvfw32.api
@@ -3,10 +3,10 @@
 BOOL
 DWORD
 HDC
+HDRAWDIB
 HIC
 HINSTANCE
 HPALETTE
-HDRAWDIB
 HWND
 INT
 LONG
diff --git a/windows/driver.c b/windows/driver.c
index 7dcf964e44ebcd336f5c7aa8ca980a54fcf3dd96..c176354b34ff0d8e1fd0f3e2a690374c4a192880 100644
--- a/windows/driver.c
+++ b/windows/driver.c
@@ -220,8 +220,8 @@ static int DRIVER_MapMsg16To32(WORD wMsg, DWORD* lParam1, DWORD* lParam2)
 	}
 	break;
     default:
-	if (wMsg >= 0x800 && wMsg < 0x900) {
-	    /* FIXME: another hack to handle MCI messages... 
+	if ((wMsg >= 0x800 && wMsg < 0x900) || (wMsg >= 0x4000 && wMsg < 0x4100 )) {
+	    /* FIXME: another hack to handle MCI and ICM messages... 
 	     * should find a *NICE* way to integrate DRIVER_ and
 	     * MCI_ mapping/unmapping functions
 	     */
@@ -286,8 +286,8 @@ static int DRIVER_UnMapMsg16To32(WORD wMsg, DWORD lParam1, DWORD lParam2)
 	ret = 0;
 	break;
     default:
-	if (wMsg >= 0x800 && wMsg < 0x900) {
-	    /* FIXME: another hack to handle MCI messages... 
+	if ((wMsg >= 0x800 && wMsg < 0x900) || (wMsg >= 0x4000 && wMsg < 0x4100 )) {
+	    /* FIXME: another hack to handle MCI and ICM messages... 
 	     * should find a *NICE* way to integrate DRIVER_ and
 	     * MCI_ mapping/unmapping functions
 	     */
@@ -396,8 +396,8 @@ static int DRIVER_MapMsg32To16(WORD wMsg, DWORD* lParam1, DWORD* lParam2)
 	}
 	break;
     default:
-	if (wMsg >= 0x800 && wMsg < 0x900) {
-	    /* FIXME: another hack to handle MCI messages... 
+	if ((wMsg >= 0x800 && wMsg < 0x900) || (wMsg >= 0x4000 && wMsg < 0x4100 )) {
+	    /* FIXME: another hack to handle MCI and ICM messages... 
 	     * should find a *NICE* way to integrate DRIVER_ and
 	     * MCI_ mapping/unmapping functions
 	     */
@@ -466,8 +466,8 @@ static int DRIVER_UnMapMsg32To16(WORD wMsg, DWORD lParam1, DWORD lParam2)
 	ret = 0;
 	break;
     default:
-	if (wMsg >= 0x800 && wMsg < 0x900) {
-	    /* FIXME: another hack to handle MCI messages... 
+	if ((wMsg >= 0x800 && wMsg < 0x900) || (wMsg >= 0x4000 && wMsg < 0x4100 )) {
+	    /* FIXME: another hack to handle MCI and ICM messages... 
 	     * should find a *NICE* way to integrate DRIVER_ and
 	     * MCI_ mapping/unmapping functions
 	     */
@@ -617,7 +617,6 @@ static	BOOL	DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam, BOOL bCallFr
 	lpDrv->lpNextItem = lpNewDrv;
 	lpNewDrv->lpPrevItem = lpDrv;
     }
-
     /* Now just open a new instance of a driver on this module */
     if (bCallFrom32) {
 	lpNewDrv->dwDriverID = SendDriverMessage((HDRVR)lpNewDrv, DRV_OPEN, 0L, lParam);