Index: trunk/src/oleaut32/guid.cpp
===================================================================
--- trunk/src/oleaut32/guid.cpp	(revision 631)
+++ trunk/src/oleaut32/guid.cpp	(revision 631)
@@ -0,0 +1,25 @@
+#define INITGUID 1
+/* 
+ * GUIDs for OLEAUT32
+ * 
+ * Copyright 1999 Sander van Leeuwen 
+ *
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+
+/* FIXME: we include all the header files containing GUIDs
+ * so that the corresponding variables get defined. But they
+ * don't even all belong to the same DLL !!!
+ *
+ * Therefore, as the builtin DLL's get teased apart (e.g. for elf-dlls)
+ * then this file will have to be partitioned into per dll files.
+ */
+#include "oleaut32.h"
+#include "wine\obj_oleaut.h"
+#include "wine\obj_olefont.h"
+#include "olectl.h"
+
+/* and now for the one assumed GUID... */
+DEFINE_GUID(GUID_NULL,   0,0,0,0,0,0,0,0,0,0,0);
Index: trunk/src/oleaut32/initterm.cpp
===================================================================
--- trunk/src/oleaut32/initterm.cpp	(revision 631)
+++ trunk/src/oleaut32/initterm.cpp	(revision 631)
@@ -0,0 +1,104 @@
+/* $Id: initterm.cpp,v 1.1 1999-08-22 22:07:36 sandervl Exp $ */
+
+/*
+ * DLL entry point
+ *
+ * Copyright 1998 Sander van Leeuwen
+ * Copyright 1998 Peter Fitzsimmons
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+/*-------------------------------------------------------------*/
+/* INITERM.C -- Source for a custom dynamic link library       */
+/*              initialization and termination (_DLL_InitTerm) */
+/*              function.                                      */
+/*                                                             */
+/* When called to perform initialization, this sample function */
+/* gets storage for an array of integers, and initializes its  */
+/* elements with random integers.  At termination time, it     */
+/* frees the array.  Substitute your own special processing.   */
+/*-------------------------------------------------------------*/
+
+
+/* Include files */
+#define  INCL_DOSMODULEMGR
+#define  INCL_DOSPROCESS
+#include <os2wrap.h>    //Odin32 OS/2 api wrappers
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <odin.h>
+#include <misc.h>       /*PLF Wed  98-03-18 23:18:15*/
+
+extern "C" {
+void CDECL _ctordtorInit( void );
+void CDECL _ctordtorTerm( void );
+}
+
+/*-------------------------------------------------------------------*/
+/* A clean up routine registered with DosExitList must be used if    */
+/* runtime calls are required and the runtime is dynamically linked. */
+/* This will guarantee that this clean up routine is run before the  */
+/* library DLL is terminated.                                        */
+/*-------------------------------------------------------------------*/
+static void APIENTRY cleanup(ULONG reason);
+
+
+/****************************************************************************/
+/* _DLL_InitTerm is the function that gets called by the operating system   */
+/* loader when it loads and frees this DLL for each process that accesses   */
+/* this DLL.  However, it only gets called the first time the DLL is loaded */
+/* and the last time it is freed for a particular process.  The system      */
+/* linkage convention MUST be used because the operating system loader is   */
+/* calling this function.                                                   */
+/****************************************************************************/
+unsigned long SYSTEM _DLL_InitTerm(unsigned long hModule, unsigned long
+                                   ulFlag)
+{
+   size_t i;
+   APIRET rc;
+
+   /*-------------------------------------------------------------------------*/
+   /* If ulFlag is zero then the DLL is being loaded so initialization should */
+   /* be performed.  If ulFlag is 1 then the DLL is being freed so            */
+   /* termination should be performed.                                        */
+   /*-------------------------------------------------------------------------*/
+
+   switch (ulFlag) {
+      case 0 :
+         _ctordtorInit();
+
+         CheckVersionFromHMOD(PE2LX_VERSION, hModule); /*PLF Wed  98-03-18 05:28:48*/
+
+         /*******************************************************************/
+         /* A DosExitList routine must be used to clean up if runtime calls */
+         /* are required and the runtime is dynamically linked.             */
+         /*******************************************************************/
+
+         rc = DosExitList(0x0000F000|EXLST_ADD, cleanup);
+         if(rc)
+                return 0UL;
+
+         break;
+      case 1 :
+         break;
+      default  :
+         return 0UL;
+   }
+
+   /***********************************************************/
+   /* A non-zero value must be returned to indicate success.  */
+   /***********************************************************/
+   return 1UL;
+}
+
+
+static void APIENTRY cleanup(ULONG ulReason)
+{
+   _ctordtorTerm();
+   DosExitList(EXLST_EXIT, cleanup);
+   return ;
+}
Index: trunk/src/oleaut32/makefile
===================================================================
--- trunk/src/oleaut32/makefile	(revision 631)
+++ trunk/src/oleaut32/makefile	(revision 631)
@@ -0,0 +1,58 @@
+#
+# PD-Win32 API 
+#
+#	ole32.dll makefile
+# 
+
+PDWIN32_INCLUDE = ..\..\include
+PDWIN32_LIB = ..\..\lib
+PDWIN32_BIN = ..\..\bin
+
+
+!include $(PDWIN32_INCLUDE)/pdwin32.mk
+
+
+CFLAGS = $(CFLAGS) -I$(PDWIN32_INCLUDE) /DNONAMELESSUNION
+CXXFLAGS = $(CXXFLAGS) -I$(PDWIN32_INCLUDE) /DNONAMELESSUNION
+
+
+TARGET = oleaut32
+
+OBJS =  oleaut32.obj guid.obj \
+	initterm.obj olefont.obj typelib.obj variant.obj ole2disp.obj parsedt.obj safearray.obj
+
+all: $(TARGET).dll $(TARGET).lib
+
+
+$(TARGET).dll: $(OBJS) $(TARGET).def 
+	$(LD) $(LDFLAGS) -Fm -Fe$@ $(OBJS) $(TARGET).def \
+              $(PDWIN32_LIB)\pmwinx.lib \
+              $(PDWIN32_LIB)\advapi32.lib \
+              $(PDWIN32_LIB)\kernel32.lib \
+              $(PDWIN32_LIB)\user32.lib \
+              $(PDWIN32_LIB)\gdi32.lib \
+               $(PDWIN32_LIB)/odincrt.lib OS2386.LIB $(RTLLIB_O)
+	$(CP) $@ $(PDWIN32_BIN)
+
+
+$(TARGET).lib: $(TARGET).dll
+	$(IMPLIB) $(IMPLIBFLAGS) $@ $(TARGET).dll
+	$(CP) $@ $(PDWIN32_LIB)
+
+
+oleaut32.obj:	oleaut32.cpp oleaut32.h
+initterm.obj:	initterm.cpp
+ole2disp.obj:    ole2disp.cpp oleaut32.h
+variant.obj:    variant.cpp parsedt.h
+typelib.obj:    typelib.cpp oleaut32.h
+olefont.obj:    olefont.cpp oleaut32.h
+parsedt.obj:    parsedt.cpp parsedt.h
+safearray.obj:  safearray.cpp oleaut32.h
+guid.obj:       guid.cpp
+
+clean:
+	$(RM) *.obj *.lib *.dll *~ *.map *.pch	
+	$(RM) $(PDWIN32_BIN)\$(TARGET).dll
+	$(RM) $(PDWIN32_LIB)\$(TARGET).lib
+
+
Index: trunk/src/oleaut32/ole2disp.cpp
===================================================================
--- trunk/src/oleaut32/ole2disp.cpp	(revision 631)
+++ trunk/src/oleaut32/ole2disp.cpp	(revision 631)
@@ -0,0 +1,348 @@
+/*
+ *	OLE2DISP library
+ *
+ * 
+ *	Copyright 1995	Martin von Loewis
+ *      Copyright 1999 Sander van Leeuwen  (WINE OS/2 Port 990815)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+#include "oleaut32.h"
+#include <string.h>
+#include "winerror.h"
+#include "ole2.h"
+#include "oleauto.h"
+#include "wine/obj_base.h"
+#include "heap.h"
+#include "ldt.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+/******************************************************************************
+ *		SysAllocString32	[OLEAUT32.2]
+ */
+BSTR WINAPI SysAllocString(LPCOLESTR in)
+{
+    /* Delegate this to the SysAllocStringLen32 method. */
+    return SysAllocStringLen(in, lstrlenW(in));
+}
+
+/******************************************************************************
+ *		SysReAllocString32	[OLEAUT32.3]
+ */
+INT WINAPI SysReAllocString(LPBSTR old,LPCOLESTR in)
+{
+    /*
+     * Sanity check
+     */
+    if (old==NULL) 
+      return 0;
+
+    /*
+     * Make sure we free the old string.
+     */
+    if (*old!=NULL)      
+      SysFreeString(*old);
+
+    /*
+     * Allocate the new string
+     */
+    *old = SysAllocString(in);
+
+     return 1;
+}
+
+
+/******************************************************************************
+ *             SysAllocStringLen32     [OLEAUT32.4]
+ *
+ * In "Inside OLE, second edition" by Kraig Brockshmidt. In the Automation
+ * section, he describes the DWORD value placed before the BSTR data type.
+ * he describes it as a "DWORD count of characters". By experimenting with
+ * a windows application, this count seems to be a DWORD count of bytes in
+ * the string. Meaning that the count is double the number of wide 
+ * characters in the string.
+ */
+BSTR WINAPI SysAllocStringLen(const OLECHAR *in, unsigned int len)
+{
+    DWORD  bufferSize;
+    DWORD* newBuffer;
+    WCHAR* stringBuffer;
+
+    /*
+     * Find the lenth of the buffer passed-in in bytes.
+     */
+    bufferSize = len * sizeof (WCHAR);
+
+    /*
+     * Allocate a new buffer to hold the string.
+     * dont't forget to keep an empty spot at the begining of the
+     * buffer for the character count and an extra character at the
+     * end for the NULL.
+     */
+    newBuffer = (DWORD*)HeapAlloc(GetProcessHeap(),
+                                 0,
+                                 bufferSize + sizeof(WCHAR) + sizeof(DWORD));
+
+    /*
+     * If the memory allocation failed, return a null pointer.
+     */
+    if (newBuffer==0)
+      return 0;
+
+    /*
+     * Copy the length of the string in the placeholder.
+     */
+    *newBuffer = bufferSize;
+
+    /*
+     * Skip the byte count.
+     */
+    newBuffer++;
+
+    /*
+     * Copy the information in the buffer.
+     * Since it is valid to pass a NULL pointer here, we'll initialize the
+     * buffer to nul if it is the case.
+     */
+    if (in != 0)
+      memcpy(newBuffer, in, bufferSize);
+    else
+      memset(newBuffer, 0, bufferSize);
+
+    /*
+     * Make sure that there is a nul character at the end of the
+     * string.
+     */
+    stringBuffer = (WCHAR*)newBuffer;
+    stringBuffer[len] = L'\0';
+
+    return (LPWSTR)stringBuffer;
+}
+
+ 
+/******************************************************************************
+ *             SysReAllocStringLen32   [OLEAUT32.5]
+ */
+int WINAPI SysReAllocStringLen(BSTR* old, const OLECHAR* in, unsigned int len)
+{
+    /*
+     * Sanity check
+     */
+    if (old==NULL) 
+      return 0;
+
+    /*
+     * Make sure we free the old string.
+     */
+    if (*old!=NULL)      
+      SysFreeString(*old);
+
+    /*
+     * Allocate the new string
+     */
+    *old = SysAllocStringLen(in, len);
+
+    return 1;
+}
+
+/******************************************************************************
+ *		SysFreeString32	[OLEAUT32.6]
+ */
+void WINAPI SysFreeString(BSTR in)
+{
+    DWORD* bufferPointer;
+    
+    /* NULL is a valid parameter */
+    if(!in) return;
+
+    /*
+     * We have to be careful when we free a BSTR pointer, it points to
+     * the beginning of the string but it skips the byte count contained
+     * before the string.
+     */
+    bufferPointer = (DWORD*)in;
+
+    bufferPointer--;
+
+    /*
+     * Free the memory from it's "real" origin.
+     */
+    HeapFree(GetProcessHeap(), 0, bufferPointer);
+}
+
+/******************************************************************************
+ *             SysStringLen32  [OLEAUT32.7]
+ *
+ * The Windows documentation states that the length returned by this function
+ * is not necessarely the same as the length returned by the _lstrlenW method.
+ * It is the same number that was passed in as the "len" parameter if the
+ * string was allocated with a SysAllocStringLen method call.
+ */
+int WINAPI SysStringLen(BSTR str)
+{
+    DWORD* bufferPointer;
+
+    /*
+     * The length of the string (in bytes) is contained in a DWORD placed 
+     * just before the BSTR pointer
+     */
+    bufferPointer = (DWORD*)str;
+
+    bufferPointer--;
+
+    return (int)(*bufferPointer/sizeof(WCHAR));
+}
+
+/******************************************************************************
+ *             SysStringByteLen  [OLEAUT32.149]
+ *
+ * The Windows documentation states that the length returned by this function
+ * is not necessarely the same as the length returned by the _lstrlenW method.
+ * It is the same number that was passed in as the "len" parameter if the
+ * string was allocated with a SysAllocStringLen method call.
+ */
+int WINAPI SysStringByteLen(BSTR str)
+{
+  return SysStringLen(str)*sizeof(WCHAR);
+}
+
+/******************************************************************************
+ *		OleTranslateColor	[OLEAUT32.421]
+ *
+ * Converts an OLE_COLOR to a COLORREF.
+ * See the documentation for conversion rules.
+ * pColorRef can be NULL. In that case the user only wants to test the 
+ * conversion.
+ */
+INT WINAPI OleTranslateColor(
+  LONG clr,
+  HPALETTE  hpal,
+  COLORREF* pColorRef)
+{
+  COLORREF colorref;
+  BYTE b = HIBYTE(HIWORD(clr));
+
+  TRACE("(%08lx, %d, %p):stub\n", clr, hpal, pColorRef);
+
+  /*
+   * In case pColorRef is NULL, provide our own to simplify the code.
+   */
+  if (pColorRef == NULL)
+    pColorRef = &colorref;
+
+  switch (b)
+  {
+    case 0x00:
+    {
+      if (hpal != 0)
+        *pColorRef =  PALETTERGB(GetRValue(clr),
+                                 GetGValue(clr),
+                                 GetBValue(clr));
+      else
+        *pColorRef = clr;
+
+      break;
+    }
+
+    case 0x01:
+    {
+      if (hpal != 0)
+      {
+        PALETTEENTRY pe;
+        /*
+         * Validate the palette index.
+         */
+        if (GetPaletteEntries(hpal, LOWORD(clr), 1, &pe) == 0)
+          return E_INVALIDARG;
+      }
+
+      *pColorRef = clr;
+
+      break;
+    }
+
+    case 0x02:
+      *pColorRef = clr;
+      break;
+
+    case 0x80:
+    {
+      int index = LOBYTE(LOWORD(clr));
+
+      /*
+       * Validate GetSysColor index.
+       */
+      if ((index < COLOR_SCROLLBAR) || (index > COLOR_GRADIENTINACTIVECAPTION))
+        return E_INVALIDARG;
+
+      *pColorRef =  GetSysColor(index);
+
+      break;
+    }
+
+    default:
+      return E_INVALIDARG;
+  }
+
+  return S_OK;
+}
+
+/******************************************************************************
+ *             SysAllocStringByteLen     [OLEAUT32.150]
+ *
+ */
+BSTR WINAPI SysAllocStringByteLen(char *in, int len)
+{
+    DWORD* newBuffer;
+    char* stringBuffer;
+
+    /*
+     * Allocate a new buffer to hold the string.
+     * dont't forget to keep an empty spot at the begining of the
+     * buffer for the character count and an extra character at the
+     * end for the NULL.
+     */
+    newBuffer = (DWORD*)HeapAlloc(GetProcessHeap(),
+                                 0,
+                                 len + sizeof(WCHAR) + sizeof(DWORD));
+
+    /*
+     * If the memory allocation failed, return a null pointer.
+     */
+    if (newBuffer==0)
+      return 0;
+
+    /*
+     * Copy the length of the string in the placeholder.
+     */
+    *newBuffer = len;
+
+    /*
+     * Skip the byte count.
+     */
+    newBuffer++;
+
+    /*
+     * Copy the information in the buffer.
+     * Since it is valid to pass a NULL pointer here, we'll initialize the
+     * buffer to nul if it is the case.
+     */
+    if (in != 0)
+      memcpy(newBuffer, in, len);
+
+    /*
+     * Make sure that there is a nul character at the end of the
+     * string.
+     */
+    stringBuffer = (char *)newBuffer;
+    stringBuffer[len] = 0;
+    stringBuffer[len+1] = 0;
+
+    return (LPWSTR)stringBuffer;
+}
+
+
Index: trunk/src/oleaut32/oleaut32.cpp
===================================================================
--- trunk/src/oleaut32/oleaut32.cpp	(revision 631)
+++ trunk/src/oleaut32/oleaut32.cpp	(revision 631)
@@ -0,0 +1,97 @@
+/* 
+ * OLEAUT32 
+ * 
+ * Copyright 1999 Sander van Leeuwen (OS/2 Port 990815)
+ *
+ * Based on Wine code: (ole\compobj.c)
+ * 
+ *	Copyright 1995	Martin von Loewis
+ *	Copyright 1998	Justin Bradford
+ *      Copyright 1999  Francis Beaudet
+ *  	Copyright 1999  Sylvain St-Germain
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ * TODO: WINE_StringFromCLSID should be imported from ole32.dll
+ * TODO: OaBuildVersion has to be changed (as well as GetVersion in kernel32)
+ */
+
+#include "oleaut32.h"
+#ifdef DEBUG
+#define DEBUG_RUNTIME
+#endif
+
+#include <debugdefs.h>
+
+
+/******************************************************************************
+ *		WINE_StringFromCLSID	[Internal]
+ * Converts a GUID into the respective string representation.
+ *
+ * NOTES
+ *
+ * RETURNS
+ *	the string representation and OLESTATUS
+ */
+HRESULT WINE_StringFromCLSID(
+	const CLSID *id,	/* [in] GUID to be converted */
+	LPSTR idstr		/* [out] pointer to buffer to contain converted guid */
+) {
+  static const char *hex = "0123456789ABCDEF";
+  char *s;
+  int	i;
+
+  if (!id)
+	{ dprintf(("called with id=Null\n"));
+	  *idstr = 0x00;
+	  return E_FAIL;
+	}
+	
+  sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
+	  id->Data1, id->Data2, id->Data3,
+	  id->Data4[0], id->Data4[1]);
+  s = &idstr[25];
+
+  /* 6 hex bytes */
+  for (i = 2; i < 8; i++) {
+    *s++ = hex[id->Data4[i]>>4];
+    *s++ = hex[id->Data4[i] & 0xf];
+  }
+
+  *s++ = '}';
+  *s++ = '\0';
+
+  dprintf(("%p->%s\n", id, idstr));
+
+  return OLE_OK;
+}
+
+
+/***********************************************************************
+ *           OaBuildVersion           [OLEAUT32.170]
+ */
+UINT WINAPI OaBuildVersion()
+{
+#if 1
+    return 0x141016;
+#else
+    WINDOWS_VERSION ver = VERSION_GetVersion();
+
+    FIXME("Please report to a.mohr@mailto.de if you get version error messages !\n");
+    switch(VersionData[ver].getVersion32)
+    {
+        case 0x80000a03: /* Win 3.1 */
+		return 0x140fd1; /* from Win32s 1.1e */
+        case 0xc0000004: /* Win 95 */
+	 case 0xc0000a04: /* Win 98: verified same as Win95 */
+		return 0x1e10a9; /* some older version: 0x0a0bd3 */
+        case 0x04213303: /* NT 3.51 */
+		FIXME("NT 3.51 version value unknown !\n");
+		return 0x1e10a9; /* value borrowed from Win95 */
+        case 0x05650004: /* NT 4.0 */
+		return 0x141016;
+	default:
+		return 0x0;
+    }
+#endif
+}
Index: trunk/src/oleaut32/oleaut32.def
===================================================================
--- trunk/src/oleaut32/oleaut32.def	(revision 631)
+++ trunk/src/oleaut32/oleaut32.def	(revision 631)
@@ -0,0 +1,293 @@
+LIBRARY OLEAUT32 INITINSTANCE
+DATA MULTIPLE NONSHARED
+
+EXPORTS
+;DllGetClassObject = _DllGetClassObject@0  @1
+SysAllocString = _SysAllocString@4  @2
+SysReAllocString = _SysReAllocString@8  @3
+SysAllocStringLen = _SysAllocStringLen@8  @4
+SysReAllocStringLen = _SysReAllocStringLen@12  @5
+SysFreeString = _SysFreeString@4  @6
+SysStringLen = _SysStringLen@4  @7
+VariantInit = _VariantInit@4  @8
+VariantClear = _VariantClear@4  @9
+VariantCopy = _VariantCopy@8  @10
+VariantCopyInd = _VariantCopyInd@8  @11
+VariantChangeType = _VariantChangeType@16  @12
+;VariantTimeToDosDateTime = _VariantTimeToDosDateTime@0  @13
+DosDateTimeToVariantTime = _DosDateTimeToVariantTime@12  @14
+SafeArrayCreate = _SafeArrayCreate@12  @15
+SafeArrayDestroy = _SafeArrayDestroy@4  @16
+SafeArrayGetDim = _SafeArrayGetDim@4  @17
+SafeArrayGetElemsize = _SafeArrayGetElemsize@4  @18
+SafeArrayGetUBound = _SafeArrayGetUBound@12  @19
+SafeArrayGetLBound = _SafeArrayGetLBound@12  @20
+SafeArrayLock = _SafeArrayLock@4  @21
+SafeArrayUnlock = _SafeArrayUnlock@4  @22
+SafeArrayAccessData = _SafeArrayAccessData@8  @23
+SafeArrayUnaccessData = _SafeArrayUnaccessData@4  @24
+SafeArrayGetElement = _SafeArrayGetElement@12  @25
+SafeArrayPutElement = _SafeArrayPutElement@12  @26
+SafeArrayCopy = _SafeArrayCopy@8  @27
+;DispGetParam = _DispGetParam@0  @28
+;DispGetIDsOfNames = _DispGetIDsOfNames@0  @29
+;DispInvoke = _DispInvoke@0  @30
+;CreateDispTypeInfo = _CreateDispTypeInfo@0  @31
+;CreateStdDispatch = _CreateStdDispatch@0  @32
+;RegisterActiveObject = _RegisterActiveObject@0  @33
+;RevokeActiveObject = _RevokeActiveObject@0  @34
+;GetActiveObject = _GetActiveObject@0  @35
+SafeArrayAllocDescriptor = _SafeArrayAllocDescriptor@8  @36
+SafeArrayAllocData = _SafeArrayAllocData@4  @37
+SafeArrayDestroyDescriptor = _SafeArrayDestroyDescriptor@4  @38
+SafeArrayDestroyData = _SafeArrayDestroyData@4  @39
+SafeArrayRedim = _SafeArrayRedim@8  @40
+;OACreateTypeLib2 = _OACreateTypeLib2@0  @41
+;VarParseNumFromStr = _VarParseNumFromStr@0  @46
+;VarNumFromParseNum = _VarNumFromParseNum@0  @47
+VarI2FromUI1 = _VarI2FromUI1@8  @48
+VarI2FromI4 = _VarI2FromI4@8  @49
+VarI2FromR4 = _VarI2FromR4@8  @50
+VarI2FromR8 = _VarI2FromR8@12  @51
+VarI2FromCy = _VarI2FromCy@12  @52
+VarI2FromDate = _VarI2FromDate@12  @53
+VarI2FromStr = _VarI2FromStr@16  @54
+;VarI2FromDisp = _VarI2FromDisp@0  @55
+VarI2FromBool = _VarI2FromBool@8  @56
+VarI4FromUI1 = _VarI4FromUI1@8  @58
+VarI4FromI2 = _VarI4FromI2@8  @59
+VarI4FromR4 = _VarI4FromR4@8  @60
+VarI4FromR8 = _VarI4FromR8@12  @61
+VarI4FromCy = _VarI4FromCy@12  @62
+VarI4FromDate = _VarI4FromDate@12  @63
+VarI4FromStr = _VarI4FromStr@16  @64
+;VarI4FromDisp = _VarI4FromDisp@0  @65
+VarI4FromBool = _VarI4FromBool@8  @66
+VarR4FromUI1 = _VarR4FromUI1@8  @68
+VarR4FromI2 = _VarR4FromI2@8  @69
+VarR4FromI4 = _VarR4FromI4@8  @70
+VarR4FromR8 = _VarR4FromR8@12  @71
+VarR4FromCy = _VarR4FromCy@12  @72
+VarR4FromDate = _VarR4FromDate@12  @73
+VarR4FromStr = _VarR4FromStr@16  @74
+;VarR4FromDisp = _VarR4FromDisp@0  @75
+VarR4FromBool = _VarR4FromBool@8  @76
+VarR8FromUI1 = _VarR8FromUI1@8  @78
+VarR8FromI2 = _VarR8FromI2@8  @79
+VarR8FromI4 = _VarR8FromI4@8  @80
+VarR8FromR4 = _VarR8FromR4@8  @81
+VarR8FromCy = _VarR8FromCy@12  @82
+VarR8FromDate = _VarR8FromDate@12  @83
+VarR8FromStr = _VarR8FromStr@16  @84
+;VarR8FromDisp = _VarR8FromDisp@0  @85
+VarR8FromBool = _VarR8FromBool@8  @86
+VarDateFromUI1 = _VarDateFromUI1@8  @88
+VarDateFromI2 = _VarDateFromI2@8  @89
+VarDateFromI4 = _VarDateFromI4@8  @90
+VarDateFromR4 = _VarDateFromR4@8  @91
+VarDateFromR8 = _VarDateFromR8@12  @92
+VarDateFromCy = _VarDateFromCy@12  @93
+VarDateFromStr = _VarDateFromStr@16  @94
+;VarDateFromDisp = _VarDateFromDisp@0  @95
+VarDateFromBool = _VarDateFromBool@8  @96
+VarCyFromUI1 = _VarCyFromUI1@8  @98
+VarCyFromI2 = _VarCyFromI2@8  @99
+VarCyFromI4 = _VarCyFromI4@8  @100
+VarCyFromR4 = _VarCyFromR4@8  @101
+VarCyFromR8 = _VarCyFromR8@12  @102
+VarCyFromDate = _VarCyFromDate@12  @103
+VarCyFromStr = _VarCyFromStr@16  @104
+;VarCyFromDisp = _VarCyFromDisp@0  @105
+VarCyFromBool = _VarCyFromBool@8  @106
+VarBstrFromUI1 = _VarBstrFromUI1@16  @108
+VarBstrFromI2 = _VarBstrFromI2@16  @109
+VarBstrFromI4 = _VarBstrFromI4@16  @110
+VarBstrFromR4 = _VarBstrFromR4@16  @111
+VarBstrFromR8 = _VarBstrFromR8@20  @112
+VarBstrFromCy = _VarBstrFromCy@20  @113
+VarBstrFromDate = _VarBstrFromDate@20  @114
+;VarBstrFromDisp = _VarBstrFromDisp@0  @115
+VarBstrFromBool = _VarBstrFromBool@16  @116
+VarBoolFromUI1 = _VarBoolFromUI1@8  @118
+VarBoolFromI2 = _VarBoolFromI2@8  @119
+VarBoolFromI4 = _VarBoolFromI4@8  @120
+VarBoolFromR4 = _VarBoolFromR4@8  @121
+VarBoolFromR8 = _VarBoolFromR8@12  @122
+VarBoolFromDate = _VarBoolFromDate@12  @123
+VarBoolFromCy = _VarBoolFromCy@12  @124
+VarBoolFromStr = _VarBoolFromStr@16  @125
+;VarBoolFromDisp = _VarBoolFromDisp@0  @126
+VarUI1FromI2 = _VarUI1FromI2@8  @130
+VarUI1FromI4 = _VarUI1FromI4@8  @131
+VarUI1FromR4 = _VarUI1FromR4@8  @132
+VarUI1FromR8 = _VarUI1FromR8@12  @133
+VarUI1FromCy = _VarUI1FromCy@12  @134
+VarUI1FromDate = _VarUI1FromDate@12  @135
+VarUI1FromStr = _VarUI1FromStr@16  @136
+;VarUI1FromDisp = _VarUI1FromDisp@0  @137
+VarUI1FromBool = _VarUI1FromBool@8  @138
+;DispCallFunc = _DispCallFunc@0  @146
+VariantChangeTypeEx = _VariantChangeTypeEx@20  @147
+;SafeArrayPtrOfIndex = _SafeArrayPtrOfIndex@0  @148
+SysStringByteLen = _SysStringByteLen@4  @149
+SysAllocStringByteLen = _SysAllocStringByteLen@8  @150
+;CreateTypeLib = _CreateTypeLib@0  @160
+LoadTypeLib = _LoadTypeLib@8  @161
+LoadRegTypeLib = _LoadRegTypeLib@20  @162
+RegisterTypeLib = _RegisterTypeLib@12  @163
+QueryPathOfRegTypeLib = _QueryPathOfRegTypeLib@20  @164
+;LHashValOfNameSys = _LHashValOfNameSys@0  @165
+;LHashValOfNameSysA = _LHashValOfNameSysA@0  @166
+OaBuildVersion = _OaBuildVersion@0  @170
+;ClearCustData = _ClearCustData@0  @171
+;CreateTypeLib2 = _CreateTypeLib2@0  @180
+;LoadTypeLibEx = _LoadTypeLibEx@0  @183
+;SystemTimeToVariantTime = _SystemTimeToVariantTime@0  @184
+;VariantTimeToSystemTime = _VariantTimeToSystemTime@0  @185
+UnRegisterTypeLib = _UnRegisterTypeLib@20  @186
+;VarDecFromUI1 = _VarDecFromUI1@0  @190
+;VarDecFromI2 = _VarDecFromI2@0  @191
+;VarDecFromI4 = _VarDecFromI4@0  @192
+;VarDecFromR4 = _VarDecFromR4@0  @193
+;VarDecFromR8 = _VarDecFromR8@0  @194
+;VarDecFromDate = _VarDecFromDate@0  @195
+;VarDecFromCy = _VarDecFromCy@0  @196
+;VarDecFromStr = _VarDecFromStr@0  @197
+;VarDecFromDisp = _VarDecFromDisp@0  @198
+;VarDecFromBool = _VarDecFromBool@0  @199
+;GetErrorInfo = _GetErrorInfo@0  @200
+;SetErrorInfo = _SetErrorInfo@0  @201
+;CreateErrorInfo = _CreateErrorInfo@0  @202
+;VarI2FromI1 = _VarI2FromI1@0  @205
+VarI2FromUI2 = _VarI2FromUI2@8  @206
+VarI2FromUI4 = _VarI2FromUI4@8  @207
+;VarI2FromDec = _VarI2FromDec@0  @208
+VarI4FromI1 = _VarI4FromI1@8  @209
+VarI4FromUI2 = _VarI4FromUI2@8  @210
+VarI4FromUI4 = _VarI4FromUI4@8  @211
+;VarI4FromDec = _VarI4FromDec@0  @212
+VarR4FromI1 = _VarR4FromI1@8  @213
+VarR4FromUI2 = _VarR4FromUI2@8  @214
+VarR4FromUI4 = _VarR4FromUI4@8  @215
+;VarR4FromDec = _VarR4FromDec@0  @216
+VarR8FromI1 = _VarR8FromI1@8  @217
+VarR8FromUI2 = _VarR8FromUI2@8  @218
+VarR8FromUI4 = _VarR8FromUI4@8  @219
+;VarR8FromDec = _VarR8FromDec@0  @220
+VarDateFromI1 = _VarDateFromI1@8  @221
+VarDateFromUI2 = _VarDateFromUI2@8  @222
+VarDateFromUI4 = _VarDateFromUI4@8  @223
+;VarDateFromDec = _VarDateFromDec@0  @224
+VarCyFromI1 = _VarCyFromI1@8  @225
+VarCyFromUI2 = _VarCyFromUI2@8  @226
+VarCyFromUI4 = _VarCyFromUI4@8  @227
+;VarCyFromDec = _VarCyFromDec@0  @228
+VarBstrFromI1 = _VarBstrFromI1@16  @229
+VarBstrFromUI2 = _VarBstrFromUI2@16  @230
+VarBstrFromUI4 = _VarBstrFromUI4@16  @231
+;VarBstrFromDec = _VarBstrFromDec@0  @232
+VarBoolFromI1 = _VarBoolFromI1@8  @233
+VarBoolFromUI2 = _VarBoolFromUI2@8  @234
+VarBoolFromUI4 = _VarBoolFromUI4@8  @235
+;VarBoolFromDec = _VarBoolFromDec@0  @236
+VarUI1FromI1 = _VarUI1FromI1@8  @237
+VarUI1FromUI2 = _VarUI1FromUI2@8  @238
+VarUI1FromUI4 = _VarUI1FromUI4@8  @239
+;VarUI1FromDec = _VarUI1FromDec@0  @240
+;VarDecFromI1 = _VarDecFromI1@0  @241
+;VarDecFromUI2 = _VarDecFromUI2@0  @242
+;VarDecFromUI4 = _VarDecFromUI4@0  @243
+VarI1FromUI1 = _VarI1FromUI1@8  @244
+VarI1FromI2 = _VarI1FromI2@8  @245
+VarI1FromI4 = _VarI1FromI4@8 @246
+VarI1FromR4 = _VarI1FromR4@8 @247
+VarI1FromR8 = _VarI1FromR8@12  @248
+VarI1FromDate = _VarI1FromDate@12  @249
+VarI1FromCy = _VarI1FromCy@12  @250
+VarI1FromStr = _VarI1FromStr@16  @251
+;VarI1FromDisp = _VarI1FromDisp@0  @252
+VarI1FromBool = _VarI1FromBool@8  @253
+VarI1FromUI2 = _VarI1FromUI2@8  @254
+VarI1FromUI4 = _VarI1FromUI4@8  @255
+;VarI1FromDec = _VarI1FromDec@0  @256
+VarUI2FromUI1 = _VarUI2FromUI1@8  @257
+VarUI2FromI2 = _VarUI2FromI2@8  @258
+VarUI2FromI4 = _VarUI2FromI4@8  @259
+VarUI2FromR4 = _VarUI2FromR4@8  @260
+VarUI2FromR8 = _VarUI2FromR8@12  @261
+VarUI2FromDate = _VarUI2FromDate@12  @262
+VarUI2FromCy = _VarUI2FromCy@12  @263
+VarUI2FromStr = _VarUI2FromStr@16  @264
+;VarUI2FromDisp = _VarUI2FromDisp@0  @265
+VarUI2FromBool = _VarUI2FromBool@8  @266
+VarUI2FromI1 = _VarUI2FromI1@8  @267
+VarUI2FromUI4 = _VarUI2FromUI4@8  @268
+;VarUI2FromDec = _VarUI2FromDec@0  @269
+VarUI4FromUI1 = _VarUI4FromUI1@8  @270
+VarUI4FromI2 = _VarUI4FromI2@8  @271
+VarUI4FromI4 = _VarUI4FromI4@8  @272
+VarUI4FromR4 = _VarUI4FromR4@8  @273
+VarUI4FromR8 = _VarUI4FromR8@12  @274
+VarUI4FromDate = _VarUI4FromDate@12  @275
+VarUI4FromCy = _VarUI4FromCy@12  @276
+VarUI4FromStr = _VarUI4FromStr@16  @277
+;VarUI4FromDisp = _VarUI4FromDisp@0  @278
+VarUI4FromBool = _VarUI4FromBool@8  @279
+VarUI4FromI1 = _VarUI4FromI1@8  @280
+VarUI4FromUI2 = _VarUI4FromUI2@8  @281
+;VarUI4FromDec = _VarUI4FromDec@0  @282
+;BSTR_UserSize = _BSTR_UserSize@0  @283
+;BSTR_UserMarshal = _BSTR_UserMarshal@0  @284
+;BSTR_UserUnmarshal = _BSTR_UserUnmarshal@0  @285
+;BSTR_UserFree = _BSTR_UserFree@0  @286
+;VARIANT_UserSize = _VARIANT_UserSize@0  @287
+;VARIANT_UserMarshal = _VARIANT_UserMarshal@0  @288
+;VARIANT_UserUnmarshal = _VARIANT_UserUnmarshal@0  @289
+;VARIANT_UserFree = _VARIANT_UserFree@0  @290
+;LPSAFEARRAY_UserSize = _LPSAFEARRAY_UserSize@0  @291
+;LPSAFEARRAY_UserMarshal = _LPSAFEARRAY_UserMarshal@0  @292
+;LPSAFEARRAY_UserUnmarshal = _LPSAFEARRAY_UserUnmarshal@0  @293
+;LPSAFEARRAY_UserFree = _LPSAFEARRAY_UserFree@0  @294
+;LPSAFEARRAY_Size = _LPSAFEARRAY_Size@0  @295
+;LPSAFEARRAY_Marshal = _LPSAFEARRAY_Marshal@0  @296
+;LPSAFEARRAY_Unmarshal = _LPSAFEARRAY_Unmarshal@0  @297
+;DllRegisterServer = _DllRegisterServer@0  @320
+;DllUnregisterServer = _DllUnregisterServer@0  @321
+;VarDateFromUdate = _VarDateFromUdate@0  @330
+;VarUdateFromDate = _VarUdateFromDate@0  @331
+;GetAltMonthNames = _GetAltMonthNames@0  @332
+;UserHWND_from_local = _UserHWND_from_local@0  @380
+;UserHWND_to_local = _UserHWND_to_local@0  @381
+;UserHWND_free_inst = _UserHWND_free_inst@0  @382
+;UserHWND_free_local = _UserHWND_free_local@0  @383
+;UserBSTR_from_local = _UserBSTR_from_local@0  @384
+;UserBSTR_to_local = _UserBSTR_to_local@0  @385
+;UserBSTR_free_inst = _UserBSTR_free_inst@0  @386
+;UserBSTR_free_local = _UserBSTR_free_local@0  @387
+;UserVARIANT_from_local = _UserVARIANT_from_local@0  @388
+;UserVARIANT_to_local = _UserVARIANT_to_local@0  @389
+;UserVARIANT_free_inst = _UserVARIANT_free_inst@0  @390
+;UserVARIANT_free_local = _UserVARIANT_free_local@0  @391
+;UserEXCEPINFO_from_local = _UserEXCEPINFO_from_local@0  @392
+;UserEXCEPINFO_to_local = _UserEXCEPINFO_to_local@0  @393
+;UserEXCEPINFO_free_inst = _UserEXCEPINFO_free_inst@0  @394
+;UserEXCEPINFO_free_local = _UserEXCEPINFO_free_local@0  @395
+;UserMSG_from_local = _UserMSG_from_local@0  @396
+;UserMSG_to_local = _UserMSG_to_local@0  @397
+;UserMSG_free_inst = _UserMSG_free_inst@0  @398
+;UserMSG_free_local = _UserMSG_free_local@0  @399
+;DllCanUnloadNow = _DllCanUnloadNow@0  @410
+;SafeArrayCreateVector = _SafeArrayCreateVector@0  @411
+;SafeArrayCopyData = _SafeArrayCopyData@0  @412
+;VectorFromBstr = _VectorFromBstr@0  @413
+;BstrFromVector = _BstrFromVector@0  @414
+;OleIconToCursor = _OleIconToCursor@0  @415
+;OleCreatePropertyFrameIndirect = _OleCreatePropertyFrameIndirect@0  @416
+;OleCreatePropertyFrame = _OleCreatePropertyFrame@0  @417
+;OleLoadPicture = _OleLoadPicture@0  @418
+;OleCreatePictureIndirect = _OleCreatePictureIndirect@0  @419
+OleCreateFontIndirect = _OleCreateFontIndirect@12  @420
+OleTranslateColor = _OleTranslateColor@12  @421
+;OleLoadPictureFile = _OleLoadPictureFile@0  @422
+;OleSavePictureFile = _OleSavePictureFile@0  @423
+;OleLoadPicturePath = _OleLoadPicturePath@0  @424
Index: trunk/src/oleaut32/oleaut32.h
===================================================================
--- trunk/src/oleaut32/oleaut32.h	(revision 631)
+++ trunk/src/oleaut32/oleaut32.h	(revision 631)
@@ -0,0 +1,47 @@
+/*
+ * Win32 OLE stubs for OS/2
+ *
+ * 1998/06/12
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ * Copyright 1998 Sander van Leeuwen
+ */
+#ifndef __OLEAUT32_H__
+#define __OLEAUT32_H__
+
+// ><DJR 17.05.99 Force to use C-interfaces for now to prevent CALLBACK definition compiler error
+#define CINTERFACE 1
+
+// ><DJR 17.05.99 Move standard includes to before os2win.h [memcmp]
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <wchar.h>
+
+// ><DJR 17.05.99 Prevent CALLCONV becoming _System
+#include <win/wtypes.h>
+#include <winbase.h>
+//#include <uconv.h>
+#undef CALLCONV
+
+#include <os2win.h>
+#include <ole2ver.h>
+#include <ole.h>
+#include <winreg.h>
+
+#include "wine/obj_base.h"
+#include "wine/obj_misc.h"
+#include "wine/obj_inplace.h"
+#include "wine/obj_dataobject.h"
+#include "wine/obj_oleobj.h"
+#include "wine/obj_marshal.h"
+#include "wine/obj_moniker.h"
+#include "wine/obj_clientserver.h"
+#include "wine/obj_dragdrop.h"
+#include <heapstring.h>
+
+#endif
Index: trunk/src/oleaut32/olefont.cpp
===================================================================
--- trunk/src/oleaut32/olefont.cpp	(revision 631)
+++ trunk/src/oleaut32/olefont.cpp	(revision 631)
@@ -0,0 +1,1400 @@
+/*
+ * OLE Font encapsulation implementation
+ *
+ * This file contains an implementation of the IFont
+ * interface and the OleCreateFontIndirect API call.
+ *
+ * Copyright 1999 Francis Beaudet
+ * Copyright 1999 Sander van Leeuwen  (WINE OS/2 Port 990815)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+#include "oleaut32.h"
+#include <assert.h>
+#include <string.h>
+#include "winerror.h"
+#include "oleauto.h"
+#include "ocidl.h"
+#include "olectl.h"
+#include "debugtools.h"
+#include "heap.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+/***********************************************************************
+ * Declaration of constants used when serializing the font object.
+ */
+#define FONTPERSIST_ITALIC        0x02
+#define FONTPERSIST_UNDERLINE     0x04
+#define FONTPERSIST_STRIKETHROUGH 0x08
+
+/***********************************************************************
+ * Declaration of the implementation class for the IFont interface
+ */
+typedef struct OLEFontImpl OLEFontImpl;
+
+struct OLEFontImpl
+{
+  /*
+   * This class supports many interfaces. IUnknown, IFont, 
+   * IDispatch, IDispFont and IPersistStream. The first two are
+   * supported by the first vtablem the next two are supported by 
+   * the second table and the last one has it's own.
+   */
+  ICOM_VTABLE(IFont)*     lpvtbl1;
+  ICOM_VTABLE(IDispatch)* lpvtbl2;
+  ICOM_VTABLE(IPersistStream)*            lpvtbl3;
+
+  /*
+   * Reference count for that instance of the class.
+   */
+  ULONG ref;
+
+  /*
+   * This structure contains the description of the class.
+   */
+  FONTDESC description;
+
+  /*
+   * Contain the font associated with this object.
+   */
+  HFONT gdiFont;
+
+  /*
+   * Font lock count.
+   */
+  DWORD fontLock;
+
+  /*
+   * Size ratio
+   */
+  long cyLogical;
+  long cyHimetric;
+};
+
+/*
+ * Here, I define utility macros to help with the casting of the 
+ * "thisptr" parameter.
+ * There is a version to accomodate all of the VTables implemented
+ * by this object.
+ */
+#define _ICOM_THIS(class,name) class* thisptr = (class*)name;
+#define _ICOM_THIS_From_IDispatch(class, name) class* thisptr = (class*)(((char*)name)-sizeof(void*)); 
+#define _ICOM_THIS_From_IPersistStream(class, name) class* thisptr = (class*)(((char*)name)-2*sizeof(void*)); 
+
+/***********************************************************************
+ * Prototypes for the implementation functions for the IFont
+ * interface
+ */
+static OLEFontImpl* OLEFontImpl_Construct(LPFONTDESC fontDesc);
+static void         OLEFontImpl_Destroy(OLEFontImpl* fontDesc);
+static HRESULT      WINAPI OLEFontImpl_QueryInterface(IFont* iface, REFIID riid, VOID** ppvoid);
+static ULONG        WINAPI OLEFontImpl_AddRef(IFont* iface);
+static ULONG        WINAPI OLEFontImpl_Release(IFont* iface);
+static HRESULT      WINAPI OLEFontImpl_get_Name(IFont* iface, BSTR* pname);
+static HRESULT      WINAPI OLEFontImpl_put_Name(IFont* iface, BSTR name);
+static HRESULT      WINAPI OLEFontImpl_get_Size(IFont* iface, CY* psize);
+static HRESULT      WINAPI OLEFontImpl_put_Size(IFont* iface, CY size);
+static HRESULT      WINAPI OLEFontImpl_get_Bold(IFont* iface, BOOL* pbold);
+static HRESULT      WINAPI OLEFontImpl_put_Bold(IFont* iface, BOOL bold);
+static HRESULT      WINAPI OLEFontImpl_get_Italic(IFont* iface, BOOL* pitalic);
+static HRESULT      WINAPI OLEFontImpl_put_Italic(IFont* iface, BOOL italic);
+static HRESULT      WINAPI OLEFontImpl_get_Underline(IFont* iface, BOOL* punderline);
+static HRESULT      WINAPI OLEFontImpl_put_Underline(IFont* iface, BOOL underline);
+static HRESULT      WINAPI OLEFontImpl_get_Strikethrough(IFont* iface, BOOL* pstrikethrough);
+static HRESULT      WINAPI OLEFontImpl_put_Strikethrough(IFont* iface, BOOL strikethrough);
+static HRESULT      WINAPI OLEFontImpl_get_Weight(IFont* iface, short* pweight);
+static HRESULT      WINAPI OLEFontImpl_put_Weight(IFont* iface, short weight);
+static HRESULT      WINAPI OLEFontImpl_get_Charset(IFont* iface, short* pcharset);
+static HRESULT      WINAPI OLEFontImpl_put_Charset(IFont* iface, short charset);
+static HRESULT      WINAPI OLEFontImpl_get_hFont(IFont* iface, HFONT* phfont);
+static HRESULT      WINAPI OLEFontImpl_Clone(IFont* iface, IFont** ppfont);
+static HRESULT      WINAPI OLEFontImpl_IsEqual(IFont* iface, IFont* pFontOther);
+static HRESULT      WINAPI OLEFontImpl_SetRatio(IFont* iface, long cyLogical, long cyHimetric);
+static HRESULT      WINAPI OLEFontImpl_QueryTextMetrics(IFont* iface, TEXTMETRICOLE* ptm);
+static HRESULT      WINAPI OLEFontImpl_AddRefHfont(IFont* iface, HFONT hfont);
+static HRESULT      WINAPI OLEFontImpl_ReleaseHfont(IFont* iface, HFONT hfont);
+static HRESULT      WINAPI OLEFontImpl_SetHdc(IFont* iface, HDC hdc);
+
+/***********************************************************************
+ * Prototypes for the implementation functions for the IDispatch
+ * interface
+ */
+static HRESULT WINAPI OLEFontImpl_IDispatch_QueryInterface(IDispatch* iface, 
+						    REFIID     riid, 
+						    VOID**     ppvoid);
+static ULONG   WINAPI OLEFontImpl_IDispatch_AddRef(IDispatch* iface);
+static ULONG   WINAPI OLEFontImpl_IDispatch_Release(IDispatch* iface);
+static HRESULT WINAPI OLEFontImpl_GetTypeInfoCount(IDispatch*    iface, 
+					           unsigned int* pctinfo);
+static HRESULT WINAPI OLEFontImpl_GetTypeInfo(IDispatch*  iface, 
+				       	      UINT      iTInfo,
+				              LCID        lcid, 
+				              ITypeInfo** ppTInfo);
+static HRESULT WINAPI OLEFontImpl_GetIDsOfNames(IDispatch*  iface,
+					        REFIID      riid, 
+					        LPOLESTR* rgszNames, 
+					        UINT      cNames, 
+					        LCID        lcid,
+					        DISPID*     rgDispId);
+static HRESULT WINAPI OLEFontImpl_Invoke(IDispatch*  iface,
+				         DISPID      dispIdMember, 
+				         REFIID      riid, 
+				         LCID        lcid, 
+				         WORD        wFlags,
+				         DISPPARAMS* pDispParams,
+				         VARIANT*    pVarResult, 
+				         EXCEPINFO*  pExepInfo,
+				         UINT*     puArgErr); 
+
+/***********************************************************************
+ * Prototypes for the implementation functions for the IPersistStream
+ * interface
+ */
+static HRESULT WINAPI OLEFontImpl_IPersistStream_QueryInterface(IPersistStream* iface, 
+						    REFIID     riid, 
+						    VOID**     ppvoid);
+static ULONG   WINAPI OLEFontImpl_IPersistStream_AddRef(IPersistStream* iface);
+static ULONG   WINAPI OLEFontImpl_IPersistStream_Release(IPersistStream* iface);
+static HRESULT WINAPI OLEFontImpl_GetClassID(IPersistStream* iface, 
+					     CLSID*                pClassID);
+static HRESULT WINAPI OLEFontImpl_IsDirty(IPersistStream*  iface);
+static HRESULT WINAPI OLEFontImpl_Load(IPersistStream*  iface,
+				       IStream*         pLoadStream);
+static HRESULT WINAPI OLEFontImpl_Save(IPersistStream*  iface,
+				       IStream*         pOutStream,
+				       BOOL             fClearDirty); 
+static HRESULT WINAPI OLEFontImpl_GetSizeMax(IPersistStream*  iface,
+					     ULARGE_INTEGER*  pcbSize); 
+
+/*
+ * Virtual function tables for the OLEFontImpl class.
+ */
+static ICOM_VTABLE(IFont) OLEFontImpl_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  OLEFontImpl_QueryInterface,
+  OLEFontImpl_AddRef,
+  OLEFontImpl_Release,
+  OLEFontImpl_get_Name,
+  OLEFontImpl_put_Name,
+  OLEFontImpl_get_Size,
+  OLEFontImpl_put_Size,
+  OLEFontImpl_get_Bold,
+  OLEFontImpl_put_Bold,
+  OLEFontImpl_get_Italic,
+  OLEFontImpl_put_Italic,
+  OLEFontImpl_get_Underline,
+  OLEFontImpl_put_Underline,
+  OLEFontImpl_get_Strikethrough,
+  OLEFontImpl_put_Strikethrough,
+  OLEFontImpl_get_Weight,
+  OLEFontImpl_put_Weight,
+  OLEFontImpl_get_Charset,
+  OLEFontImpl_put_Charset,
+  OLEFontImpl_get_hFont,
+  OLEFontImpl_Clone, 
+  OLEFontImpl_IsEqual,
+  OLEFontImpl_SetRatio,
+  OLEFontImpl_QueryTextMetrics,
+  OLEFontImpl_AddRefHfont,
+  OLEFontImpl_ReleaseHfont,
+  OLEFontImpl_SetHdc
+};
+
+static ICOM_VTABLE(IDispatch) OLEFontImpl_IDispatch_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  OLEFontImpl_IDispatch_QueryInterface,
+  OLEFontImpl_IDispatch_AddRef,
+  OLEFontImpl_IDispatch_Release,
+  OLEFontImpl_GetTypeInfoCount,
+  OLEFontImpl_GetTypeInfo,
+  OLEFontImpl_GetIDsOfNames,
+  OLEFontImpl_Invoke
+};
+
+static ICOM_VTABLE(IPersistStream) OLEFontImpl_IPersistStream_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  OLEFontImpl_IPersistStream_QueryInterface,
+  OLEFontImpl_IPersistStream_AddRef,
+  OLEFontImpl_IPersistStream_Release,
+  OLEFontImpl_GetClassID,
+  OLEFontImpl_IsDirty,
+  OLEFontImpl_Load,
+  OLEFontImpl_Save,
+  OLEFontImpl_GetSizeMax
+};
+
+/******************************************************************************
+ *		OleCreateFontIndirect	[OLEAUT32.420]
+ */
+INT WINAPI OleCreateFontIndirect(
+  LPFONTDESC lpFontDesc,
+  REFIID     riid,
+  VOID**     ppvObj)
+{
+  OLEFontImpl* newFont = 0;
+  HRESULT      hr      = S_OK;
+
+  /*
+   * Sanity check
+   */
+  if (ppvObj==0)
+    return E_POINTER;
+
+  *ppvObj = 0;
+
+  /*
+   * Try to construct a new instance of the class.
+   */
+  newFont = OLEFontImpl_Construct(lpFontDesc);
+
+  if (newFont == 0)
+    return E_OUTOFMEMORY;
+
+  /*
+   * Make sure it supports the interface required by the caller.
+   */
+  hr = IFont_QueryInterface((IFont*)newFont, riid, ppvObj);
+
+  /*
+   * Release the reference obtained in the constructor. If
+   * the QueryInterface was unsuccessful, it will free the class.
+   */
+  IFont_Release((IFont*)newFont);
+
+  return hr;
+}
+
+
+/***********************************************************************
+ * Implementation of the OLEFontImpl class.
+ */
+
+/************************************************************************
+ * OLEFontImpl_Construct
+ *
+ * This method will construct a new instance of the OLEFontImpl
+ * class.
+ *
+ * The caller of this method must release the object when it's
+ * done with it.
+ */
+static OLEFontImpl* OLEFontImpl_Construct(LPFONTDESC fontDesc)
+{
+  OLEFontImpl* newObject = 0;
+
+  /*
+   * Allocate space for the object.
+   */
+  newObject = (OLEFontImpl*)HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl));
+
+  if (newObject==0)
+    return newObject;
+  
+  /*
+   * Initialize the virtual function table.
+   */
+  newObject->lpvtbl1 = &OLEFontImpl_VTable;
+  newObject->lpvtbl2 = &OLEFontImpl_IDispatch_VTable;
+  newObject->lpvtbl3 = &OLEFontImpl_IPersistStream_VTable;
+  
+  /*
+   * Start with one reference count. The caller of this function 
+   * must release the interface pointer when it is done.
+   */
+  newObject->ref = 1;
+
+  /*
+   * Copy the description of the font in the object.
+   */
+  assert(fontDesc->cbSizeofstruct >= sizeof(FONTDESC));
+
+  newObject->description.cbSizeofstruct = sizeof(FONTDESC);
+  newObject->description.lpstrName = (LPWSTR)HeapAlloc(GetProcessHeap(),
+					       0, 
+					       (lstrlenW(fontDesc->lpstrName)+1) * sizeof(WCHAR));
+  lstrcpyW(newObject->description.lpstrName, fontDesc->lpstrName);
+  newObject->description.cySize         = fontDesc->cySize;
+  newObject->description.sWeight        = fontDesc->sWeight;
+  newObject->description.sCharset       = fontDesc->sCharset;
+  newObject->description.fItalic        = fontDesc->fItalic;
+  newObject->description.fUnderline     = fontDesc->fUnderline;
+  newObject->description.fStrikethrough = fontDesc->fStrikethrough;
+
+  /*
+   * Initializing all the other members.
+   */
+  newObject->gdiFont  = 0;
+  newObject->fontLock = 0;
+  newObject->cyHimetric = 1;
+  newObject->cyLogical  = 1;
+
+  return newObject;
+}
+
+/************************************************************************
+ * OLEFontImpl_Construct
+ *
+ * This method is called by the Release method when the reference
+ * count goes doen to 0. it will free all resources used by
+ * this object.
+ */
+static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc)
+{
+  if (fontDesc->description.lpstrName!=0)
+    HeapFree(GetProcessHeap(), 0, fontDesc->description.lpstrName);
+
+  if (fontDesc->gdiFont!=0)
+    DeleteObject(fontDesc->gdiFont);
+
+  HeapFree(GetProcessHeap(), 0, fontDesc);
+}
+
+/************************************************************************
+ * OLEFontImpl_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+HRESULT WINAPI OLEFontImpl_QueryInterface(
+  IFont*  iface,
+  REFIID  riid,
+  void**  ppvObject)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (thisptr==0) || (ppvObject==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+  
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = (IFont*)thisptr;
+  }
+  else if (memcmp(&IID_IFont, riid, sizeof(IID_IFont)) == 0) 
+  {
+    *ppvObject = (IFont*)thisptr;
+  }
+  else if (memcmp(&IID_IDispatch, riid, sizeof(IID_IDispatch)) == 0) 
+  {
+    *ppvObject = (IDispatch*)&(thisptr->lpvtbl2);
+  }
+  else if (memcmp(&IID_IFontDisp, riid, sizeof(IID_IFontDisp)) == 0) 
+  {
+    *ppvObject = (IDispatch*)&(thisptr->lpvtbl2);
+  }
+  else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0) 
+  {
+    *ppvObject = (IPersistStream*)&(thisptr->lpvtbl3);
+  }
+  
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+  {
+    char clsid[50];
+
+    WINE_StringFromCLSID((LPCLSID)riid,clsid);
+    
+    WARN(
+	 "() : asking for un supported interface %s\n", 
+	 clsid);
+
+    return E_NOINTERFACE;
+  }
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  OLEFontImpl_AddRef((IFont*)thisptr);
+
+  return S_OK;;
+}
+        
+/************************************************************************
+ * OLEFontImpl_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+ULONG WINAPI OLEFontImpl_AddRef( 
+  IFont* iface)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  thisptr->ref++;
+
+  return thisptr->ref;
+}
+        
+/************************************************************************
+ * OLEFontImpl_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+ULONG WINAPI OLEFontImpl_Release( 
+      IFont* iface)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  /*
+   * Decrease the reference count on this object.
+   */
+  thisptr->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (thisptr->ref==0)
+  {
+    OLEFontImpl_Destroy(thisptr);
+
+    return 0;
+  }
+  
+  return thisptr->ref;
+}
+        
+/************************************************************************
+ * OLEFontImpl_get_Name (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_get_Name(
+  IFont*  iface, 
+  BSTR* pname)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  /*
+   * Sanity check.
+   */
+  if (pname==0)
+    return E_POINTER;
+
+  if (thisptr->description.lpstrName!=0)
+    *pname = SysAllocString(thisptr->description.lpstrName);
+  else
+    *pname = 0;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_put_Name (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_put_Name(
+  IFont* iface, 
+  BSTR name)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  if (thisptr->description.lpstrName==0)
+  {
+    thisptr->description.lpstrName = (LPWSTR)HeapAlloc(GetProcessHeap(),
+					    0, 
+					    (lstrlenW(name)+1) * sizeof(WCHAR));
+  }
+  else
+  {
+    thisptr->description.lpstrName = (LPWSTR)HeapReAlloc(GetProcessHeap(),
+					      0, 
+					      thisptr->description.lpstrName,
+					      (lstrlenW(name)+1) * sizeof(WCHAR));
+  }
+
+  if (thisptr->description.lpstrName==0)
+    return E_OUTOFMEMORY;
+
+  lstrcpyW(thisptr->description.lpstrName, name);
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_get_Size (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_get_Size(
+  IFont* iface, 
+  CY*    psize)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  /*
+   * Sanity check
+   */
+  if (psize==0)
+    return E_POINTER;
+
+  psize->u.Hi = 0;
+  psize->u.Lo = thisptr->description.cySize.u.Lo;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_put_Size (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_put_Size(
+  IFont* iface, 
+  CY     size)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  thisptr->description.cySize.u.Hi = 0;
+  thisptr->description.cySize.u.Lo = thisptr->description.cySize.u.Lo;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_get_Bold (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_get_Bold(
+  IFont*  iface, 
+  BOOL* pbold)
+{
+  FIXME("():Stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEFontImpl_put_Bold (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_put_Bold(
+  IFont* iface,
+  BOOL bold)
+{
+  FIXME("():Stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEFontImpl_get_Italic (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_get_Italic(
+  IFont*  iface, 
+  BOOL* pitalic)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  /*
+   * Sanity check
+   */
+  if (pitalic==0)
+    return E_POINTER;
+
+  *pitalic = thisptr->description.fItalic;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_put_Italic (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_put_Italic(
+  IFont* iface, 
+  BOOL italic)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  thisptr->description.fItalic = italic;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_get_Underline (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_get_Underline(
+  IFont*  iface, 
+  BOOL* punderline)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  /*
+   * Sanity check
+   */
+  if (punderline==0)
+    return E_POINTER;
+
+  *punderline = thisptr->description.fUnderline;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_put_Underline (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_put_Underline(
+  IFont* iface,
+  BOOL underline)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  thisptr->description.fUnderline = underline;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_get_Strikethrough (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_get_Strikethrough(
+  IFont*  iface, 
+  BOOL* pstrikethrough)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  /*
+   * Sanity check
+   */
+  if (pstrikethrough==0)
+    return E_POINTER;
+
+  *pstrikethrough = thisptr->description.fStrikethrough;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_put_Strikethrough (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_put_Strikethrough(
+ IFont* iface, 
+ BOOL strikethrough)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  thisptr->description.fStrikethrough = strikethrough;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_get_Weight (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_get_Weight(
+  IFont* iface, 
+  short* pweight)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  /*
+   * Sanity check
+   */
+  if (pweight==0)
+    return E_POINTER;
+
+  *pweight = thisptr->description.sWeight;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_put_Weight (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_put_Weight(
+  IFont* iface, 
+  short  weight)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  thisptr->description.sWeight = weight;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_get_Charset (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_get_Charset(
+  IFont* iface, 
+  short* pcharset)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  /*
+   * Sanity check
+   */
+  if (pcharset==0)
+    return E_POINTER;
+
+  *pcharset = thisptr->description.sCharset;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_put_Charset (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_put_Charset(
+  IFont* iface, 
+  short charset)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  thisptr->description.sCharset = charset;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_get_hFont (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_get_hFont(
+  IFont*   iface,
+  HFONT* phfont)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  if (phfont==NULL)
+    return E_POINTER;
+
+  /*
+   * Realize the font if necessary
+ */
+  if (thisptr->gdiFont==0)
+{
+    LOGFONTW logFont;
+    INT      fontHeight;
+    CY       cySize;
+    
+    /*
+     * The height of the font returned by the get_Size property is the
+     * height of the font in points multiplied by 10000... Using some
+     * simple conversions and the ratio given by the application, it can
+     * be converted to a height in pixels.
+     */
+    IFont_get_Size(iface, &cySize);
+
+    fontHeight = MulDiv(cySize.u.Lo, 2540L, 72L);
+    fontHeight = MulDiv(fontHeight, thisptr->cyLogical,thisptr->cyHimetric);
+
+    memset(&logFont, 0, sizeof(LOGFONTW));
+
+    logFont.lfHeight          = ((fontHeight%10000L)>5000L) ? (-fontHeight/10000L)-1 :
+                                                              (-fontHeight/10000L);
+    logFont.lfItalic          = thisptr->description.fItalic;
+    logFont.lfUnderline       = thisptr->description.fUnderline;
+    logFont.lfStrikeOut       = thisptr->description.fStrikethrough;
+    logFont.lfWeight          = thisptr->description.sWeight;
+    logFont.lfCharSet         = thisptr->description.sCharset;
+    logFont.lfOutPrecision    = OUT_CHARACTER_PRECIS;
+    logFont.lfClipPrecision   = CLIP_DEFAULT_PRECIS;
+    logFont.lfQuality         = DEFAULT_QUALITY;
+    logFont.lfPitchAndFamily  = DEFAULT_PITCH;
+    lstrcpyW(logFont.lfFaceName,thisptr->description.lpstrName);
+
+    thisptr->gdiFont = CreateFontIndirectW(&logFont);
+  }
+
+  *phfont = thisptr->gdiFont;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_Clone (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_Clone(
+  IFont*  iface,
+  IFont** ppfont)
+{
+  OLEFontImpl* newObject = 0;
+
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  if (ppfont == NULL)
+    return E_POINTER;
+
+  *ppfont = NULL;
+
+  /*
+   * Allocate space for the object.
+   */
+  newObject = (OLEFontImpl*) HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl));
+
+  if (newObject==NULL)
+    return E_OUTOFMEMORY;
+
+  *newObject = *thisptr;
+
+  /*
+   * That new object starts with a reference count of 1
+   */
+  newObject->ref          = 1;
+
+  *ppfont = (IFont*)newObject;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_IsEqual (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_IsEqual(
+  IFont* iface, 
+  IFont* pFontOther)
+{
+  FIXME("():Stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEFontImpl_SetRatio (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_SetRatio(
+  IFont* iface,
+  long   cyLogical,
+  long   cyHimetric)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  thisptr->cyLogical  = cyLogical;
+  thisptr->cyHimetric = cyHimetric;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_QueryTextMetrics (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT      WINAPI OLEFontImpl_QueryTextMetrics(
+  IFont*         iface, 
+  TEXTMETRICOLE* ptm)
+{
+  FIXME("():Stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEFontImpl_AddRefHfont (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_AddRefHfont(
+  IFont*  iface, 
+  HFONT hfont)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  if ( (hfont == 0) ||
+       (hfont != thisptr->gdiFont) )
+    return E_INVALIDARG;
+
+  thisptr->fontLock++;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_ReleaseHfont (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_ReleaseHfont(
+  IFont*  iface,
+  HFONT hfont)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+
+  if ( (hfont == 0) ||
+       (hfont != thisptr->gdiFont) )
+    return E_INVALIDARG;
+
+  thisptr->fontLock--;
+
+  /*
+   * If we just released our last font reference, destroy it.
+   */
+  if (thisptr->fontLock==0)
+  {
+    DeleteObject(thisptr->gdiFont);
+    thisptr->gdiFont = 0; 
+}
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_SetHdc (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_SetHdc(
+  IFont* iface,
+  HDC  hdc)
+{
+  FIXME("():Stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEFontImpl_IDispatch_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI OLEFontImpl_IDispatch_QueryInterface(
+  IDispatch* iface,
+  REFIID     riid,
+  VOID**     ppvoid)
+{
+  _ICOM_THIS_From_IDispatch(IFont, iface);
+
+  return IFont_QueryInterface(thisptr, riid, ppvoid);
+}
+
+/************************************************************************
+ * OLEFontImpl_IDispatch_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEFontImpl_IDispatch_Release(
+  IDispatch* iface)
+{
+  _ICOM_THIS_From_IDispatch(IFont, iface);
+
+  return IFont_Release(thisptr);
+}
+
+/************************************************************************
+ * OLEFontImpl_IDispatch_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEFontImpl_IDispatch_AddRef(
+  IDispatch* iface)
+{
+  _ICOM_THIS_From_IDispatch(IFont, iface);
+
+  return IFont_AddRef(thisptr);
+}
+
+/************************************************************************
+ * OLEFontImpl_GetTypeInfoCount (IDispatch)
+ *
+ * See Windows documentation for more details on IDispatch methods.
+ */
+static HRESULT WINAPI OLEFontImpl_GetTypeInfoCount(
+  IDispatch*    iface, 
+  unsigned int* pctinfo)
+{
+  FIXME("():Stub\n");
+
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEFontImpl_GetTypeInfo (IDispatch)
+ *
+ * See Windows documentation for more details on IDispatch methods.
+ */
+static HRESULT WINAPI OLEFontImpl_GetTypeInfo(
+  IDispatch*  iface, 
+  UINT      iTInfo,
+  LCID        lcid, 
+  ITypeInfo** ppTInfo)
+{
+  FIXME("():Stub\n");
+
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEFontImpl_GetIDsOfNames (IDispatch)
+ *
+ * See Windows documentation for more details on IDispatch methods.
+ */
+static HRESULT WINAPI OLEFontImpl_GetIDsOfNames(
+  IDispatch*  iface,
+  REFIID      riid, 
+  LPOLESTR* rgszNames, 
+  UINT      cNames, 
+  LCID        lcid,
+  DISPID*     rgDispId)
+{
+  FIXME("():Stub\n");
+
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEFontImpl_Invoke (IDispatch)
+ *
+ * See Windows documentation for more details on IDispatch methods.
+ */
+static HRESULT WINAPI OLEFontImpl_Invoke(
+  IDispatch*  iface,
+  DISPID      dispIdMember, 
+  REFIID      riid, 
+  LCID        lcid, 
+  WORD        wFlags,
+  DISPPARAMS* pDispParams,
+  VARIANT*    pVarResult, 
+  EXCEPINFO*  pExepInfo,
+  UINT*     puArgErr)
+{
+  FIXME("():Stub\n");
+
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEFontImpl_IPersistStream_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI OLEFontImpl_IPersistStream_QueryInterface(
+  IPersistStream* iface,
+  REFIID     riid,
+  VOID**     ppvoid)
+{
+  _ICOM_THIS_From_IPersistStream(IFont, iface);
+
+  return IFont_QueryInterface(thisptr, riid, ppvoid);
+}
+
+/************************************************************************
+ * OLEFontImpl_IPersistStream_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEFontImpl_IPersistStream_Release(
+  IPersistStream* iface)
+{
+  _ICOM_THIS_From_IPersistStream(IFont, iface);
+
+  return IFont_Release(thisptr);
+}
+
+/************************************************************************
+ * OLEFontImpl_IPersistStream_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEFontImpl_IPersistStream_AddRef(
+  IPersistStream* iface)
+{
+  _ICOM_THIS_From_IPersistStream(IFont, iface);
+
+  return IFont_AddRef(thisptr);
+}
+
+/************************************************************************
+ * OLEFontImpl_GetClassID (IPersistStream)
+ *
+ * See Windows documentation for more details on IPersistStream methods.
+ */
+static HRESULT WINAPI OLEFontImpl_GetClassID(
+  IPersistStream* iface, 
+  CLSID*                pClassID)
+{
+  if (pClassID==0)
+    return E_POINTER;
+
+  memcpy(pClassID, &CLSID_StdFont, sizeof(CLSID_StdFont));
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_IsDirty (IPersistStream)
+ *
+ * See Windows documentation for more details on IPersistStream methods.
+ */
+static HRESULT WINAPI OLEFontImpl_IsDirty(
+  IPersistStream*  iface)
+{
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_Load (IPersistStream)
+ *
+ * See Windows documentation for more details on IPersistStream methods.
+ *
+ * This is the format of the standard font serialization as far as I
+ * know
+ *
+ * Offset   Type   Value           Comment
+ * 0x0000   Byte   Unknown         Probably a version number, contains 0x01
+ * 0x0001   Short  Charset         Charset value from the FONTDESC structure
+ * 0x0003   Byte   Attributes      Flags defined as follows:
+ *                                     00000010 - Italic
+ *                                     00000100 - Underline
+ *                                     00001000 - Strikethrough
+ * 0x0004   Short  Weight          Weight value from FONTDESC structure
+ * 0x0006   DWORD  size            "Low" portion of the cySize member of the FONTDESC
+ *                                 structure/
+ * 0x000A   Byte   name length     Length of the font name string (no null character)
+ * 0x000B   String name            Name of the font (ASCII, no nul character)
+ */
+static HRESULT WINAPI OLEFontImpl_Load(
+  IPersistStream*  iface,
+  IStream*         pLoadStream)
+{
+  char  readBuffer[0x100];
+  ULONG cbRead;
+  BYTE  bVersion;
+  BYTE  bAttributes;
+  BYTE  bStringSize;
+
+  _ICOM_THIS_From_IPersistStream(OLEFontImpl, iface);
+  
+  /*
+   * Read the version byte
+   */
+  IStream_Read(pLoadStream, &bVersion, 1, &cbRead);
+
+  if ( (cbRead!=1) ||
+       (bVersion!=0x01) )
+    return E_FAIL;
+
+  /*
+   * Charset
+   */
+  IStream_Read(pLoadStream, &thisptr->description.sCharset, 2, &cbRead);
+
+  if (cbRead!=2)
+    return E_FAIL;
+
+  /*
+   * Attributes
+   */
+  IStream_Read(pLoadStream, &bAttributes, 1, &cbRead);
+
+  if (cbRead!=1)
+    return E_FAIL;
+
+  thisptr->description.fItalic        = (bAttributes & FONTPERSIST_ITALIC) != 0;
+  thisptr->description.fStrikethrough = (bAttributes & FONTPERSIST_STRIKETHROUGH) != 0;
+  thisptr->description.fUnderline     = (bAttributes & FONTPERSIST_UNDERLINE) != 0;
+    
+  /*
+   * Weight
+   */
+  IStream_Read(pLoadStream, &thisptr->description.sWeight, 2, &cbRead);
+
+  if (cbRead!=2)
+    return E_FAIL;
+
+  /*
+   * Size
+   */
+  IStream_Read(pLoadStream, &thisptr->description.cySize.u.Lo, 4, &cbRead);
+
+  if (cbRead!=4)
+    return E_FAIL;
+
+  thisptr->description.cySize.u.Hi = 0;
+
+  /*
+   * FontName
+   */
+  IStream_Read(pLoadStream, &bStringSize, 1, &cbRead);
+
+  if (cbRead!=1)
+    return E_FAIL;
+
+  memset(readBuffer, 0, 0x100);
+  IStream_Read(pLoadStream, readBuffer, bStringSize, &cbRead);
+
+  if (cbRead!=bStringSize)
+    return E_FAIL;
+
+  if (thisptr->description.lpstrName!=0)
+    HeapFree(GetProcessHeap(), 0, thisptr->description.lpstrName);
+
+  thisptr->description.lpstrName = HEAP_strdupAtoW(GetProcessHeap(), 
+						    HEAP_ZERO_MEMORY,
+						    readBuffer);
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_Save (IPersistStream)
+ *
+ * See Windows documentation for more details on IPersistStream methods.
+ */
+static HRESULT WINAPI OLEFontImpl_Save(
+  IPersistStream*  iface,
+  IStream*         pOutStream,
+  BOOL             fClearDirty)
+{
+  char* writeBuffer = NULL;
+  ULONG cbWritten;
+  BYTE  bVersion = 0x01;
+  BYTE  bAttributes;
+  BYTE  bStringSize;
+  
+  _ICOM_THIS_From_IPersistStream(OLEFontImpl, iface);
+
+  /*
+   * Read the version byte
+   */
+  IStream_Write(pOutStream, &bVersion, 1, &cbWritten);
+
+  if (cbWritten!=1)
+    return E_FAIL;
+
+  /*
+   * Charset
+   */
+  IStream_Write(pOutStream, &thisptr->description.sCharset, 2, &cbWritten);
+
+  if (cbWritten!=2)
+    return E_FAIL;
+
+  /*
+   * Attributes
+   */
+  bAttributes = 0;
+
+  if (thisptr->description.fItalic)
+    bAttributes |= FONTPERSIST_ITALIC;
+
+  if (thisptr->description.fStrikethrough)
+    bAttributes |= FONTPERSIST_STRIKETHROUGH;
+  
+  if (thisptr->description.fUnderline)
+    bAttributes |= FONTPERSIST_UNDERLINE;
+
+  IStream_Write(pOutStream, &bAttributes, 1, &cbWritten);
+
+  if (cbWritten!=1)
+    return E_FAIL;
+  
+  /*
+   * Weight
+   */
+  IStream_Write(pOutStream, &thisptr->description.sWeight, 2, &cbWritten);
+
+  if (cbWritten!=2)
+    return E_FAIL;
+
+  /*
+   * Size
+   */
+  IStream_Write(pOutStream, &thisptr->description.cySize.u.Lo, 4, &cbWritten);
+
+  if (cbWritten!=4)
+    return E_FAIL;
+
+  /*
+   * FontName
+   */
+  if (thisptr->description.lpstrName!=0)
+    bStringSize = lstrlenW(thisptr->description.lpstrName);
+  else
+    bStringSize = 0;
+
+  IStream_Write(pOutStream, &bStringSize, 1, &cbWritten);
+
+  if (cbWritten!=1)
+    return E_FAIL;
+
+  if (bStringSize!=0)
+  {
+    writeBuffer = HEAP_strdupWtoA(GetProcessHeap(), 
+				  HEAP_ZERO_MEMORY,
+				  thisptr->description.lpstrName);
+
+    if (writeBuffer==0)
+      return E_OUTOFMEMORY;
+
+    IStream_Write(pOutStream, writeBuffer, bStringSize, &cbWritten);
+    
+    HeapFree(GetProcessHeap(), 0, writeBuffer);
+
+    if (cbWritten!=bStringSize)
+      return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_GetSizeMax (IPersistStream)
+ *
+ * See Windows documentation for more details on IPersistStream methods.
+ */
+static HRESULT WINAPI OLEFontImpl_GetSizeMax(
+  IPersistStream*  iface,
+  ULARGE_INTEGER*  pcbSize)
+{
+  _ICOM_THIS_From_IPersistStream(OLEFontImpl, iface);
+
+  if (pcbSize==NULL)
+    return E_POINTER;
+
+  pcbSize->HighPart = 0;
+  pcbSize->LowPart = 0;
+
+  pcbSize->LowPart += sizeof(BYTE);  /* Version */
+  pcbSize->LowPart += sizeof(WORD);  /* Lang code */
+  pcbSize->LowPart += sizeof(BYTE);  /* Flags */
+  pcbSize->LowPart += sizeof(WORD);  /* Weight */
+  pcbSize->LowPart += sizeof(DWORD); /* Size */
+  pcbSize->LowPart += sizeof(BYTE);  /* StrLength */
+
+  if (thisptr->description.lpstrName!=0)
+    pcbSize->LowPart += lstrlenW(thisptr->description.lpstrName);
+
+  return S_OK;
+}
Index: trunk/src/oleaut32/parsedt.cpp
===================================================================
--- trunk/src/oleaut32/parsedt.cpp	(revision 631)
+++ trunk/src/oleaut32/parsedt.cpp	(revision 631)
@@ -0,0 +1,1332 @@
+/*
+PostgreSQL Data Base Management System (formerly known as Postgres, then
+as Postgres95).
+
+Copyright (c) 1994-7 Regents of the University of California
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose, without fee, and without a written agreement
+is hereby granted, provided that the above copyright notice and this
+paragraph and the following two paragraphs appear in all copies.
+
+IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+/*-------------------------------------------------------------------------
+ *
+ * dt.c--
+ *	  Functions for the built-in type "dt".
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <time.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/timeb.h>
+
+#include "parsedt.h"
+
+static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
+static int	DecodeDate(char *str, int fmask, int *tmask, struct tm * tm);
+static int DecodeNumber(int flen, char *field,
+			 int fmask, int *tmask, struct tm * tm, double *fsec);
+static int DecodeNumberField(int len, char *str,
+				  int fmask, int *tmask, struct tm * tm, double *fsec);
+static int	DecodeSpecial(int field, char *lowtoken, int *val);
+static int DecodeTime(char *str, int fmask, int *tmask,
+		   struct tm * tm, double *fsec);
+static int	DecodeTimezone(char *str, int *tzp);
+
+#define USE_DATE_CACHE 1
+#define ROUND_ALL 0
+
+int			mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
+
+char	   *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
+
+char	   *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
+"Thursday", "Friday", "Saturday", NULL};
+
+
+#define UTIME_MINYEAR (1901)
+#define UTIME_MINMONTH (12)
+#define UTIME_MINDAY (14)
+#define UTIME_MAXYEAR (2038)
+#define UTIME_MAXMONTH (01)
+#define UTIME_MAXDAY (18)
+
+#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \
+ || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \
+  || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \
+ && ((y < UTIME_MAXYEAR) \
+ || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \
+  || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY))))))
+
+
+int	DateStyle = 0;
+bool EuroDates= 0;
+int	CTimeZone= 0;
+
+
+/*****************************************************************************
+ *	 PRIVATE ROUTINES														 *
+ *****************************************************************************/
+
+/* definitions for squeezing values into "value" */
+#define ABS_SIGNBIT		(char) 0200
+#define VALMASK			(char) 0177
+#define NEG(n)			((n)|ABS_SIGNBIT)
+#define SIGNEDCHAR(c)	((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
+#define FROMVAL(tp)		(-SIGNEDCHAR((tp)->value) * 10) /* uncompress */
+#define TOVAL(tp, v)	((tp)->value = ((v) < 0? NEG((-(v))/10): (v)/10))
+
+/*
+ * to keep this table reasonably small, we divide the lexval for TZ and DTZ
+ * entries by 10 and truncate the text field at MAXTOKLEN characters.
+ * the text field is not guaranteed to be NULL-terminated.
+ */
+static datetkn datetktbl[] = {
+/*		text			token	lexval */
+	{EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
+	{"acsst", DTZ, 63},			/* Cent. Australia */
+	{"acst", TZ, 57},			/* Cent. Australia */
+	{DA_D, ADBC, AD},			/* "ad" for years >= 0 */
+	{"abstime", IGNOREFIELD, 0},		/* "abstime" for pre-v6.1 "Invalid
+								 * Abstime" */
+	{"adt", DTZ, NEG(18)},		/* Atlantic Daylight Time */
+	{"aesst", DTZ, 66},			/* E. Australia */
+	{"aest", TZ, 60},			/* Australia Eastern Std Time */
+	{"ahst", TZ, 60},			/* Alaska-Hawaii Std Time */
+	{"allballs", RESERV, DTK_ZULU},		/* 00:00:00 */
+	{"am", AMPM, AM},
+	{"apr", MONTH, 4},
+	{"april", MONTH, 4},
+	{"ast", TZ, NEG(24)},		/* Atlantic Std Time (Canada) */
+	{"at", IGNOREFIELD, 0},			/* "at" (throwaway) */
+	{"aug", MONTH, 8},
+	{"august", MONTH, 8},
+	{"awsst", DTZ, 54},			/* W. Australia */
+	{"awst", TZ, 48},			/* W. Australia */
+	{DB_C, ADBC, BC},			/* "bc" for years < 0 */
+	{"bst", TZ, 6},				/* British Summer Time */
+	{"bt", TZ, 18},				/* Baghdad Time */
+	{"cadt", DTZ, 63},			/* Central Australian DST */
+	{"cast", TZ, 57},			/* Central Australian ST */
+	{"cat", TZ, NEG(60)},		/* Central Alaska Time */
+	{"cct", TZ, 48},			/* China Coast */
+	{"cdt", DTZ, NEG(30)},		/* Central Daylight Time */
+	{"cet", TZ, 6},				/* Central European Time */
+	{"cetdst", DTZ, 12},		/* Central European Dayl.Time */
+	{"cst", TZ, NEG(36)},		/* Central Standard Time */
+	{DCURRENT, RESERV, DTK_CURRENT},	/* "current" is always now */
+	{"dec", MONTH, 12},
+	{"december", MONTH, 12},
+	{"dnt", TZ, 6},				/* Dansk Normal Tid */
+	{"dow", RESERV, DTK_DOW},	/* day of week */
+	{"doy", RESERV, DTK_DOY},	/* day of year */
+	{"dst", DTZMOD, 6},
+	{"east", TZ, NEG(60)},		/* East Australian Std Time */
+	{"edt", DTZ, NEG(24)},		/* Eastern Daylight Time */
+	{"eet", TZ, 12},			/* East. Europe, USSR Zone 1 */
+	{"eetdst", DTZ, 18},		/* Eastern Europe */
+	{EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
+#if USE_AUSTRALIAN_RULES
+	{"est", TZ, 60},			/* Australia Eastern Std Time */
+#else
+	{"est", TZ, NEG(30)},		/* Eastern Standard Time */
+#endif
+	{"feb", MONTH, 2},
+	{"february", MONTH, 2},
+	{"fri", DOW, 5},
+	{"friday", DOW, 5},
+	{"fst", TZ, 6},				/* French Summer Time */
+	{"fwt", DTZ, 12},			/* French Winter Time  */
+	{"gmt", TZ, 0},				/* Greenwish Mean Time */
+	{"gst", TZ, 60},			/* Guam Std Time, USSR Zone 9 */
+	{"hdt", DTZ, NEG(54)},		/* Hawaii/Alaska */
+	{"hmt", DTZ, 18},			/* Hellas ? ? */
+	{"hst", TZ, NEG(60)},		/* Hawaii Std Time */
+	{"idle", TZ, 72},			/* Intl. Date Line, East */
+	{"idlw", TZ, NEG(72)},		/* Intl. Date Line,,	est */
+	{LATE, RESERV, DTK_LATE},	/* "infinity" reserved for "late time" */
+	{INVALID, RESERV, DTK_INVALID},		/* "invalid" reserved for invalid
+										 * time */
+	{"ist", TZ, 12},			/* Israel */
+	{"it", TZ, 22},				/* Iran Time */
+	{"jan", MONTH, 1},
+	{"january", MONTH, 1},
+	{"jst", TZ, 54},			/* Japan Std Time,USSR Zone 8 */
+	{"jt", TZ, 45},				/* Java Time */
+	{"jul", MONTH, 7},
+	{"july", MONTH, 7},
+	{"jun", MONTH, 6},
+	{"june", MONTH, 6},
+	{"kst", TZ, 54},			/* Korea Standard Time */
+	{"ligt", TZ, 60},			/* From Melbourne, Australia */
+	{"mar", MONTH, 3},
+	{"march", MONTH, 3},
+	{"may", MONTH, 5},
+	{"mdt", DTZ, NEG(36)},		/* Mountain Daylight Time */
+	{"mest", DTZ, 12},			/* Middle Europe Summer Time */
+	{"met", TZ, 6},				/* Middle Europe Time */
+	{"metdst", DTZ, 12},		/* Middle Europe Daylight Time */
+	{"mewt", TZ, 6},			/* Middle Europe Winter Time */
+	{"mez", TZ, 6},				/* Middle Europe Zone */
+	{"mon", DOW, 1},
+	{"monday", DOW, 1},
+	{"mst", TZ, NEG(42)},		/* Mountain Standard Time */
+	{"mt", TZ, 51},				/* Moluccas Time */
+	{"ndt", DTZ, NEG(15)},		/* Nfld. Daylight Time */
+	{"nft", TZ, NEG(21)},		/* Newfoundland Standard Time */
+	{"nor", TZ, 6},				/* Norway Standard Time */
+	{"nov", MONTH, 11},
+	{"november", MONTH, 11},
+	{NOW, RESERV, DTK_NOW},		/* current transaction time */
+	{"nst", TZ, NEG(21)},		/* Nfld. Standard Time */
+	{"nt", TZ, NEG(66)},		/* Nome Time */
+	{"nzdt", DTZ, 78},			/* New Zealand Daylight Time */
+	{"nzst", TZ, 72},			/* New Zealand Standard Time */
+	{"nzt", TZ, 72},			/* New Zealand Time */
+	{"oct", MONTH, 10},
+	{"october", MONTH, 10},
+	{"on", IGNOREFIELD, 0},			/* "on" (throwaway) */
+	{"pdt", DTZ, NEG(42)},		/* Pacific Daylight Time */
+	{"pm", AMPM, PM},
+	{"pst", TZ, NEG(48)},		/* Pacific Standard Time */
+	{"sadt", DTZ, 63},			/* S. Australian Dayl. Time */
+	{"sast", TZ, 57},			/* South Australian Std Time */
+	{"sat", DOW, 6},
+	{"saturday", DOW, 6},
+	{"sep", MONTH, 9},
+	{"sept", MONTH, 9},
+	{"september", MONTH, 9},
+	{"set", TZ, NEG(6)},		/* Seychelles Time ?? */
+	{"sst", DTZ, 12},			/* Swedish Summer Time */
+	{"sun", DOW, 0},
+	{"sunday", DOW, 0},
+	{"swt", TZ, 6},				/* Swedish Winter Time	*/
+	{"thu", DOW, 4},
+	{"thur", DOW, 4},
+	{"thurs", DOW, 4},
+	{"thursday", DOW, 4},
+	{TODAY, RESERV, DTK_TODAY}, /* midnight */
+	{TOMORROW, RESERV, DTK_TOMORROW},	/* tomorrow midnight */
+	{"tue", DOW, 2},
+	{"tues", DOW, 2},
+	{"tuesday", DOW, 2},
+	{"undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid
+										 * time */
+	{"ut", TZ, 0},
+	{"utc", TZ, 0},
+	{"wadt", DTZ, 48},			/* West Australian DST */
+	{"wast", TZ, 42},			/* West Australian Std Time */
+	{"wat", TZ, NEG(6)},		/* West Africa Time */
+	{"wdt", DTZ, 54},			/* West Australian DST */
+	{"wed", DOW, 3},
+	{"wednesday", DOW, 3},
+	{"weds", DOW, 3},
+	{"wet", TZ, 0},				/* Western Europe */
+	{"wetdst", DTZ, 6},			/* Western Europe */
+	{"wst", TZ, 48},			/* West Australian Std Time */
+	{"ydt", DTZ, NEG(48)},		/* Yukon Daylight Time */
+	{YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
+	{"yst", TZ, NEG(54)},		/* Yukon Standard Time */
+	{"zp4", TZ, NEG(24)},		/* GMT +4  hours. */
+	{"zp5", TZ, NEG(30)},		/* GMT +5  hours. */
+	{"zp6", TZ, NEG(36)},		/* GMT +6  hours. */
+	{"z", RESERV, DTK_ZULU},	/* 00:00:00 */
+	{ZULU, RESERV, DTK_ZULU},	/* 00:00:00 */
+};
+
+static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
+
+
+
+#if USE_DATE_CACHE
+datetkn    *datecache[MAXDATEFIELDS] = {NULL};
+
+datetkn    *deltacache[MAXDATEFIELDS] = {NULL};
+
+#endif
+
+
+/*
+ * Calendar time to Julian date conversions.
+ * Julian date is commonly used in astronomical applications,
+ *	since it is numerically accurate and computationally simple.
+ * The algorithms here will accurately convert between Julian day
+ *	and calendar date for all non-negative Julian days
+ *	(i.e. from Nov 23, -4713 on).
+ *
+ * Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
+ *	University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
+ *
+ * Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
+ *	now at Aerospace Corp. (hi, Henry!)
+ *
+ * These routines will be used by other date/time packages - tgl 97/02/25
+ */
+
+/* Set the minimum year to one greater than the year of the first valid day
+ *	to avoid having to check year and day both. - tgl 97/05/08
+ */
+
+#define JULIAN_MINYEAR (-4713)
+#define JULIAN_MINMONTH (11)
+#define JULIAN_MINDAY (23)
+
+#define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \
+ || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \
+  || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY)))))
+
+int
+date2j(int y, int m, int d)
+{
+	int			m12 = (m - 14) / 12;
+
+	return ((1461 * (y + 4800 + m12)) / 4 + (367 * (m - 2 - 12 * (m12))) / 12
+			- (3 * ((y + 4900 + m12) / 100)) / 4 + d - 32075);
+}	/* date2j() */
+
+void
+j2date(int jd, int *year, int *month, int *day)
+{
+	int			j,
+				y,
+				m,
+				d;
+
+	int			i,
+				l,
+				n;
+
+	l = jd + 68569;
+	n = (4 * l) / 146097;
+	l -= (146097 * n + 3) / 4;
+	i = (4000 * (l + 1)) / 1461001;
+	l += 31 - (1461 * i) / 4;
+	j = (80 * l) / 2447;
+	d = l - (2447 * j) / 80;
+	l = j / 11;
+	m = (j + 2) - (12 * l);
+	y = 100 * (n - 49) + i + l;
+
+	*year = y;
+	*month = m;
+	*day = d;
+	return;
+}	/* j2date() */
+
+
+
+
+/*
+ * parse and convert date in timestr (the normal interface)
+ *
+ * Returns the number of seconds since epoch (J2000)
+ */
+
+/* ParseDateTime()
+ * Break string into tokens based on a date/time context.
+ */
+int
+ParseDateTime(char *timestr, char *lowstr,
+			  char **field, int *ftype, int maxfields, int *numfields)
+{
+	int			nf = 0;
+	char	   *cp = timestr;
+	char	   *lp = lowstr;
+
+#ifdef DATEDEBUG
+	printf("ParseDateTime- input string is %s\n", timestr);
+#endif
+	/* outer loop through fields */
+	while (*cp != '\0')
+	{
+		field[nf] = lp;
+
+		/* leading digit? then date or time */
+		if (isdigit(*cp) || (*cp == '.'))
+		{
+			*lp++ = *cp++;
+			while (isdigit(*cp))
+				*lp++ = *cp++;
+			/* time field? */
+			if (*cp == ':')
+			{
+				ftype[nf] = DTK_TIME;
+				while (isdigit(*cp) || (*cp == ':') || (*cp == '.'))
+					*lp++ = *cp++;
+
+			}
+			/* date field? allow embedded text month */
+			else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
+			{
+				ftype[nf] = DTK_DATE;
+				while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
+					*lp++ = tolower(*cp++);
+
+			}
+
+			/*
+			 * otherwise, number only and will determine year, month, or
+			 * day later
+			 */
+			else
+				ftype[nf] = DTK_NUMBER;
+
+		}
+
+		/*
+		 * text? then date string, month, day of week, special, or
+		 * timezone
+		 */
+		else if (isalpha(*cp))
+		{
+			ftype[nf] = DTK_STRING;
+			*lp++ = tolower(*cp++);
+			while (isalpha(*cp))
+				*lp++ = tolower(*cp++);
+
+			/* full date string with leading text month? */
+			if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
+			{
+				ftype[nf] = DTK_DATE;
+				while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
+					*lp++ = tolower(*cp++);
+			}
+
+			/* skip leading spaces */
+		}
+		else if (isspace(*cp))
+		{
+			cp++;
+			continue;
+
+			/* sign? then special or numeric timezone */
+		}
+		else if ((*cp == '+') || (*cp == '-'))
+		{
+			*lp++ = *cp++;
+			/* soak up leading whitespace */
+			while (isspace(*cp))
+				cp++;
+			/* numeric timezone? */
+			if (isdigit(*cp))
+			{
+				ftype[nf] = DTK_TZ;
+				*lp++ = *cp++;
+				while (isdigit(*cp) || (*cp == ':'))
+					*lp++ = *cp++;
+
+				/* special? */
+			}
+			else if (isalpha(*cp))
+			{
+				ftype[nf] = DTK_SPECIAL;
+				*lp++ = tolower(*cp++);
+				while (isalpha(*cp))
+					*lp++ = tolower(*cp++);
+
+				/* otherwise something wrong... */
+			}
+			else
+				return -1;
+
+			/* ignore punctuation but use as delimiter */
+		}
+		else if (ispunct(*cp))
+		{
+			cp++;
+			continue;
+
+		}
+		else
+			return -1;
+
+		/* force in a delimiter */
+		*lp++ = '\0';
+		nf++;
+		if (nf > MAXDATEFIELDS)
+			return -1;
+#ifdef DATEDEBUG
+		printf("ParseDateTime- set field[%d] to %s type %d\n", (nf - 1), field[nf - 1], ftype[nf - 1]);
+#endif
+	}
+
+	*numfields = nf;
+
+	return 0;
+}	/* ParseDateTime() */
+
+
+/* DecodeDateTime()
+ * Interpret previously parsed fields for general date and time.
+ * Return 0 if full date, 1 if only time, and -1 if problems.
+ *		External format(s):
+ *				"<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
+ *				"Fri Feb-7-1997 15:23:27"
+ *				"Feb-7-1997 15:23:27"
+ *				"2-7-1997 15:23:27"
+ *				"1997-2-7 15:23:27"
+ *				"1997.038 15:23:27"		(day of year 1-366)
+ *		Also supports input in compact time:
+ *				"970207 152327"
+ *				"97038 152327"
+ *
+ * Use the system-provided functions to get the current time zone
+ *	if not specified in the input string.
+ * If the date is outside the time_t system-supported time range,
+ *	then assume GMT time zone. - tgl 97/05/27
+ */
+int
+DecodeDateTime(char **field, int *ftype, int nf,
+			   int *dtype, struct tm * tm, double *fsec, int *tzp)
+{
+	int			fmask = 0,
+				tmask,
+				type;
+	int			i;
+	int			flen,
+				val;
+	int			mer = HR24;
+	int			bc = FALSE;
+
+	*dtype = DTK_DATE;
+	tm->tm_hour = 0;
+	tm->tm_min = 0;
+	tm->tm_sec = 0;
+	*fsec = 0;
+	tm->tm_isdst = -1;			/* don't know daylight savings time status
+								 * apriori */
+	if (tzp != NULL)
+		*tzp = 0;
+
+	for (i = 0; i < nf; i++)
+	{
+#ifdef DATEDEBUG
+		printf("DecodeDateTime- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
+#endif
+		switch (ftype[i])
+		{
+			case DTK_DATE:
+				if (DecodeDate(field[i], fmask, &tmask, tm) != 0)
+					return -1;
+				break;
+
+			case DTK_TIME:
+				if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
+					return -1;
+
+				/*
+				 * check upper limit on hours; other limits checked in
+				 * DecodeTime()
+				 */
+				if (tm->tm_hour > 23)
+					return -1;
+				break;
+
+			case DTK_TZ:
+				if (tzp == NULL)
+					return -1;
+				if (DecodeTimezone(field[i], tzp) != 0)
+					return -1;
+				tmask = DTK_M(TZ);
+				break;
+
+			case DTK_NUMBER:
+				flen = strlen(field[i]);
+
+				if (flen > 4)
+				{
+					if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
+						return -1;
+
+				}
+				else
+				{
+					if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec) != 0)
+						return -1;
+				}
+				break;
+
+			case DTK_STRING:
+			case DTK_SPECIAL:
+				type = DecodeSpecial(i, field[i], &val);
+#ifdef DATEDEBUG
+				printf("DecodeDateTime- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
+#endif
+				if (type == IGNOREFIELD)
+					continue;
+
+				tmask = DTK_M(type);
+				switch (type)
+				{
+					case RESERV:
+#ifdef DATEDEBUG
+						printf("DecodeDateTime- RESERV field %s value is %d\n", field[i], val);
+#endif
+						switch (val)
+						{
+
+							default:
+								*dtype = val;
+						}
+
+						break;
+
+					case MONTH:
+#ifdef DATEDEBUG
+						printf("DecodeDateTime- month field %s value is %d\n", field[i], val);
+#endif
+						tm->tm_mon = val;
+						break;
+
+						/*
+						 * daylight savings time modifier (solves "MET
+						 * DST" syntax)
+						 */
+					case DTZMOD:
+						tmask |= DTK_M(DTZ);
+						tm->tm_isdst = 1;
+						if (tzp == NULL)
+							return -1;
+						*tzp += val * 60;
+						break;
+
+					case DTZ:
+
+						/*
+						 * set mask for TZ here _or_ check for DTZ later
+						 * when getting default timezone
+						 */
+						tmask |= DTK_M(TZ);
+						tm->tm_isdst = 1;
+						if (tzp == NULL)
+							return -1;
+						*tzp = val * 60;
+						break;
+
+					case TZ:
+						tm->tm_isdst = 0;
+						if (tzp == NULL)
+							return -1;
+						*tzp = val * 60;
+						break;
+
+					case IGNOREFIELD:
+						break;
+
+					case AMPM:
+						mer = val;
+						break;
+
+					case ADBC:
+						bc = (val == BC);
+						break;
+
+					case DOW:
+						tm->tm_wday = val;
+						break;
+
+					default:
+						return -1;
+				}
+				break;
+
+			default:
+				return -1;
+		}
+
+#ifdef DATEDEBUG
+		printf("DecodeDateTime- field[%d] %s (%08x/%08x) value is %d\n",
+			   i, field[i], fmask, tmask, val);
+#endif
+
+		if (tmask & fmask)
+			return -1;
+		fmask |= tmask;
+	}
+
+	/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
+	if (bc)
+		tm->tm_year = -(tm->tm_year - 1);
+
+	if ((mer != HR24) && (tm->tm_hour > 12))
+		return -1;
+	if ((mer == AM) && (tm->tm_hour == 12))
+		tm->tm_hour = 0;
+	else if ((mer == PM) && (tm->tm_hour != 12))
+		tm->tm_hour += 12;
+
+#ifdef DATEDEBUG
+	printf("DecodeDateTime- mask %08x (%08x)", fmask, DTK_DATE_M);
+	printf(" set y%04d m%02d d%02d", tm->tm_year, tm->tm_mon, tm->tm_mday);
+	printf(" %02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
+#endif
+
+	if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) != DTK_DATE_M))
+		return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
+
+	/* timezone not specified? then find local timezone if possible */
+	if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) == DTK_DATE_M)
+		&& (tzp != NULL) && (!(fmask & DTK_M(TZ))))
+	{
+
+		/*
+		 * daylight savings time modifier but no standard timezone? then
+		 * error
+		 */
+		if (fmask & DTK_M(DTZMOD))
+			return -1;
+
+		if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
+		{
+#ifdef USE_POSIX_TIME
+			tm->tm_year -= 1900;
+			tm->tm_mon -= 1;
+			tm->tm_isdst = -1;
+			mktime(tm);
+			tm->tm_year += 1900;
+			tm->tm_mon += 1;
+
+#ifdef HAVE_INT_TIMEZONE
+			*tzp = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone);
+
+#else							/* !HAVE_INT_TIMEZONE */
+			*tzp = -(tm->tm_gmtoff);	/* tm_gmtoff is Sun/DEC-ism */
+#endif
+
+#else							/* !USE_POSIX_TIME */
+			*tzp = CTimeZone;
+#endif
+		}
+		else
+		{
+			tm->tm_isdst = 0;
+			*tzp = 0;
+		}
+	}
+
+	return 0;
+}	/* DecodeDateTime() */
+
+
+/* DecodeTimeOnly()
+ * Interpret parsed string as time fields only.
+ */
+int
+DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec)
+{
+	int			fmask,
+				tmask,
+				type;
+	int			i;
+	int			flen,
+				val;
+	int			mer = HR24;
+
+	*dtype = DTK_TIME;
+	tm->tm_hour = 0;
+	tm->tm_min = 0;
+	tm->tm_sec = 0;
+	tm->tm_isdst = -1;			/* don't know daylight savings time status
+								 * apriori */
+	*fsec = 0;
+
+	fmask = DTK_DATE_M;
+
+	for (i = 0; i < nf; i++)
+	{
+#ifdef DATEDEBUG
+		printf("DecodeTimeOnly- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
+#endif
+		switch (ftype[i])
+		{
+			case DTK_TIME:
+				if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
+					return -1;
+				break;
+
+			case DTK_NUMBER:
+				flen = strlen(field[i]);
+
+				if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
+					return -1;
+				break;
+
+			case DTK_STRING:
+			case DTK_SPECIAL:
+				type = DecodeSpecial(i, field[i], &val);
+#ifdef DATEDEBUG
+				printf("DecodeTimeOnly- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
+#endif
+				if (type == IGNOREFIELD)
+					continue;
+
+				tmask = DTK_M(type);
+				switch (type)
+				{
+					case RESERV:
+#ifdef DATEDEBUG
+						printf("DecodeTimeOnly- RESERV field %s value is %d\n", field[i], val);
+#endif
+						switch (val)
+						{
+
+							default:
+								return -1;
+						}
+
+						break;
+
+					case IGNOREFIELD:
+						break;
+
+					case AMPM:
+						mer = val;
+						break;
+
+					default:
+						return -1;
+				}
+				break;
+
+			default:
+				return -1;
+		}
+
+		if (tmask & fmask)
+			return -1;
+		fmask |= tmask;
+
+#ifdef DATEDEBUG
+		printf("DecodeTimeOnly- field[%d] %s value is %d\n", i, field[i], val);
+#endif
+	}
+
+#ifdef DATEDEBUG
+	printf("DecodeTimeOnly- mask %08x (%08x)", fmask, DTK_TIME_M);
+	printf(" %02d:%02d:%02d (%f)\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
+#endif
+
+	if ((mer != HR24) && (tm->tm_hour > 12))
+		return -1;
+	if ((mer == AM) && (tm->tm_hour == 12))
+		tm->tm_hour = 0;
+	else if ((mer == PM) && (tm->tm_hour != 12))
+		tm->tm_hour += 12;
+
+	if ((fmask & DTK_TIME_M) != DTK_TIME_M)
+		return -1;
+
+	return 0;
+}	/* DecodeTimeOnly() */
+
+
+/* DecodeDate()
+ * Decode date string which includes delimiters.
+ * Insist on a complete set of fields.
+ */
+static int
+DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
+{
+	double		fsec;
+
+	int			nf = 0;
+	int			i,
+				len;
+	int			type,
+				val,
+				dmask = 0;
+	char	   *field[MAXDATEFIELDS];
+
+	/* parse this string... */
+	while ((*str != '\0') && (nf < MAXDATEFIELDS))
+	{
+		/* skip field separators */
+		while (!isalnum(*str))
+			str++;
+
+		field[nf] = str;
+		if (isdigit(*str))
+		{
+			while (isdigit(*str))
+				str++;
+		}
+		else if (isalpha(*str))
+		{
+			while (isalpha(*str))
+				str++;
+		}
+
+		if (*str != '\0')
+			*str++ = '\0';
+		nf++;
+	}
+
+	/* don't allow too many fields */
+	if (nf > 3)
+		return -1;
+
+	*tmask = 0;
+
+	/* look first for text fields, since that will be unambiguous month */
+	for (i = 0; i < nf; i++)
+	{
+		if (isalpha(*field[i]))
+		{
+			type = DecodeSpecial(i, field[i], &val);
+			if (type == IGNOREFIELD)
+				continue;
+
+			dmask = DTK_M(type);
+			switch (type)
+			{
+				case MONTH:
+#ifdef DATEDEBUG
+					printf("DecodeDate- month field %s value is %d\n", field[i], val);
+#endif
+					tm->tm_mon = val;
+					break;
+
+				default:
+#ifdef DATEDEBUG
+					printf("DecodeDate- illegal field %s value is %d\n", field[i], val);
+#endif
+					return -1;
+			}
+			if (fmask & dmask)
+				return -1;
+
+			fmask |= dmask;
+			*tmask |= dmask;
+
+			/* mark this field as being completed */
+			field[i] = NULL;
+		}
+	}
+
+	/* now pick up remaining numeric fields */
+	for (i = 0; i < nf; i++)
+	{
+		if (field[i] == NULL)
+			continue;
+
+		if ((len = strlen(field[i])) <= 0)
+			return -1;
+
+		if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec) != 0)
+			return -1;
+
+		if (fmask & dmask)
+			return -1;
+
+		fmask |= dmask;
+		*tmask |= dmask;
+	}
+
+	return 0;
+}	/* DecodeDate() */
+
+
+/* DecodeTime()
+ * Decode time string which includes delimiters.
+ * Only check the lower limit on hours, since this same code
+ *	can be used to represent time spans.
+ */
+static int
+DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
+{
+	char	   *cp;
+
+	*tmask = DTK_TIME_M;
+
+	tm->tm_hour = strtol(str, &cp, 10);
+	if (*cp != ':')
+		return -1;
+	str = cp + 1;
+	tm->tm_min = strtol(str, &cp, 10);
+	if (*cp == '\0')
+	{
+		tm->tm_sec = 0;
+		*fsec = 0;
+
+	}
+	else if (*cp != ':')
+	{
+		return -1;
+
+	}
+	else
+	{
+		str = cp + 1;
+		tm->tm_sec = strtol(str, &cp, 10);
+		if (*cp == '\0')
+			*fsec = 0;
+		else if (*cp == '.')
+		{
+			str = cp;
+			*fsec = strtod(str, &cp);
+			if (cp == str)
+				return -1;
+		}
+		else
+			return -1;
+	}
+
+	/* do a sanity check */
+	if ((tm->tm_hour < 0)
+		|| (tm->tm_min < 0) || (tm->tm_min > 59)
+		|| (tm->tm_sec < 0) || (tm->tm_sec > 59))
+		return -1;
+
+	return 0;
+}	/* DecodeTime() */
+
+
+/* DecodeNumber()
+ * Interpret numeric field as a date value in context.
+ */
+static int
+DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
+{
+	int			val;
+	char	   *cp;
+
+	*tmask = 0;
+
+	val = strtol(str, &cp, 10);
+	if (cp == str)
+		return -1;
+	if (*cp == '.')
+	{
+		*fsec = strtod(cp, &cp);
+		if (*cp != '\0')
+			return -1;
+	}
+
+#ifdef DATEDEBUG
+	printf("DecodeNumber- %s is %d fmask=%08x tmask=%08x\n", str, val, fmask, *tmask);
+#endif
+
+	/* enough digits to be unequivocal year? */
+	if (flen == 4)
+	{
+#ifdef DATEDEBUG
+		printf("DecodeNumber- match %d (%s) as year\n", val, str);
+#endif
+		*tmask = DTK_M(YEAR);
+
+		/* already have a year? then see if we can substitute... */
+		if (fmask & DTK_M(YEAR))
+		{
+			if ((!(fmask & DTK_M(DAY)))
+				&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
+			{
+#ifdef DATEDEBUG
+				printf("DecodeNumber- misidentified year previously; swap with day %d\n", tm->tm_mday);
+#endif
+				tm->tm_mday = tm->tm_year;
+				*tmask = DTK_M(DAY);
+			}
+		}
+
+		tm->tm_year = val;
+
+		/* special case day of year? */
+	}
+	else if ((flen == 3) && (fmask & DTK_M(YEAR))
+			 && ((val >= 1) && (val <= 366)))
+	{
+		*tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
+		tm->tm_yday = val;
+		j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1),
+			   &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+
+		/* already have year? then could be month */
+	}
+	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
+			 && ((val >= 1) && (val <= 12)))
+	{
+#ifdef DATEDEBUG
+		printf("DecodeNumber- match %d (%s) as month\n", val, str);
+#endif
+		*tmask = DTK_M(MONTH);
+		tm->tm_mon = val;
+
+		/* no year and EuroDates enabled? then could be day */
+	}
+	else if ((EuroDates || (fmask & DTK_M(MONTH)))
+			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
+			 && ((val >= 1) && (val <= 31)))
+	{
+#ifdef DATEDEBUG
+		printf("DecodeNumber- match %d (%s) as day\n", val, str);
+#endif
+		*tmask = DTK_M(DAY);
+		tm->tm_mday = val;
+
+	}
+	else if ((!(fmask & DTK_M(MONTH)))
+			 && ((val >= 1) && (val <= 12)))
+	{
+#ifdef DATEDEBUG
+		printf("DecodeNumber- (2) match %d (%s) as month\n", val, str);
+#endif
+		*tmask = DTK_M(MONTH);
+		tm->tm_mon = val;
+
+	}
+	else if ((!(fmask & DTK_M(DAY)))
+			 && ((val >= 1) && (val <= 31)))
+	{
+#ifdef DATEDEBUG
+		printf("DecodeNumber- (2) match %d (%s) as day\n", val, str);
+#endif
+		*tmask = DTK_M(DAY);
+		tm->tm_mday = val;
+
+	}
+	else if (!(fmask & DTK_M(YEAR)))
+	{
+#ifdef DATEDEBUG
+		printf("DecodeNumber- (2) match %d (%s) as year\n", val, str);
+#endif
+		*tmask = DTK_M(YEAR);
+		tm->tm_year = val;
+		if (tm->tm_year < 70)
+			tm->tm_year += 2000;
+		else if (tm->tm_year < 100)
+			tm->tm_year += 1900;
+
+	}
+	else
+		return -1;
+
+	return 0;
+}	/* DecodeNumber() */
+
+
+/* DecodeNumberField()
+ * Interpret numeric string as a concatenated date field.
+ */
+static int
+DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
+{
+	char	   *cp;
+
+	/* yyyymmdd? */
+	if (len == 8)
+	{
+#ifdef DATEDEBUG
+		printf("DecodeNumberField- %s is 8 character date fmask=%08x tmask=%08x\n", str, fmask, *tmask);
+#endif
+
+		*tmask = DTK_DATE_M;
+
+		tm->tm_mday = atoi(str + 6);
+		*(str + 6) = '\0';
+		tm->tm_mon = atoi(str + 4);
+		*(str + 4) = '\0';
+		tm->tm_year = atoi(str + 0);
+
+		/* yymmdd or hhmmss? */
+	}
+	else if (len == 6)
+	{
+#ifdef DATEDEBUG
+		printf("DecodeNumberField- %s is 6 characters fmask=%08x tmask=%08x\n", str, fmask, *tmask);
+#endif
+		if (fmask & DTK_DATE_M)
+		{
+#ifdef DATEDEBUG
+			printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
+#endif
+			*tmask = DTK_TIME_M;
+			tm->tm_sec = atoi(str + 4);
+			*(str + 4) = '\0';
+			tm->tm_min = atoi(str + 2);
+			*(str + 2) = '\0';
+			tm->tm_hour = atoi(str + 0);
+
+		}
+		else
+		{
+#ifdef DATEDEBUG
+			printf("DecodeNumberField- %s is date field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
+#endif
+			*tmask = DTK_DATE_M;
+			tm->tm_mday = atoi(str + 4);
+			*(str + 4) = '\0';
+			tm->tm_mon = atoi(str + 2);
+			*(str + 2) = '\0';
+			tm->tm_year = atoi(str + 0);
+		}
+
+	}
+	else if (strchr(str, '.') != NULL)
+	{
+#ifdef DATEDEBUG
+		printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
+#endif
+		*tmask = DTK_TIME_M;
+		tm->tm_sec = strtod((str + 4), &cp);
+		if (cp == (str + 4))
+			return -1;
+		if (*cp == '.')
+			*fsec = strtod(cp, NULL);
+		*(str + 4) = '\0';
+		tm->tm_min = strtod((str + 2), &cp);
+		*(str + 2) = '\0';
+		tm->tm_hour = strtod((str + 0), &cp);
+
+	}
+	else
+		return -1;
+
+	return 0;
+}	/* DecodeNumberField() */
+
+
+/* DecodeTimezone()
+ * Interpret string as a numeric timezone.
+ */
+static int
+DecodeTimezone(char *str, int *tzp)
+{
+	int			tz;
+	int			hr,
+				min;
+	char	   *cp;
+	int			len;
+
+	/* assume leading character is "+" or "-" */
+	hr = strtol((str + 1), &cp, 10);
+
+	/* explicit delimiter? */
+	if (*cp == ':')
+	{
+		min = strtol((cp + 1), &cp, 10);
+
+		/* otherwise, might have run things together... */
+	}
+	else if ((*cp == '\0') && ((len = strlen(str)) > 3))
+	{
+		min = strtol((str + len - 2), &cp, 10);
+		*(str + len - 2) = '\0';
+		hr = strtol((str + 1), &cp, 10);
+
+	}
+	else
+		min = 0;
+
+	tz = (hr * 60 + min) * 60;
+	if (*str == '-')
+		tz = -tz;
+
+	*tzp = -tz;
+	return *cp != '\0';
+}	/* DecodeTimezone() */
+
+
+/* DecodeSpecial()
+ * Decode text string using lookup table.
+ * Implement a cache lookup since it is likely that dates
+ *	will be related in format.
+ */
+static int
+DecodeSpecial(int field, char *lowtoken, int *val)
+{
+	int			type;
+	datetkn    *tp;
+
+#if USE_DATE_CACHE
+	if ((datecache[field] != NULL)
+		&& (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0))
+		tp = datecache[field];
+	else
+	{
+#endif
+		tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
+#if USE_DATE_CACHE
+	}
+	datecache[field] = tp;
+#endif
+	if (tp == NULL)
+	{
+		type = IGNOREFIELD;
+		*val = 0;
+	}
+	else
+	{
+		type = tp->type;
+		switch (type)
+		{
+			case TZ:
+			case DTZ:
+			case DTZMOD:
+				*val = FROMVAL(tp);
+				break;
+
+			default:
+				*val = tp->value;
+				break;
+		}
+	}
+
+	return type;
+}	/* DecodeSpecial() */
+
+
+
+/* datebsearch()
+ * Binary search -- from Knuth (6.2.1) Algorithm B.  Special case like this
+ * is WAY faster than the generic bsearch().
+ */
+static datetkn *
+datebsearch(char *key, datetkn *base, unsigned int nel)
+{
+	datetkn    *last = base + nel - 1,
+			   *position;
+	int			result;
+
+	while (last >= base)
+	{
+		position = base + ((last - base) >> 1);
+		result = key[0] - position->token[0];
+		if (result == 0)
+		{
+			result = strncmp(key, position->token, TOKMAXLEN);
+			if (result == 0)
+				return position;
+		}
+		if (result < 0)
+			last = position - 1;
+		else
+			base = position + 1;
+	}
+	return NULL;
+}
+
+
+
Index: trunk/src/oleaut32/parsedt.h
===================================================================
--- trunk/src/oleaut32/parsedt.h	(revision 631)
+++ trunk/src/oleaut32/parsedt.h	(revision 631)
@@ -0,0 +1,374 @@
+/*
+PostgreSQL Data Base Management System (formerly known as Postgres, then
+as Postgres95).
+
+Copyright (c) 1994-7 Regents of the University of California
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose, without fee, and without a written agreement
+is hereby granted, provided that the above copyright notice and this
+paragraph and the following two paragraphs appear in all copies.
+
+IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+*/
+/*-------------------------------------------------------------------------
+ *
+ * dt.h--
+ *	  Definitions for the date/time and other date/time support code.
+ *	  The support code is shared with other date data types,
+ *	   including abstime, reltime, date, and time.
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parsedt.h,v 1.1 1999-08-22 22:07:37 sandervl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef DT_H
+#define DT_H
+
+#include <time.h>
+#include <math.h>
+
+/* We have to include stdlib.h here because it defines many of these macros
+   on some platforms, and we only want our definitions used if stdlib.h doesn't
+   have its own.
+*/
+
+#include <stdlib.h>
+
+/* ----------------------------------------------------------------
+ *				Section 1:	bool, true, false, TRUE, FALSE
+ * ----------------------------------------------------------------
+ */
+/*
+ * bool --
+ *		Boolean value, either true or false.
+ *
+ */
+#define false	((char) 0)
+#define true	((char) 1)
+//#ifndef __cplusplus
+#ifndef bool
+typedef char bool;
+#endif   /* ndef bool */
+//#endif	 /* not C++ */
+typedef bool *BoolPtr;
+
+#ifndef TRUE
+#define TRUE	1
+#endif	 /* TRUE */
+
+#ifndef FALSE
+#define FALSE	0
+#endif	 /* FALSE */
+
+
+
+/* ----------------------------------------------------------------
+ *				Section 3:	standard system types
+ * ----------------------------------------------------------------
+ */
+
+/*
+ * intN --
+ *		Signed integer, EXACTLY N BITS IN SIZE,
+ *		used for numerical computations and the
+ *		frontend/backend protocol.
+ */
+typedef signed char int8;		/* == 8 bits */
+typedef signed short int16;		/* == 16 bits */
+typedef signed int int32;		/* == 32 bits */
+
+/*
+ * uintN --
+ *		Unsigned integer, EXACTLY N BITS IN SIZE,
+ *		used for numerical computations and the
+ *		frontend/backend protocol.
+ */
+typedef unsigned char uint8;	/* == 8 bits */
+typedef unsigned short uint16;	/* == 16 bits */
+typedef unsigned int uint32;	/* == 32 bits */
+
+/*
+ * floatN --
+ *		Floating point number, AT LEAST N BITS IN SIZE,
+ *		used for numerical computations.
+ *
+ *		Since sizeof(floatN) may be > sizeof(char *), always pass
+ *		floatN by reference.
+ */
+typedef float float32data;
+typedef double float64data;
+typedef float *float32;
+typedef double *float64;
+
+/*
+ * boolN --
+ *		Boolean value, AT LEAST N BITS IN SIZE.
+ */
+typedef uint8 bool8;			/* >= 8 bits */
+typedef uint16 bool16;			/* >= 16 bits */
+typedef uint32 bool32;			/* >= 32 bits */
+
+
+/* Date/Time Configuration
+ *
+ * Constants to pass info from runtime environment:
+ *	USE_POSTGRES_DATES specifies traditional postgres format for output.
+ *	USE_ISO_DATES specifies ISO-compliant format for output.
+ *	USE_SQL_DATES specified Oracle/Ingres-compliant format for output.
+ *	USE_GERMAN_DATES specifies German-style dd.mm/yyyy date format.
+ *
+ * DateStyle specifies preference for date formatting for output.
+ * EuroDates if client prefers dates interpreted and written w/European conventions.
+ *
+ * HasCTZSet if client timezone is specified by client.
+ * CDayLight is the apparent daylight savings time status.
+ * CTimeZone is the timezone offset in seconds.
+ * CTZName is the timezone label.
+ */
+
+#define USE_POSTGRES_DATES		0
+#define USE_ISO_DATES			1
+#define USE_SQL_DATES			2
+#define USE_GERMAN_DATES		3
+
+extern int	DateStyle;
+extern bool EuroDates;
+extern int	CTimeZone;
+
+typedef double float8;
+
+struct varlena
+{
+	int		vl_len;
+	char		vl_dat[1];
+};
+
+typedef struct varlena text;
+
+
+
+typedef int AbsoluteTime;
+typedef int RelativeTime;
+
+/*
+ * Note a leap year is one that is a multiple of 4
+ * but not of a 100.  Except if it is a multiple of
+ * 400 then it is a leap year.
+ */
+#define isleap(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
+
+/*
+ * DateTime represents absolute time.
+ * TimeSpan represents delta time. Keep track of months (and years)
+ *	separately since the elapsed time spanned is unknown until instantiated
+ *	relative to an absolute time.
+ *
+ * Note that Postgres uses "time interval" to mean a bounded interval,
+ *	consisting of a beginning and ending time, not a time span - thomas 97/03/20
+ */
+
+typedef double DateTime;
+
+typedef struct
+{
+	double		time;			/* all time units other than months and
+								 * years */
+	int		month;			/* months and years, after time for
+								 * alignment */
+} TimeSpan;
+
+
+/* ----------------------------------------------------------------
+ *				time types + support macros
+ *
+ * String definitions for standard time quantities.
+ *
+ * These strings are the defaults used to form output time strings.
+ * Other alternate forms are hardcoded into token tables in dt.c.
+ * ----------------------------------------------------------------
+ */
+
+#define DAGO			"ago"
+#define DCURRENT		"current"
+#define EPOCH			"epoch"
+#define INVALID			"invalid"
+#define EARLY			"-infinity"
+#define LATE			"infinity"
+#define NOW				"now"
+#define TODAY			"today"
+#define TOMORROW		"tomorrow"
+#define YESTERDAY		"yesterday"
+#define ZULU			"zulu"
+
+#define DMICROSEC		"usecond"
+#define DMILLISEC		"msecond"
+#define DSECOND			"second"
+#define DMINUTE			"minute"
+#define DHOUR			"hour"
+#define DDAY			"day"
+#define DWEEK			"week"
+#define DMONTH			"month"
+#define DQUARTER		"quarter"
+#define DYEAR			"year"
+#define DDECADE			"decade"
+#define DCENTURY		"century"
+#define DMILLENIUM		"millenium"
+#define DA_D			"ad"
+#define DB_C			"bc"
+#define DTIMEZONE		"timezone"
+
+/*
+ * Fundamental time field definitions for parsing.
+ *
+ *	Meridian:  am, pm, or 24-hour style.
+ *	Millenium: ad, bc
+ */
+
+#define AM		0
+#define PM		1
+#define HR24	2
+
+#define AD		0
+#define BC		1
+
+/*
+ * Fields for time decoding.
+ * Can't have more of these than there are bits in an unsigned int
+ *	since these are turned into bit masks during parsing and decoding.
+ */
+
+#define RESERV	0
+#define MONTH	1
+#define YEAR	2
+#define DAY		3
+#define TIMES	4				/* not used - thomas 1997-07-14 */
+#define TZ		5
+#define DTZ		6
+#define DTZMOD	7
+#define IGNOREFIELD	8
+#define AMPM	9
+#define HOUR	10
+#define MINUTE	11
+#define SECOND	12
+#define DOY		13
+#define DOW		14
+#define UNITS	15
+#define ADBC	16
+/* these are only for relative dates */
+#define AGO		17
+#define ABS_BEFORE		18
+#define ABS_AFTER		19
+
+/*
+ * Token field definitions for time parsing and decoding.
+ * These need to fit into the datetkn table type.
+ * At the moment, that means keep them within [-127,127].
+ * These are also used for bit masks in DecodeDateDelta()
+ *	so actually restrict them to within [0,31] for now.
+ * - thomas 97/06/19
+ * Not all of these fields are used for masks in DecodeDateDelta
+ *	so allow some larger than 31. - thomas 1997-11-17
+ */
+
+#define DTK_NUMBER		0
+#define DTK_STRING		1
+
+#define DTK_DATE		2
+#define DTK_TIME		3
+#define DTK_TZ			4
+#define DTK_AGO			5
+
+#define DTK_SPECIAL		6
+#define DTK_INVALID		7
+#define DTK_CURRENT		8
+#define DTK_EARLY		9
+#define DTK_LATE		10
+#define DTK_EPOCH		11
+#define DTK_NOW			12
+#define DTK_YESTERDAY	13
+#define DTK_TODAY		14
+#define DTK_TOMORROW	15
+#define DTK_ZULU		16
+
+#define DTK_DELTA		17
+#define DTK_SECOND		18
+#define DTK_MINUTE		19
+#define DTK_HOUR		20
+#define DTK_DAY			21
+#define DTK_WEEK		22
+#define DTK_MONTH		23
+#define DTK_QUARTER		24
+#define DTK_YEAR		25
+#define DTK_DECADE		26
+#define DTK_CENTURY		27
+#define DTK_MILLENIUM	28
+#define DTK_MILLISEC	29
+#define DTK_MICROSEC	30
+
+#define DTK_DOW			32
+#define DTK_DOY			33
+#define DTK_TZ_HOUR		34
+#define DTK_TZ_MINUTE	35
+
+/*
+ * Bit mask definitions for time parsing.
+ */
+
+#define DTK_M(t)		(0x01 << (t))
+
+#define DTK_DATE_M		(DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
+#define DTK_TIME_M		(DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND))
+
+#define MAXDATELEN		47		/* maximum possible length of an input
+								 * date string */
+#define MAXDATEFIELDS	25		/* maximum possible number of fields in a
+								 * date string */
+#define TOKMAXLEN		10		/* only this many chars are stored in
+								 * datetktbl */
+
+/* keep this struct small; it gets used a lot */
+typedef struct
+{
+#if defined(_AIX)
+	char	   *token;
+#else
+	char		token[TOKMAXLEN];
+#endif	 /* _AIX */
+	char		type;
+	char		value;			/* this may be unsigned, alas */
+} datetkn;
+
+
+
+/*
+ * dt.c prototypes
+ */
+
+
+void j2date(int jd, int *year, int *month, int *day);
+int	date2j(int year, int month, int day);
+
+int ParseDateTime(char *timestr, char *lowstr,
+			  char **field, int *ftype, int maxfields, int *numfields);
+int DecodeDateTime(char **field, int *ftype,
+			 int nf, int *dtype, struct tm * tm, double *fsec, int *tzp);
+
+int DecodeTimeOnly(char **field, int *ftype, int nf,
+			   int *dtype, struct tm * tm, double *fsec);
+
+
+#endif	 /* DT_H */
Index: trunk/src/oleaut32/safearray.cpp
===================================================================
--- trunk/src/oleaut32/safearray.cpp	(revision 631)
+++ trunk/src/oleaut32/safearray.cpp	(revision 631)
@@ -0,0 +1,1003 @@
+/*************************************************************************
+ * OLE Automation
+ * SafeArray Implementation
+ *
+ * This file contains the implementation of the SafeArray interface.
+ *
+ * Copyright 1999 Sylvain St-Germain
+ * Copyright 1999 Sander van Leeuwen (WINE OS/2 Port 990815)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+#include "oleaut32.h"
+#include <stdio.h>
+#include <string.h>
+#include "windef.h"
+#include "winerror.h"
+#include "winbase.h"
+#include "oleauto.h"
+#include "wine/obj_base.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+/* Localy used methods */
+static INT  
+endOfDim(LONG *coor, SAFEARRAYBOUND *mat, LONG dim, LONG realDim);
+
+static ULONG   
+calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
+
+static BOOL  
+isPointer(USHORT feature);
+
+static INT   
+getFeatures(VARTYPE vt);
+
+static BOOL  
+validCoordinate(LONG *coor, SAFEARRAY *psa);
+
+static BOOL  
+resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
+
+static BOOL  
+validArg(SAFEARRAY *psa);
+
+static ULONG   
+getArraySize(SAFEARRAY *psa);
+
+static HRESULT 
+duplicateData(SAFEARRAY *psa, SAFEARRAY **ppsaOut);
+
+/* Association between VARTYPE and their size.
+   A size of zero is defined for the unsupported types.  */
+
+#define VARTYPE_NOT_SUPPORTED 0
+const static ULONG VARTYPE_SIZE[] =
+{
+  /* this is taken from wtypes.h.  Only [S]es are supported by the SafeArray */
+VARTYPE_NOT_SUPPORTED,	/* VT_EMPTY    [V]   [P]    nothing			*/
+VARTYPE_NOT_SUPPORTED,	/* VT_NULL     [V]   [P]    SQL style Nul	*/
+2,	                    /* VT_I2       [V][T][P][S] 2 byte signed int */
+4, 	                    /* VT_I4       [V][T][P][S] 4 byte signed int */
+4, 	                    /* VT_R4       [V][T][P][S] 4 byte real	*/
+8,	                    /* VT_R8       [V][T][P][S] 8 byte real	*/
+8,                      /* VT_CY       [V][T][P][S] currency */
+8,	                    /* VT_DATE     [V][T][P][S] date */
+4,	                    /* VT_BSTR     [V][T][P][S] OLE Automation string*/
+4,	                    /* VT_DISPATCH [V][T][P][S] IDispatch *	*/
+4,                      /* VT_ERROR    [V][T]   [S] SCODE	*/
+4,	                    /* VT_BOOL     [V][T][P][S] True=-1, False=0*/
+24,                     /* VT_VARIANT  [V][T][P][S] VARIANT *	*/
+4,	                    /* VT_UNKNOWN  [V][T]   [S] IUnknown * */
+16,	                    /* VT_DECIMAL  [V][T]   [S] 16 byte fixed point	*/
+VARTYPE_NOT_SUPPORTED,                         /* no VARTYPE here..... */
+VARTYPE_NOT_SUPPORTED,	/* VT_I1          [T]       signed char	*/
+1,	                    /* VT_UI1      [V][T][P][S] unsigned char			*/
+VARTYPE_NOT_SUPPORTED,	/* VT_UI2         [T][P]    unsigned short	*/
+VARTYPE_NOT_SUPPORTED,	/* VT_UI4         [T][P]    unsigned short	*/
+VARTYPE_NOT_SUPPORTED,	/* VT_I8          [T][P]    signed 64-bit int			*/
+VARTYPE_NOT_SUPPORTED,	/* VT_UI8         [T][P]    unsigned 64-bit int		*/
+VARTYPE_NOT_SUPPORTED,	/* VT_INT         [T]       signed machine int		*/
+VARTYPE_NOT_SUPPORTED,	/* VT_UINT        [T]       unsigned machine int	*/
+VARTYPE_NOT_SUPPORTED,	/* VT_VOID        [T]       C style void			*/
+VARTYPE_NOT_SUPPORTED,	/* VT_HRESULT     [T]       Standard return type	*/
+VARTYPE_NOT_SUPPORTED,	/* VT_PTR         [T]       pointer type			*/
+VARTYPE_NOT_SUPPORTED,	/* VT_SAFEARRAY   [T]       (use VT_ARRAY in VARIANT)*/
+VARTYPE_NOT_SUPPORTED,	/* VT_CARRAY      [T]       C style array			*/
+VARTYPE_NOT_SUPPORTED,	/* VT_USERDEFINED [T]       user defined type			*/
+VARTYPE_NOT_SUPPORTED,	/* VT_LPSTR       [T][P]    null terminated string	*/
+VARTYPE_NOT_SUPPORTED,	/* VT_LPWSTR      [T][P]    wide null term string		*/
+VARTYPE_NOT_SUPPORTED,	/* VT_FILETIME       [P]    FILETIME			*/
+VARTYPE_NOT_SUPPORTED,	/* VT_BLOB           [P]    Length prefixed bytes */
+VARTYPE_NOT_SUPPORTED,	/* VT_STREAM         [P]    Name of stream follows		*/
+VARTYPE_NOT_SUPPORTED,	/* VT_STORAGE        [P]    Name of storage follows	*/
+VARTYPE_NOT_SUPPORTED,	/* VT_STREAMED_OBJECT[P]    Stream contains an object*/
+VARTYPE_NOT_SUPPORTED,	/* VT_STORED_OBJECT  [P]    Storage contains object*/
+VARTYPE_NOT_SUPPORTED,	/* VT_BLOB_OBJECT    [P]    Blob contains an object*/
+VARTYPE_NOT_SUPPORTED,	/* VT_CF             [P]    Clipboard format			*/
+VARTYPE_NOT_SUPPORTED,	/* VT_CLSID          [P]    A Class ID			*/
+VARTYPE_NOT_SUPPORTED,	/* VT_VECTOR         [P]    simple counted array		*/
+VARTYPE_NOT_SUPPORTED,	/* VT_ARRAY    [V]          SAFEARRAY*			*/
+VARTYPE_NOT_SUPPORTED 	/* VT_BYREF    [V]          void* for local use	*/
+};
+
+const static int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(ULONG);
+
+
+/*************************************************************************
+ * Allocate the appropriate amount of memory for the SafeArray descriptor
+ */
+HRESULT WINAPI SafeArrayAllocDescriptor( 
+  UINT    cDims, 
+  SAFEARRAY **ppsaOut) 
+{
+  SAFEARRAYBOUND *sab;
+  LONG allocSize = 0;
+
+  /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
+                                             ( in SAFEARRAY struct */
+  allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
+
+  /* Allocate memory for SAFEARRAY struc */
+  if(( (*ppsaOut)=(SAFEARRAY *)HeapAlloc( 
+        GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
+    return(E_UNEXPECTED);
+  }
+  TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
+
+  return(S_OK);
+}
+
+/*************************************************************************
+ * Allocate the appropriate amount of data for the SafeArray data
+ */
+HRESULT WINAPI SafeArrayAllocData(
+  SAFEARRAY *psa) 
+{
+  ULONG  ulWholeArraySize;   /* to store the size of the whole thing */
+
+  if(! validArg(psa)) 
+    return E_INVALIDARG;
+
+  ulWholeArraySize = getArraySize(psa);
+
+  /* Allocate memory for the data itself */
+  if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
+        psa->cbElements*ulWholeArraySize)) == NULL)
+    return(E_UNEXPECTED);
+
+  TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n", 
+    psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
+
+  return(S_OK);
+}
+
+/*************************************************************************
+ * Create a SafeArray object by encapsulating AllocDescriptor and AllocData 
+ */
+SAFEARRAY* WINAPI SafeArrayCreate(
+  VARTYPE        vt, 
+  UINT         cDims, 
+  SAFEARRAYBOUND *rgsabound)
+{
+  SAFEARRAY *psa;
+  HRESULT   hRes;
+  USHORT    cDim;
+
+  /* Validate supported VARTYPE */
+  if ( (vt >= LAST_VARTYPE) ||
+       ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
+    return NULL;
+
+  /* Allocate memory for the array descriptor */
+  if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
+    return NULL;
+
+  /* setup data members... */ 
+  psa->cDims     = cDims;
+  psa->fFeatures = getFeatures(vt);
+  psa->cLocks    = 0;
+  psa->pvData    = NULL;
+  psa->cbElements= VARTYPE_SIZE[vt];
+
+  /* Invert the bounds ... */
+  for(cDim=0; cDim < psa->cDims; cDim++) {
+    psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
+    psa->rgsabound[cDim].lLbound   = rgsabound[psa->cDims-cDim-1].lLbound;
+  }
+
+  /* allocate memory for the data... */ 
+  if( FAILED( hRes = SafeArrayAllocData(psa))) {
+    SafeArrayDestroyDescriptor(psa); 
+    ERR("() : Failed to allocate the Safe Array data\n");
+    return NULL;
+  }
+
+  return(psa); 
+}
+
+/*************************************************************************
+ * Frees the memory associated with the descriptor.
+ */
+HRESULT WINAPI SafeArrayDestroyDescriptor(
+  SAFEARRAY *psa)
+{
+  /* Check for lockness before to free... */
+  if(psa->cLocks > 0) 
+    return DISP_E_ARRAYISLOCKED;
+
+  /* The array is unlocked, then, deallocate memory */
+  if(HeapFree( GetProcessHeap(), 0, psa) == FALSE) 
+    return E_UNEXPECTED;
+  
+  return(S_OK);
+}
+
+
+/*************************************************************************
+ * Increment the lock counter
+ *
+ * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
+ * only when psa->cLocks is > 0... I don't get it since pvData is allocated 
+ * before the array is locked, therefore  
+ */
+HRESULT WINAPI SafeArrayLock(
+  SAFEARRAY *psa)
+{
+  if(! validArg(psa))     
+    return E_INVALIDARG;
+
+  psa->cLocks++;
+
+  return(S_OK);
+}
+
+/*************************************************************************
+ * Decrement the lock counter
+ */
+HRESULT WINAPI SafeArrayUnlock(
+  SAFEARRAY *psa)
+{
+  if(! validArg(psa)) 
+    return E_INVALIDARG;
+
+  if (psa->cLocks > 0) 
+    psa->cLocks--;
+
+  return(S_OK);
+}
+
+
+/*************************************************************************
+ * Set the data at the given coordinate
+ */
+HRESULT WINAPI SafeArrayPutElement(
+  SAFEARRAY *psa, 
+  LONG      *rgIndices, 
+  void      *pv)
+{
+  ULONG stepCountInSAData     = 0;    /* Number of array item to skip to get to 
+                                         the desired one... */
+  PVOID elementStorageAddress = NULL; /* Adress to store the data */
+  BSTR  pbstrReAllocStr     = NULL; /* BSTR reallocated */
+
+  /* Validate the index given */
+  if(! validCoordinate(rgIndices, psa)) 
+    return DISP_E_BADINDEX;
+  if(! validArg(psa))
+    return E_INVALIDARG;
+
+  if( SafeArrayLock(psa) == S_OK) {
+
+    /* Figure out the number of items to skip */
+    stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
+  
+    /* Figure out the number of byte to skip ... */
+    elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
+  
+    if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
+
+      *((VOID**)elementStorageAddress) = *(VOID**)pv; 
+      IUnknown_AddRef( *(IUnknown**)pv);
+
+    } else { 
+
+      if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
+
+        if((pbstrReAllocStr = SysAllocString( (OLECHAR*)pv )) == NULL) {
+          SafeArrayUnlock(psa);  
+          return E_OUTOFMEMORY;
+        } else 
+          *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
+
+      } else /* dupplicate the memory */
+        memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
+    }
+
+  } else {
+    ERR("SafeArray: Cannot lock array....\n");
+    return E_UNEXPECTED; /* UNDOC error condition */
+  }
+
+  TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
+  return SafeArrayUnlock(psa);  
+}
+
+
+/*************************************************************************
+ * Return the data element corresponding the the given coordinate
+ */
+HRESULT WINAPI SafeArrayGetElement(
+  SAFEARRAY *psa, 
+  LONG      *rgIndices, 
+  void      *pv)
+{
+  ULONG stepCountInSAData     = 0;    /* Number of array item to skip to get to 
+                                         the desired one... */
+  PVOID elementStorageAddress = NULL; /* Adress to store the data */
+  BSTR  pbstrReturnedStr    = NULL; /* BSTR reallocated */
+
+  if(! validArg(psa)) 
+    return E_INVALIDARG;
+  
+  if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
+    return(DISP_E_BADINDEX);
+
+  if( SafeArrayLock(psa) == S_OK) {
+
+    /* Figure out the number of items to skip */
+    stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
+  
+    /* Figure out the number of byte to skip ... */
+    elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
+  
+    if( psa->fFeatures == FADF_BSTR) {           /* reallocate the obj */
+      if( (pbstrReturnedStr = 
+          SysAllocString( *(OLECHAR**)elementStorageAddress )) == NULL) {
+        SafeArrayUnlock(psa);
+        return E_OUTOFMEMORY;
+      } else 
+        *((BSTR*)pv) = pbstrReturnedStr; 
+        
+    } else if( isPointer(psa->fFeatures) )       /* simply copy the pointer */
+       pv = *((PVOID*)elementStorageAddress); 
+    else                                         /* copy the bytes */
+      memcpy(pv, elementStorageAddress, SafeArrayGetElemsize(psa) );
+
+  } else {
+    ERR("SafeArray: Cannot lock array....\n");
+    return E_UNEXPECTED; /* UNDOC error condition */
+  }
+
+  return( SafeArrayUnlock(psa) );  
+}
+
+/*************************************************************************
+ * return the UP bound for a given array dimension
+ */
+HRESULT WINAPI SafeArrayGetUBound(
+  SAFEARRAY *psa, 
+  UINT    nDim,
+  LONG      *plUbound)
+{
+  if(! validArg(psa))   
+    return E_INVALIDARG;
+
+  if(nDim > psa->cDims) 
+    return DISP_E_BADINDEX;
+
+  *plUbound = psa->rgsabound[nDim-1].lLbound + 
+              psa->rgsabound[nDim-1].cElements - 1;
+
+  return S_OK;
+}
+
+/*************************************************************************
+ * Return the LO bound for a given array dimension 
+ */
+HRESULT WINAPI SafeArrayGetLBound(
+  SAFEARRAY *psa,
+  UINT    nDim, 
+  LONG      *plLbound)
+{
+  if(! validArg(psa))   
+    return E_INVALIDARG;
+
+  if(nDim > psa->cDims) 
+    return DISP_E_BADINDEX;
+
+  *plLbound = psa->rgsabound[nDim-1].lLbound;
+  return S_OK;
+}
+
+/*************************************************************************
+ * returns the number of dimension in the array
+ */
+UINT WINAPI SafeArrayGetDim(
+  SAFEARRAY * psa)
+{ 
+  /*
+   * A quick test in Windows shows that the behavior here for an invalid
+   * pointer is to return 0.
+   */
+  if(! validArg(psa)) 
+    return 0;
+
+  return psa->cDims;
+}
+
+/*************************************************************************
+ * Return the size of the element in the array
+ */
+UINT WINAPI SafeArrayGetElemsize(
+  SAFEARRAY * psa)
+{ 
+  /*
+   * A quick test in Windows shows that the behavior here for an invalid
+   * pointer is to return 0.
+   */
+  if(! validArg(psa)) 
+    return 0;
+
+  return psa->cbElements;
+}
+
+/*************************************************************************
+ * increment the access count and return the data 
+ */
+HRESULT WINAPI SafeArrayAccessData(
+  SAFEARRAY *psa, 
+  void      **ppvData)
+{ 
+  HRESULT hRes;
+
+  if(! validArg(psa)) 
+    return E_INVALIDARG;
+
+  hRes = SafeArrayLock(psa);
+
+  switch (hRes) {
+    case S_OK: 
+      (*ppvData) = psa->pvData;
+      break;
+    case E_INVALIDARG:
+      (*ppvData) = NULL;
+      return E_INVALIDARG;
+  }
+  
+  return S_OK;
+}
+
+
+/*************************************************************************
+ * Decrement the access count
+ */
+HRESULT WINAPI SafeArrayUnaccessData(
+  SAFEARRAY * psa)
+{ 
+  if(! validArg(psa)) 
+    return E_INVALIDARG;
+
+  return(SafeArrayUnlock(psa));
+}
+
+/************************************************************************ 
+ * Return a pointer to the element at rgIndices
+ */
+HRESULT WINAPI SafeArrayPtrOfIndex(
+  SAFEARRAY *psa, 
+  LONG      *rgIndices, 
+  void      **ppvData)
+{ 
+  ULONG stepCountInSAData     = 0;    /* Number of array item to skip to get to 
+                                         the desired one... */
+
+  if(! validArg(psa))                   
+    return E_INVALIDARG;
+
+  if(! validCoordinate(rgIndices, psa)) 
+    return DISP_E_BADINDEX;
+
+  /* Figure out the number of items to skip */
+  stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
+  
+  *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
+
+  return S_OK;
+}
+
+/************************************************************************ 
+ * Frees the memory data bloc
+ */
+HRESULT WINAPI SafeArrayDestroyData(
+  SAFEARRAY *psa)
+{ 
+  HRESULT  hRes;
+  ULONG    ulWholeArraySize; /* count spot in array  */
+  ULONG    ulDataIter;       /* to iterate the data space */
+  IUnknown *punk;
+  BSTR   bstr;
+
+  if(! validArg(psa)) 
+    return E_INVALIDARG;
+
+  if(psa->cLocks > 0) 
+    return DISP_E_ARRAYISLOCKED;
+
+  ulWholeArraySize = getArraySize(psa);
+
+  if(isPointer(psa->fFeatures)) {           /* release the pointers */
+
+    for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
+      punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));	
+
+      if( punk != NULL) 
+        IUnknown_Release(punk);
+    }
+
+  } else if(psa->fFeatures & FADF_BSTR) {  /* deallocate the obj */
+
+    for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
+      bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
+
+      if( bstr != NULL) 
+        SysFreeString( bstr );
+    }
+  }
+      
+  /* check if this array is a Vector, in which case do not free the data 
+     block since it has been allocated by AllocDescriptor and therefore
+     deserve to be freed by DestroyDescriptor */
+  if(!(psa->fFeatures & FADF_FIXEDSIZE)) { /* Set when we do CreateVector */
+
+    /* free the whole chunk */
+    if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
+      return E_UNEXPECTED; /* UNDOC error condition */
+
+    psa->pvData = NULL;
+  }
+  
+  return S_OK;
+}
+
+/************************************************************************ 
+ * Copy the psaSource's data block into psaTarget if dimension and size
+ * permits it.
+ */
+HRESULT WINAPI SafeArrayCopyData(
+  SAFEARRAY *psaSource,
+  SAFEARRAY **psaTarget)
+{ 
+  USHORT   cDimCount;        /* looper */
+  LONG     lDelta;           /* looper */
+  IUnknown *punk;   
+  ULONG    ulWholeArraySize; /* Number of item in SA */
+  BSTR   bstr;
+
+  if(! (validArg(psaSource) && validArg(*psaTarget)) ) 
+    return E_INVALIDARG;
+
+  if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
+    return E_INVALIDARG;
+
+  ulWholeArraySize = getArraySize(psaSource); 
+
+  /* The two arrays boundaries must be of same lenght */
+  for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
+    if( psaSource->rgsabound[cDimCount].cElements != 
+      (*psaTarget)->rgsabound[cDimCount].cElements)
+      return E_INVALIDARG;
+
+  if( isPointer((*psaTarget)->fFeatures) ) {         /* the target contains ptr 
+                                                        that must be released */
+    for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
+      punk = *(IUnknown**)
+        ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
+
+      if( punk != NULL) 
+        IUnknown_Release(punk);
+    }
+
+  } else if( (*psaTarget)->fFeatures & FADF_BSTR) {  /* the target contain BSTR
+                                                        that must be freed */ 
+    for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
+      bstr = 
+        *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
+
+      if( bstr != NULL) 
+        SysFreeString( bstr );
+    }
+  }
+
+  return duplicateData(psaSource, psaTarget);
+}
+
+/************************************************************************ 
+ * Deallocates all memory reserved for the SafeArray
+ */
+HRESULT WINAPI SafeArrayDestroy(
+  SAFEARRAY * psa)
+{ 
+  HRESULT hRes;
+
+  if(! validArg(psa)) 
+    return E_INVALIDARG;
+
+  if(psa->cLocks > 0) 
+    return DISP_E_ARRAYISLOCKED;
+
+  if((hRes = SafeArrayDestroyData( psa )) == S_OK)
+    if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
+      return S_OK;
+
+  return E_UNEXPECTED; /* UNDOC error condition */
+}
+
+/************************************************************************ 
+ * Make a dupplicate of a SafeArray
+ */
+HRESULT WINAPI SafeArrayCopy(
+  SAFEARRAY *psa, 
+  SAFEARRAY **ppsaOut)
+{ 
+  HRESULT hRes;
+  DWORD   dAllocSize;
+
+  if(! validArg(psa)) 
+    return E_INVALIDARG;
+
+  if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
+
+    /* Duplicate the SAFEARRAY struc */
+    memcpy(*ppsaOut, psa, 
+            sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
+
+    (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
+  
+    /* Get the allocated memory size for source and allocate it for target */ 
+    dAllocSize = HeapSize(GetProcessHeap(), 0, psa->pvData);
+    (*ppsaOut)->pvData = 
+      HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
+
+    if( (*ppsaOut)->pvData != NULL) {   /* HeapAlloc succeed */
+
+      if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
+        HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
+        (*ppsaOut)->pvData = NULL;
+        SafeArrayDestroyDescriptor(*ppsaOut);
+        return hRes;
+      }
+        
+    } else { /* failed to allocate or dupplicate... */
+      SafeArrayDestroyDescriptor(*ppsaOut);
+      return E_UNEXPECTED; /* UNDOC error condition */
+    }
+  } else { /* failed to allocate mem for descriptor */
+    return E_OUTOFMEMORY; /* UNDOC error condiftion */
+  }
+
+  return S_OK;
+}
+
+/************************************************************************ 
+ * Creates a one dimension safearray where the data is next to the 
+ * SAFEARRAY structure.
+ */
+SAFEARRAY* WINAPI SafeArrayCreateVector(
+  VARTYPE vt, 
+  LONG    lLbound, 
+  ULONG   cElements) 
+{ 
+  SAFEARRAY *psa;
+
+  /* Validate supported VARTYPE */
+  if ( (vt >= LAST_VARTYPE) ||
+       ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
+    return NULL;
+
+  /* Allocate memory for the array descriptor and data contiguously  */
+  if( FAILED( psa = (SAFEARRAY *)HeapAlloc( GetProcessHeap(), 
+                      HEAP_ZERO_MEMORY, 
+                      (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
+    return NULL;
+  }
+
+  /* setup data members... */ 
+  psa->cDims      = 1; /* always and forever */
+  psa->fFeatures  = getFeatures(vt) | FADF_FIXEDSIZE;
+  psa->cLocks     = 0;
+  psa->pvData     = psa+sizeof(*psa);
+  psa->cbElements = VARTYPE_SIZE[vt];
+
+  psa->rgsabound[0].cElements = cElements;
+  psa->rgsabound[0].lLbound   = lLbound;
+  
+  return(psa); 
+} 
+
+/************************************************************************ 
+ * Changes the caracteristics of the last dimension of the SafeArray
+ */
+HRESULT WINAPI SafeArrayRedim(
+  SAFEARRAY      *psa, 
+  SAFEARRAYBOUND *psaboundNew)
+{ 
+  LONG   lDelta;  /* hold difference in size */
+  USHORT cDims=1; /* dims counter */
+
+  if( !validArg(psa) )                    
+    return E_INVALIDARG;
+
+  if( psa->cLocks > 0 )                    
+    return DISP_E_ARRAYISLOCKED;
+
+  if( psa->fFeatures & FADF_FIXEDSIZE )    
+    return E_INVALIDARG;
+
+  if( SafeArrayLock(psa)==E_UNEXPECTED ) 
+    return E_UNEXPECTED;/* UNDOC error condition */
+
+  /* find the delta in number of array spot to apply to the new array */
+  lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
+  for(; cDims < psa->cDims; cDims++)
+    /* delta in number of spot implied by modifying the last dimension */
+    lDelta *= psa->rgsabound[cDims].cElements;
+
+  if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
+
+  } else /* need to enlarge (lDelta +) reduce (lDelta -) */
+    if(! resizeSafeArray(psa, lDelta)) 
+      return E_UNEXPECTED; /* UNDOC error condition */
+
+  /* the only modifyable dimension sits in [0] as the dimensions were reversed  
+     at array creation time... */
+  psa->rgsabound[0].cElements = psaboundNew->cElements;
+  psa->rgsabound[0].lLbound   = psaboundNew->lLbound;
+
+  return SafeArrayUnlock(psa);
+}
+
+/************************************************************************
+ * NOT WINDOWS API - SafeArray* Utility functions
+ ************************************************************************/
+
+/************************************************************************ 
+ * Used to validate the SAFEARRAY type of arg
+ */
+static BOOL validArg(
+  SAFEARRAY *psa) 
+{
+  SAFEARRAYBOUND *sab;
+  LONG psaSize  = 0;
+  LONG descSize = 0;
+  LONG fullSize = 0;
+
+  /*
+   * Let's check for the null pointer just in case.
+   */
+  if (psa == NULL)
+    return FALSE;
+
+  /* Check whether the size of the chunk make sens... That's the only thing
+     I can think of now... */
+
+  psaSize   = HeapSize(GetProcessHeap(), 0, psa);
+
+  /* size of the descriptor when the SA is not created with CreateVector */
+  descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
+
+  /* size of the descriptor + data when created with CreateVector */
+  fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
+
+  return((psaSize >= descSize) || (psaSize >= fullSize));
+}
+
+/************************************************************************ 
+ * Used to reallocate memory
+ */
+static BOOL resizeSafeArray(
+  SAFEARRAY *psa, 
+  LONG lDelta)
+{
+  ULONG    ulWholeArraySize;  /* use as multiplicator */
+  PVOID    pvNewBlock = NULL;  
+  IUnknown *punk;
+  BSTR   bstr;
+
+  ulWholeArraySize = getArraySize(psa);
+
+  if(lDelta < 0) {                    /* array needs to be shorthen  */
+    if( isPointer(psa->fFeatures))    /* ptr that need to be released */
+	    for(;lDelta < 0; lDelta++) {
+	      punk = *(IUnknown**)
+          ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
+	
+        if( punk != NULL )
+          IUnknown_Release(punk);
+	    }
+
+    else if(psa->fFeatures & FADF_BSTR)  /* BSTR that need to be freed */
+	    for(;lDelta < 0; lDelta++) {
+        bstr = *(BSTR*)
+          ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
+
+        if( bstr != NULL )
+          SysFreeString( bstr );
+      }
+  }
+
+  /* Ok now, if we are enlarging the array, we *MUST* move the whole block 
+     pointed to by pvData.   If we are shorthening the array, this move is
+     optional but we do it anyway becuase the benefit is that we are 
+     releasing to the system the unused memory */
+  
+  if((pvNewBlock = HeapReAlloc(GetProcessHeap(), 0, psa->pvData, 
+     (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL) 
+      return FALSE; /* TODO If we get here it means:
+                       SHRINK situation :  we've deleted the undesired
+                                           data and did not release the memory
+                       GROWING situation:  we've been unable to grow the array
+                    */
+
+  /* reassign to the new block of data */
+  psa->pvData = pvNewBlock;
+  return TRUE;
+}
+
+/************************************************************************ 
+ * Used to set the fFeatures data member of the SAFEARRAY structure. 
+ */
+static INT getFeatures(
+  VARTYPE vt) 
+{
+  switch(vt) {
+    case VT_UNKNOWN:   return FADF_UNKNOWN;
+    case VT_DISPATCH:  return FADF_DISPATCH;
+    case VT_BSTR:      return FADF_BSTR;
+  }
+  return 0;
+}
+
+/************************************************************************ 
+ * Used to figure out if the fFeatures data member of the SAFEARRAY 
+ * structure contain any information about the type of data stored... 
+ */
+static BOOL isPointer(
+  USHORT feature) 
+{
+  switch(feature) {
+    case FADF_UNKNOWN:  return TRUE; /* those are pointers */
+    case FADF_DISPATCH: return TRUE;
+  }
+  return FALSE;
+}
+
+/************************************************************************ 
+ * Used to calculate the displacement when accessing or modifying 
+ * safearray data set.
+ *
+ *  Parameters: - LONG *coor is the desired location in the multidimension
+ *              table.  Ex for a 3 dim table: coor[] = {1,2,3};
+ *              - ULONG *mat is the format of the table.  Ex for a 3 dim
+ *              table mat[] = {4,4,4};
+ *              - USHORT dim is the number of dimension of the SafeArray
+ */
+static ULONG calcDisplacement(
+  LONG           *coor, 
+  SAFEARRAYBOUND *mat, 
+  LONG           dim) 
+{
+  ULONG res = 0;
+  LONG  iterDim;
+
+  for(iterDim=0; iterDim<dim; iterDim++) 
+    /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
+    res += ((coor[iterDim]-mat[iterDim].lLbound) * 
+            endOfDim(coor, mat, iterDim+1, dim));
+
+  TRACE("SafeArray: calculated displacement is %lu.\n", res);
+  return(res);
+}
+
+/************************************************************************ 
+ * Recursivity agent for calcDisplacement method.  Used within Put and 
+ * Get methods.
+ */
+static INT endOfDim(
+  LONG           *coor, 
+  SAFEARRAYBOUND *mat, 
+  LONG           dim, 
+  LONG           realDim) 
+{
+  if(dim==realDim) 
+    return 1;
+  else 
+    return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
+}
+
+
+/************************************************************************ 
+ * Method used to validate the coordinate received in Put and Get 
+ * methods.
+ */
+static BOOL validCoordinate(
+  LONG      *coor, 
+  SAFEARRAY *psa) 
+{
+  INT   iter=0;
+  LONG    lUBound;
+  LONG    lLBound;
+  HRESULT hRes;
+
+  for(; iter<psa->cDims; iter++) {
+    if((hRes = SafeArrayGetLBound(psa, iter, &lLBound)) != S_OK)
+      return FALSE;
+    if((hRes = SafeArrayGetUBound(psa, iter, &lUBound)) != S_OK)
+      return FALSE;
+ 
+    if(lLBound == lUBound) 
+      return FALSE; 
+   
+    if((coor[iter] >= lLBound) && (coor[iter] <= lUBound))
+      return TRUE;
+    else
+      return FALSE;
+  }
+  return FALSE;
+}  
+
+/************************************************************************ 
+ * Method used to calculate the number of cells of the SA
+ */
+static ULONG getArraySize(
+  SAFEARRAY *psa) 
+{
+  USHORT cCount; 
+  ULONG  ulWholeArraySize = 1;
+
+  for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
+    ulWholeArraySize *= psa->rgsabound[cCount].cElements;
+
+  return ulWholeArraySize;  
+}
+
+
+/************************************************************************ 
+ * Method used to handle data space dupplication for Copy32 and CopyData32
+ */
+static HRESULT duplicateData(
+  SAFEARRAY *psa, 
+  SAFEARRAY **ppsaOut) 
+{
+  ULONG    ulWholeArraySize; /* size of the thing */
+  LONG     lDelta;
+  IUnknown *punk;
+  BSTR   pbstrReAllocStr = NULL; /* BSTR reallocated */
+
+  ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
+  
+  SafeArrayLock(*ppsaOut);
+
+  if( isPointer(psa->fFeatures) ) {  /* If datatype is object increment 
+                                        object's reference count */
+
+    for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
+      punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
+
+      if( punk != NULL)
+        IUnknown_AddRef(punk);
+    }
+
+    /* Copy the source array data into target array */
+    memcpy((*ppsaOut)->pvData, psa->pvData, 
+      ulWholeArraySize*psa->cbElements);
+
+  } else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate 
+                                               the BSTR in the new array */
+
+    for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
+      if(( pbstrReAllocStr = SysAllocString(
+            *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
+
+        SafeArrayUnlock(*ppsaOut);
+        return E_OUTOFMEMORY;
+      }
+
+      *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) = 
+        pbstrReAllocStr;
+    }
+
+  } else { /* Simply copy the source array data into target array */
+
+    memcpy((*ppsaOut)->pvData, psa->pvData, 
+      ulWholeArraySize*psa->cbElements);
+  }
+
+  SafeArrayUnlock(*ppsaOut);
+
+  return S_OK;
+}
+
Index: trunk/src/oleaut32/typelib.cpp
===================================================================
--- trunk/src/oleaut32/typelib.cpp	(revision 631)
+++ trunk/src/oleaut32/typelib.cpp	(revision 631)
@@ -0,0 +1,2500 @@
+/*
+ *	TYPELIB
+ *
+ *	Copyright 1997	Marcus Meissner
+ *		      1999  Rein Klazes
+ *
+ * Copyright 1999 Sander van Leeuwen (WINE OS/2 Port 990815)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ * there is much left to do here before it can be usefull for real world
+ * programs
+ * know problems:
+ * -. Only one format of typelibs is supported
+ * -. All testing until sofar is done using special written windows programs
+ * -. Data structures are straightforward, but slow for look-ups.
+ * -. (related) nothing is hashed
+ * -. a typelib is always read in its entirely into memory and never released.
+ * -. there are a number of stubs in ITypeLib and ITypeInfo interfaces. Most
+ *      of them I don't know yet how to implement them.
+ * -. Most error return values are just guessed not checked with windows
+ *      behaviour.
+ * -. all locale stuf ignored
+ * -. move stuf to wine/dlls
+ * -. didn't bother with a c++ interface
+ * -. lousy fatal error handling
+ * -. some methods just return pointers to internal data structures, this is
+ *      partly laziness, partly I want to check how windows does it.
+ * 
+ */
+
+#include "oleaut32.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "windef.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "oleauto.h"
+#include "winnls.h"
+#include "wine/winbase16.h"
+#include "heap.h"
+#include "wine/obj_base.h"
+#include "debugtools.h"
+#include "winversion.h"
+/* FIXME: get rid of these */
+typedef struct ITypeInfoVtbl ITypeLib_VTable, *LPTYPEINFO_VTABLE ; 
+typedef struct ITypeLibVtbl *LPTYPELIB_VTABLE  ; 
+#include "typelib.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+DECLARE_DEBUG_CHANNEL(typelib)
+
+ 
+/****************************************************************************
+ *		QueryPathOfRegTypeLib	[OLEAUT32.164]
+ * RETURNS
+ *	path of typelib
+ */
+HRESULT WINAPI
+QueryPathOfRegTypeLib(	
+	REFGUID guid,	/* [in] referenced guid */
+	WORD wMaj,	/* [in] major version */
+	WORD wMin,	/* [in] minor version */
+	LCID lcid,	/* [in] locale id */
+	LPBSTR path	/* [out] path of typelib */
+) {
+	char	xguid[80];
+	char	typelibkey[100],pathname[260];
+	DWORD	plen;
+
+
+	if (HIWORD(guid)) {
+		WINE_StringFromCLSID(guid,xguid);
+		sprintf(typelibkey,"SOFTWARE\\Classes\\Typelib\\%s\\%d.%d\\%lx\\win32",
+			xguid,wMaj,wMin,lcid
+		);
+	} else {
+		sprintf(xguid,"<guid 0x%08lx>",(DWORD)guid);
+		FIXME_(ole)("(%s,%d,%d,0x%04lx,%p),stub!\n",xguid,wMaj,wMin,(DWORD)lcid,path);
+		return E_FAIL;
+	}
+	plen = sizeof(pathname);
+	if (RegQueryValueA(HKEY_LOCAL_MACHINE,typelibkey,pathname,(LPLONG)&plen)) {
+		/* try again without lang specific id */
+		if (SUBLANGID(lcid))
+			return QueryPathOfRegTypeLib(guid,wMaj,wMin,PRIMARYLANGID(lcid),path);
+		FIXME_(ole)("key %s not found\n",typelibkey);
+		return E_FAIL;
+	}
+	*path = HEAP_strdupAtoW(GetProcessHeap(),0,pathname);
+	return S_OK;
+}
+
+/******************************************************************************
+ * LoadTypeLib [TYPELIB.3]  Loads and registers a type library
+ * NOTES
+ *    Docs: OLECHAR FAR* szFile
+ *    Docs: iTypeLib FAR* FAR* pptLib
+ *
+ * RETURNS
+ *    Success: S_OK
+ *    Failure: Status
+ */
+HRESULT WINAPI LoadTypeLib16(
+    OLECHAR *szFile, /* [in] Name of file to load from */
+    void * *pptLib) /* [out] Pointer to pointer to loaded type library */
+{
+    FIXME_(ole)("('%s',%p): stub\n",debugstr_w((LPWSTR)szFile),pptLib);
+
+    if (pptLib!=0)
+      *pptLib=0;
+
+    return E_FAIL;
+}
+
+/******************************************************************************
+ *		LoadTypeLib	[OLEAUT32.161]
+ * Loads and registers a type library
+ * NOTES
+ *    Docs: OLECHAR FAR* szFile
+ *    Docs: iTypeLib FAR* FAR* pptLib
+ *
+ * RETURNS
+ *    Success: S_OK
+ *    Failure: Status
+ */
+int TLB_ReadTypeLib(PCHAR file, ITypeLib **ppTypelib);
+HRESULT WINAPI LoadTypeLib(
+    OLECHAR *szFile,   /* [in] Name of file to load from */
+    ITypeLib * *pptLib) /* [out] Pointer to pointer to loaded type library */
+{
+    LPSTR p;
+    HRESULT res;
+    TRACE_(typelib)("('%s',%p)\n",debugstr_w(szFile),pptLib);
+    
+    p=HEAP_strdupWtoA(GetProcessHeap(),0,szFile);
+    res= TLB_ReadTypeLib(p, pptLib);
+    /* XXX need to free p ?? */
+
+    TRACE_(typelib)(" returns %ld\n",res);
+
+    return res;
+}
+
+/******************************************************************************
+ *		LoadRegTypeLib	[OLEAUT32.162]
+ */
+HRESULT WINAPI LoadRegTypeLib(	
+	REFGUID rguid,	/* [in] referenced guid */
+	WORD wVerMajor,	/* [in] major version */
+	WORD wVerMinor,	/* [in] minor version */
+	LCID lcid,	/* [in] locale id */
+	ITypeLib **ppTLib	/* [out] path of typelib */
+) {
+    BSTR bstr=NULL;
+    HRESULT res=QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor,
+		    lcid, &bstr);
+    if(SUCCEEDED(res)){
+        res= LoadTypeLib(bstr, ppTLib);
+        SysFreeString(bstr);
+    }
+    if(TRACE_ON(typelib)){
+        char xriid[50];
+        WINE_StringFromCLSID((LPCLSID)rguid,xriid);
+        TRACE_(typelib)("(IID: %s) load %s (%p)\n",xriid,
+                SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
+    }
+    return res;
+}	
+
+
+/******************************************************************************
+ *		RegisterTypeLib	[OLEAUT32.163]
+ * Adds information about a type library to the System Registry           
+ * NOTES
+ *    Docs: ITypeLib FAR * ptlib
+ *    Docs: OLECHAR FAR* szFullPath
+ *    Docs: OLECHAR FAR* szHelpDir
+ *
+ * RETURNS
+ *    Success: S_OK
+ *    Failure: Status
+ */
+HRESULT WINAPI RegisterTypeLib(
+     ITypeLib * ptlib,      /*[in] Pointer to the library*/
+     OLECHAR * szFullPath, /*[in] full Path of the library*/
+     OLECHAR * szHelpDir)  /*[in] dir to the helpfile for the library,
+							 may be NULL*/
+{   FIXME_(ole)("(%p,%s,%s): stub\n",ptlib, debugstr_w(szFullPath),debugstr_w(szHelpDir));
+    return S_OK;	/* FIXME: pretend everything is OK */
+}
+
+
+/******************************************************************************
+ *	UnRegisterTypeLib	[OLEAUT32.186]
+ * Removes information about a type library from the System Registry           
+ * NOTES
+ *
+ * RETURNS
+ *    Success: S_OK
+ *    Failure: Status
+ */
+HRESULT WINAPI UnRegisterTypeLib(
+    REFGUID libid,	/* [in] Guid of the library */
+	WORD wVerMajor,	/* [in] major version */
+	WORD wVerMinor,	/* [in] minor version */
+	LCID lcid,	/* [in] locale id */
+	SYSKIND syskind)
+{   
+    char xriid[50];
+    WINE_StringFromCLSID((LPCLSID)libid,xriid);
+    TRACE_(typelib)("(IID: %s): stub\n",xriid);
+    return S_OK;	/* FIXME: pretend everything is OK */
+}
+
+
+/* for better debugging info leave the static out for the time being */
+#define static
+
+/*=======================Itypelib methods ===============================*/
+/* ITypeLib methods */
+static HRESULT WINAPI ITypeLib_fnQueryInterface( LPTYPELIB This, REFIID riid,
+    VOID **ppvObject); 
+static ULONG WINAPI ITypeLib_fnAddRef( LPTYPELIB This); 
+static ULONG WINAPI ITypeLib_fnRelease( LPTYPELIB This); 
+static UINT WINAPI ITypeLib_fnGetTypeInfoCount( LPTYPELIB This); 
+static HRESULT WINAPI ITypeLib_fnGetTypeInfo( LPTYPELIB This, UINT index, 
+    ITypeInfo **ppTInfo); 
+
+static HRESULT WINAPI ITypeLib_fnGetTypeInfoType( LPTYPELIB This, UINT index,
+    TYPEKIND *pTKind); 
+
+static HRESULT WINAPI ITypeLib_fnGetTypeInfoOfGuid( LPTYPELIB This, REFGUID guid,
+    ITypeInfo **ppTinfo);
+
+static HRESULT WINAPI ITypeLib_fnGetLibAttr( LPTYPELIB This, 
+    LPTLIBATTR *ppTLibAttr); 
+
+static HRESULT WINAPI ITypeLib_fnGetTypeComp( LPTYPELIB This,
+    ITypeComp **ppTComp); 
+
+static HRESULT WINAPI ITypeLib_fnGetDocumentation( LPTYPELIB This, INT index,
+    BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, 
+    BSTR *pBstrHelpFile);
+
+static HRESULT WINAPI ITypeLib_fnIsName( LPTYPELIB This, LPOLESTR szNameBuf,
+    ULONG lHashVal, BOOL *pfName);
+
+static HRESULT WINAPI ITypeLib_fnFindName( LPTYPELIB This, LPOLESTR szNameBuf,
+    ULONG lHashVal, ITypeInfo **ppTInfo, MEMBERID *rgMemId, UINT16 *pcFound);
+
+static VOID WINAPI ITypeLib_fnReleaseTLibAttr( LPTYPELIB This,
+		TLIBATTR *pTLibAttr);
+
+static HRESULT WINAPI ITypeLib2_fnGetCustData( ITypeLib * This, REFGUID guid, 
+        VARIANT *pVarVal); 
+
+static HRESULT WINAPI ITypeLib2_fnGetLibStatistics( ITypeLib * This, 
+        UINT *pcUniqueNames, UINT *pcchUniqueNames); 
+
+static HRESULT WINAPI ITypeLib2_fnGetDocumentation2( ITypeLib * This, 
+        INT index, LCID lcid, BSTR *pbstrHelpString,
+        INT *pdwHelpStringContext, BSTR *pbstrHelpStringDll); 
+
+static HRESULT WINAPI ITypeLib2_fnGetAllCustData( ITypeLib * This,
+        CUSTDATA *pCustData);
+static ICOM_VTABLE(ITypeLib) tlbvt = {
+    ITypeLib_fnQueryInterface,
+    ITypeLib_fnAddRef,
+    ITypeLib_fnRelease,
+    ITypeLib_fnGetTypeInfoCount,
+    ITypeLib_fnGetTypeInfo,
+    ITypeLib_fnGetTypeInfoType,
+    ITypeLib_fnGetTypeInfoOfGuid,
+    ITypeLib_fnGetLibAttr,
+    ITypeLib_fnGetTypeComp,
+    ITypeLib_fnGetDocumentation,
+    ITypeLib_fnIsName,
+    ITypeLib_fnFindName,
+    ITypeLib_fnReleaseTLibAttr,
+    ITypeLib2_fnGetCustData,
+    ITypeLib2_fnGetLibStatistics,
+    ITypeLib2_fnGetDocumentation2,
+    ITypeLib2_fnGetAllCustData
+ };
+/* TypeInfo Methods */
+
+static HRESULT WINAPI ITypeInfo_fnQueryInterface( LPTYPEINFO This, REFIID riid,
+    VOID **ppvObject); 
+static ULONG WINAPI ITypeInfo_fnAddRef( LPTYPEINFO This); 
+static ULONG WINAPI ITypeInfo_fnRelease( LPTYPEINFO This); 
+static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( LPTYPEINFO This,
+        LPTYPEATTR  *ppTypeAttr); 
+
+static HRESULT WINAPI ITypeInfo_fnGetTypeComp( LPTYPEINFO This,
+        ITypeComp  * *ppTComp); 
+
+static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( LPTYPEINFO This, UINT index,
+        LPFUNCDESC  *ppFuncDesc); 
+
+static HRESULT WINAPI ITypeInfo_fnGetVarDesc( LPTYPEINFO This, UINT index,
+        LPVARDESC  *ppVarDesc); 
+
+static HRESULT WINAPI ITypeInfo_fnGetNames( LPTYPEINFO This, MEMBERID memid,
+        BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames);
+
+
+static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType( LPTYPEINFO This,
+        UINT index, HREFTYPE  *pRefType); 
+
+static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( LPTYPEINFO This,
+        UINT index, INT  *pImplTypeFlags); 
+
+static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( LPTYPEINFO This,
+        LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId); 
+
+static HRESULT WINAPI ITypeInfo_fnInvoke( LPTYPEINFO This, VOID  *pIUnk,
+        MEMBERID memid, UINT16 dwFlags, DISPPARAMS  *pDispParams, 
+        VARIANT  *pVarResult, EXCEPINFO  *pExcepInfo, UINT  *pArgErr);
+
+static HRESULT WINAPI ITypeInfo_fnGetDocumentation( LPTYPEINFO This,
+        MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString, 
+        DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile); 
+
+static HRESULT WINAPI ITypeInfo_fnGetDllEntry( LPTYPEINFO This,
+        MEMBERID memid, INVOKEKIND invKind, BSTR  *pBstrDllName,
+        BSTR  *pBstrName, WORD  *pwOrdinal); 
+
+static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( LPTYPEINFO This,
+        HREFTYPE hRefType, ITypeInfo  * *ppTInfo); 
+
+static HRESULT WINAPI ITypeInfo_fnAddressOfMember( LPTYPEINFO This,
+        MEMBERID memid, INVOKEKIND invKind, PVOID *ppv); 
+
+static HRESULT WINAPI ITypeInfo_fnCreateInstance( LPTYPEINFO This, 
+        IUnknown *pUnk, REFIID riid, VOID  * *ppvObj); 
+
+static HRESULT WINAPI ITypeInfo_fnGetMops( LPTYPEINFO This, MEMBERID memid, 
+        BSTR  *pBstrMops);
+
+
+static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( LPTYPEINFO This,
+        ITypeLib  * *ppTLib, UINT  *pIndex); 
+
+static HRESULT WINAPI ITypeInfo_fnReleaseTypeAttr( LPTYPEINFO This,
+        TYPEATTR *pTypeAttr); 
+
+static HRESULT WINAPI ITypeInfo_fnReleaseFuncDesc( LPTYPEINFO This,
+        FUNCDESC *pFuncDesc); 
+
+static HRESULT WINAPI ITypeInfo_fnReleaseVarDesc( LPTYPEINFO This,
+        VARDESC *pVarDesc); 
+/* itypeinfo2 methods */
+static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo * This,
+    TYPEKIND *pTypeKind);
+static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo * This,
+    UINT *pTypeFlags);
+static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo * This,
+    MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex);
+static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo * This,
+    MEMBERID memid, UINT *pVarIndex);
+static HRESULT WINAPI ITypeInfo2_fnGetCustData( ITypeInfo * This,
+    REFGUID guid, VARIANT *pVarVal);
+static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData( ITypeInfo * This,
+    UINT index, REFGUID guid, VARIANT *pVarVal);
+static HRESULT WINAPI ITypeInfo2_fnGetParamCustData( ITypeInfo * This,
+    UINT indexFunc, UINT indexParam, REFGUID guid, VARIANT *pVarVal);
+static HRESULT WINAPI ITypeInfo2_fnGetVarCustData( ITypeInfo * This,
+    UINT index, REFGUID guid, VARIANT *pVarVal);
+static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData( ITypeInfo * This,
+    UINT index, REFGUID guid, VARIANT *pVarVal);
+static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2( ITypeInfo * This,
+    MEMBERID memid, LCID lcid, BSTR *pbstrHelpString,
+    INT *pdwHelpStringContext, BSTR *pbstrHelpStringDll);
+static HRESULT WINAPI ITypeInfo2_fnGetAllCustData( ITypeInfo * This,
+    CUSTDATA *pCustData);
+static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData( ITypeInfo * This,
+    UINT index, CUSTDATA *pCustData);
+static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo * This,
+    UINT indexFunc, UINT indexParam, CUSTDATA *pCustData);
+static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo * This,
+    UINT index, CUSTDATA *pCustData);
+static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData( ITypeInfo * This,
+    UINT index, CUSTDATA *pCustData);
+
+static ICOM_VTABLE(ITypeInfo) tinfvt = {
+    ITypeInfo_fnQueryInterface,
+    ITypeInfo_fnAddRef,
+    ITypeInfo_fnRelease,
+    ITypeInfo_fnGetTypeAttr,
+    ITypeInfo_fnGetTypeComp,
+    ITypeInfo_fnGetFuncDesc,
+    ITypeInfo_fnGetVarDesc,
+    ITypeInfo_fnGetNames,
+    ITypeInfo_fnGetRefTypeOfImplType,
+    ITypeInfo_fnGetImplTypeFlags,
+    ITypeInfo_fnGetIDsOfNames,
+    ITypeInfo_fnInvoke,
+    ITypeInfo_fnGetDocumentation,
+    ITypeInfo_fnGetDllEntry,
+    ITypeInfo_fnGetRefTypeInfo,
+    ITypeInfo_fnAddressOfMember,
+    ITypeInfo_fnCreateInstance,
+    ITypeInfo_fnGetMops,
+    ITypeInfo_fnGetContainingTypeLib,
+    ITypeInfo_fnReleaseTypeAttr,
+    ITypeInfo_fnReleaseFuncDesc,
+    ITypeInfo_fnReleaseVarDesc,
+
+    ITypeInfo2_fnGetTypeKind,
+    ITypeInfo2_fnGetTypeFlags,
+    ITypeInfo2_fnGetFuncIndexOfMemId,
+    ITypeInfo2_fnGetVarIndexOfMemId,
+    ITypeInfo2_fnGetCustData,
+    ITypeInfo2_fnGetFuncCustData,
+    ITypeInfo2_fnGetParamCustData,
+    ITypeInfo2_fnGetVarCustData,
+    ITypeInfo2_fnGetImplTypeCustData,
+    ITypeInfo2_fnGetDocumentation2,
+    ITypeInfo2_fnGetAllCustData,
+    ITypeInfo2_fnGetAllFuncCustData,
+    ITypeInfo2_fnGetAllParamCustData,
+    ITypeInfo2_fnGetAllVarCustData,
+    ITypeInfo2_fnGetAllImplTypeCustData,
+
+};
+
+static TYPEDESC stndTypeDesc[VT_LPWSTR+1]={/* VT_LPWSTR is largest type that */
+										/* may appear in type description*/
+	{{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4},
+        {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9},
+    {{0},10},{{0},11},{{0},12},{{0},13},{{0},14},
+        {{0},15},{{0},16},{{0},17},{{0},18},{{0},19},
+    {{0},20},{{0},21},{{0},22},{{0},23},{{0},24},
+        {{0},25},{{0},26},{{0},27},{{0},28},{{0},29},
+    {{0},30},{{0},31}};
+
+static void TLB_abort()
+{
+		*((int *)0)=0;
+}
+static void * TLB_Alloc(unsigned size)
+{
+    void * ret;
+    if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){
+        /* FIXME */
+        ERR_(ole)("cannot allocate memory\n");
+    }
+    return ret;
+}
+
+/* candidate for a more global appearance... */
+static BSTR  TLB_DupAtoBstr(PCHAR Astr)
+{
+    int len;
+    BSTR bstr;
+    DWORD *pdw  ;
+    if(!Astr)
+        return NULL;
+    len=strlen(Astr);
+    pdw = (DWORD *)TLB_Alloc((len+3)*sizeof(OLECHAR));
+    pdw[0]=(len)*sizeof(OLECHAR);
+    bstr=(BSTR)&( pdw[1]);
+    lstrcpyAtoW( bstr, Astr);
+    TRACE_(typelib)("copying %s to (%p)\n", Astr, bstr);
+    return bstr;
+}
+
+static void TLB_Free(void * ptr)
+{
+    HeapFree(GetProcessHeap(), 0, ptr);
+}
+/* read function */
+DWORD TLB_Read(void *buffer,  DWORD count, TLBContext *pcx, long where )
+{
+	DWORD bytesread=0;
+	
+	if ((   where != DO_NOT_SEEK &&
+		(0xffffffff == SetFilePointer( pcx->hFile, where, 0,FILE_BEGIN))
+	    ) ||
+	    !ReadFile(pcx->hFile, buffer, count, &bytesread, NULL)
+	) {
+        /* FIXME */
+		ERR_(typelib)("read error is 0x%lx reading %ld bytes at 0x%lx\n",
+			    GetLastError(), count, where);
+		TLB_abort();
+		exit(1);
+	}
+	return bytesread;
+}
+
+static void TLB_ReadGuid( GUID *pGuid, int offset,   TLBContext *pcx)
+{
+    if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
+        memset(pGuid,0, sizeof(GUID));
+        return;
+    }
+    TLB_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
+}
+
+PCHAR TLB_ReadName( TLBContext *pcx, int offset)
+{
+    char * name;
+    TLBNameIntro niName;
+    TLB_Read(&niName, sizeof(niName), pcx,
+				pcx->pTblDir->pNametab.offset+offset);
+    niName.namelen &= 0xFF; /* FIXME: correct ? */
+    name=(char *)TLB_Alloc((niName.namelen & 0xff) +1);
+    TLB_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
+    name[niName.namelen & 0xff]='\0';
+    return name;
+}
+PCHAR TLB_ReadString( TLBContext *pcx, int offset)
+{
+    char * string;
+    INT16 length;
+    if(offset<0) return NULL;
+    TLB_Read(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
+    if(length <= 0) return 0;
+    string=(char *)TLB_Alloc(length +1);
+    TLB_Read(string, length, pcx, DO_NOT_SEEK);
+    string[length]='\0';
+    return string;
+}
+/*
+ * read a value and fill a VARIANT structure 
+ */
+static void TLB_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
+{
+    int size;
+    if(offset <0) { /* data is packed in here */
+        pVar->vt = (offset & 0x7c000000 )>> 26;
+        V_UNION(pVar, iVal) = offset & 0xffff;
+        return;
+    }
+    TLB_Read(&(pVar->vt), sizeof(VARTYPE), pcx, 
+        pcx->pTblDir->pCustData.offset + offset );
+    switch(pVar->vt){
+        case VT_EMPTY:  /* FIXME: is this right? */
+        case VT_NULL:   /* FIXME: is this right? */
+        case VT_I2  :   /* this should not happen */
+        case VT_I4  :
+        case VT_R4  :
+        case VT_ERROR   : 
+        case VT_BOOL    : 
+        case VT_I1  : 
+        case VT_UI1 : 
+        case VT_UI2 : 
+        case VT_UI4 : 
+        case VT_INT : 
+        case VT_UINT    : 
+        case VT_VOID    : /* FIXME: is this right? */
+        case VT_HRESULT : 
+            size=4; break;
+        case VT_R8  :
+        case VT_CY  :
+        case VT_DATE    : 
+        case VT_I8  : 
+        case VT_UI8 : 
+        case VT_DECIMAL :  /* FIXME: is this right? */
+        case VT_FILETIME :
+            size=8;break;
+            /* pointer types with known behaviour */
+        case VT_BSTR    :{
+            char * ptr;
+            TLB_Read(&size, sizeof(INT), pcx, DO_NOT_SEEK );
+            ptr=(char *)TLB_Alloc(size);/* allocate temp buffer */
+            TLB_Read(ptr, size, pcx, DO_NOT_SEEK ); /* read string (ANSI) */
+            V_UNION(pVar, bstrVal)=SysAllocStringLen(NULL,size);
+            /* FIXME: do we need a AtoW conversion here? */
+            V_UNION(pVar, bstrVal[size])=L'\0';
+            while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
+            TLB_Free(ptr);
+        }
+            size=-4; break;
+    /* FIXME: this will not work AT ALL when the variant contains a pointer */
+        case VT_DISPATCH :
+        case VT_VARIANT : 
+        case VT_UNKNOWN : 
+        case VT_PTR : 
+        case VT_SAFEARRAY :
+        case VT_CARRAY  : 
+        case VT_USERDEFINED : 
+        case VT_LPSTR   : 
+        case VT_LPWSTR  : 
+        case VT_BLOB    : 
+        case VT_STREAM  : 
+        case VT_STORAGE : 
+        case VT_STREAMED_OBJECT : 
+        case VT_STORED_OBJECT   : 
+        case VT_BLOB_OBJECT : 
+        case VT_CF  : 
+        case VT_CLSID   : 
+        default: 
+            size=0; 
+            FIXME_(ole)("VARTYPE %d is not supported, setting pointer to NULL\n",
+                pVar->vt);
+    }
+
+    if(size>0) /* (big|small) endian correct? */
+        TLB_Read(&(V_UNION(pVar, iVal)), size, pcx, DO_NOT_SEEK );
+        return ;
+}
+/*
+ * create a linked list with custom data
+ */
+static int TLB_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData )
+{
+    TLBCDGuid entry;
+    TLBCustData* pNew;
+    int count=0;
+    while(offset >=0){
+        count++;
+        pNew=(TLBCustData* )TLB_Alloc(sizeof(TLBCustData));
+        TLB_Read(&entry, sizeof(entry), pcx, 
+            pcx->pTblDir->pCDGuids.offset+offset);
+        TLB_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
+        TLB_ReadValue(&(pNew->data), entry.DataOffset, pcx);
+        /* add new custom data at head of the list */
+        pNew->next=*ppCustData;
+        *ppCustData=pNew;
+        offset = entry.next;
+    }
+    return count;
+}
+
+static void TLB_GetTdesc(TLBContext *pcx, INT type,TYPEDESC * pTd )
+{
+    if(type <0)
+        pTd->vt=type & VT_TYPEMASK;
+    else
+        *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
+}
+static void TLB_DoFuncs(TLBContext *pcx, int cFuncs, int cVars,
+                          int offset, TLBFuncDesc ** pptfd)
+{
+    /* 
+     * member information is stored in a data structure at offset
+     * indicated by the memoffset field of the typeinfo structure
+     * There are several distinctive parts.
+     * the first part starts with a field that holds the total length 
+     * of this (first) part excluding this field. Then follow the records,
+     * for each member there is one record.
+     *
+     * First entry is always the length of the record (excluding this
+     * length word). 
+     * Rest of the record depends on the type of the member. If there is 
+     * a field indicating the member type (function variable intereface etc)
+     * I have not found it yet. At this time we depend on the information
+     * in the type info and the usual order how things are stored.
+     *
+     * Second follows an array sized nrMEM*sizeof(INT) with a memeber id
+     * for each member;
+     * 
+     * Third is a equal sized array with file offsets to the name entry 
+     * of each member.
+     * 
+     * Forth and last (?) part is an array with offsets to the records in the
+     * first part of this file segment.
+     */
+
+    int infolen, nameoffset, reclength, nrattributes;
+    char recbuf[512];
+    TLBFuncRecord * pFuncRec=(TLBFuncRecord *) recbuf;
+    int i, j;
+    int recoffset=offset+sizeof(INT);
+    TLB_Read(&infolen,sizeof(INT), pcx, offset);
+    for(i=0;i<cFuncs;i++){
+        *pptfd=(TLBFuncDesc*)TLB_Alloc(sizeof(TLBFuncDesc));
+    /* name, eventually add to a hash table */
+        TLB_Read(&nameoffset, sizeof(INT), pcx, 
+            offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
+        (*pptfd)->Name=TLB_ReadName(pcx, nameoffset);
+    /* read the function information record */
+        TLB_Read(&reclength, sizeof(INT), pcx, recoffset);
+        reclength &=0x1ff;
+        TLB_Read(pFuncRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK) ; 
+    /* do the attributes */
+        nrattributes=(reclength-pFuncRec->nrargs*3*sizeof(int)-0x18)
+            /sizeof(int);
+        if(nrattributes>0){
+            (*pptfd)->helpcontext = pFuncRec->OptAttr[0] ;
+            if(nrattributes>1){
+                (*pptfd)->HelpString = TLB_ReadString(pcx,
+                                                      pFuncRec->OptAttr[1]) ;
+                if(nrattributes>2){
+                    if(pFuncRec->FKCCIC & 0x2000)
+                        (*pptfd)->Entry = (char *) pFuncRec->OptAttr[2] ;
+                    else
+                        (*pptfd)->Entry = TLB_ReadString(pcx,
+                                                         pFuncRec->OptAttr[2]);
+                    if(nrattributes>5 )
+                        (*pptfd)->HelpStringContext = pFuncRec->OptAttr[5] ;
+                    if(nrattributes>6 && pFuncRec->FKCCIC & 0x80){
+                        TLB_CustData(pcx, pFuncRec->OptAttr[6],
+                                &(*pptfd)->pCustData);
+                    }
+                }
+            }
+        }
+    /* fill the FuncDesc Structure */
+        TLB_Read(&(*pptfd)->funcdesc.memid, sizeof(INT), pcx, 
+            offset + infolen + ( i + 1) * sizeof(INT));
+        (*pptfd)->funcdesc.funckind = (tagFUNCKIND)((pFuncRec->FKCCIC) & 0x7);
+        (*pptfd)->funcdesc.invkind = (tagINVOKEKIND)(((pFuncRec->FKCCIC) >>3) & 0xF);
+        (*pptfd)->funcdesc.callconv = (tagCALLCONV)((pFuncRec->FKCCIC) >>8 & 0xF);
+        (*pptfd)->funcdesc.cParams = pFuncRec->nrargs ;
+        (*pptfd)->funcdesc.cParamsOpt = pFuncRec->nroargs ;
+        (*pptfd)->funcdesc.oVft = pFuncRec->VtableOffset ;
+        (*pptfd)->funcdesc.wFuncFlags = LOWORD(pFuncRec->Flags)  ;
+        TLB_GetTdesc(pcx, pFuncRec->DataType,   
+            &(*pptfd)->funcdesc.elemdescFunc.tdesc) ;
+                                    
+        /* do the parameters/arguments */
+        if(pFuncRec->nrargs){
+            TLBParameterInfo paraminfo;
+            (*pptfd)->funcdesc.lprgelemdescParam=(ELEMDESC*)
+                TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC));
+            (*pptfd)->pParamDesc=(TLBParDesc*)TLB_Alloc(pFuncRec->nrargs *
+                sizeof(TLBParDesc));
+
+            TLB_Read(&paraminfo,sizeof(paraminfo), pcx, recoffset+reclength -
+                pFuncRec->nrargs * sizeof(TLBParameterInfo));
+            for(j=0;j<pFuncRec->nrargs;j++){
+                TLB_GetTdesc(pcx, paraminfo.DataType,   
+                    &(*pptfd)->funcdesc.lprgelemdescParam[j].tdesc) ;
+                V_UNION(&((*pptfd)->funcdesc.lprgelemdescParam[j]),
+                    paramdesc.wParamFlags) = paraminfo.Flags;
+                (*pptfd)->pParamDesc[j].Name=(char *)paraminfo.oName;
+                TLB_Read(&paraminfo,sizeof(TLBParameterInfo), pcx,
+                        DO_NOT_SEEK);
+            }
+            /* second time around */
+            for(j=0;j<pFuncRec->nrargs;j++){
+                /* name */
+                (*pptfd)->pParamDesc[j].Name=
+                    TLB_ReadName(pcx, (int)(*pptfd)->pParamDesc[j].Name);
+                /* default value */
+                if((PARAMFLAG_FHASDEFAULT & V_UNION(&((*pptfd)->funcdesc.
+                    lprgelemdescParam[j]),paramdesc.wParamFlags)) &&
+                    ((pFuncRec->FKCCIC) & 0x1000)){
+                    INT *pInt=(INT *)((char *)pFuncRec + reclength -
+                        (pFuncRec->nrargs * 4 + 1) * sizeof(INT) );
+                    PARAMDESC * pParamDesc= &V_UNION(&((*pptfd)->funcdesc.
+                        lprgelemdescParam[j]),paramdesc);
+                    pParamDesc->pparamdescex = (tagPARAMDESCEX*)TLB_Alloc(sizeof(PARAMDESCEX));
+                    pParamDesc->pparamdescex->cBytes= sizeof(PARAMDESCEX);
+                    TLB_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue), 
+                        pInt[j], pcx);
+                }
+                /* custom info */
+                if(nrattributes>7+j && pFuncRec->FKCCIC & 0x80)
+                    TLB_CustData(pcx, pFuncRec->OptAttr[7+j],
+									&(*pptfd)->pParamDesc[j].pCustData);
+            }
+        }
+    /* scode is not used: archaic win16 stuff FIXME: right? */
+        (*pptfd)->funcdesc.cScodes = 0 ;
+        (*pptfd)->funcdesc.lprgscode = NULL ;
+        pptfd=&((*pptfd)->next);
+        recoffset += reclength;
+    }
+}
+static void TLB_DoVars(TLBContext *pcx, int cFuncs, int cVars,
+                          int offset, TLBVarDesc ** pptvd)
+{
+    int infolen, nameoffset, reclength;
+    char recbuf[256];
+    TLBVarRecord * pVarRec=(TLBVarRecord *) recbuf;
+    int i;
+    int recoffset;
+    TLB_Read(&infolen,sizeof(INT), pcx, offset);
+    TLB_Read(&recoffset,sizeof(INT), pcx, offset + infolen + 
+        ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
+    recoffset += offset+sizeof(INT);
+    for(i=0;i<cVars;i++){
+        *pptvd=(TLBVarDesc*)TLB_Alloc(sizeof(TLBVarDesc));
+    /* name, eventually add to a hash table */
+        TLB_Read(&nameoffset, sizeof(INT), pcx, 
+            offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
+        (*pptvd)->Name=TLB_ReadName(pcx, nameoffset);
+    /* read the variable information record */
+        TLB_Read(&reclength, sizeof(INT), pcx, recoffset);
+        reclength &=0xff;
+        TLB_Read(pVarRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK) ; 
+    /* Optional data */
+        if(reclength >(6*sizeof(INT)) )
+            (*pptvd)->HelpContext=pVarRec->HelpContext;
+        if(reclength >(7*sizeof(INT)) )
+            (*pptvd)->HelpString = TLB_ReadString(pcx, pVarRec->oHelpString) ;
+        if(reclength >(8*sizeof(INT)) )
+        if(reclength >(9*sizeof(INT)) )
+            (*pptvd)->HelpStringContext=pVarRec->HelpStringContext;
+    /* fill the VarDesc Structure */
+        TLB_Read(&(*pptvd)->vardesc.memid, sizeof(INT), pcx, 
+            offset + infolen + ( i + 1) * sizeof(INT));
+        (*pptvd)->vardesc.varkind = (tagVARKIND)pVarRec->VarKind;
+        (*pptvd)->vardesc.wVarFlags = pVarRec->Flags;
+        TLB_GetTdesc(pcx, pVarRec->DataType,    
+            &(*pptvd)->vardesc.elemdescVar.tdesc) ;
+/*   (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) fixme?? */
+        if(pVarRec->VarKind == VAR_CONST ){
+            V_UNION(&((*pptvd)->vardesc),lpvarValue)=(VARIANT*)TLB_Alloc(sizeof(VARIANT));
+            TLB_ReadValue(V_UNION(&((*pptvd)->vardesc),lpvarValue), 
+                pVarRec->OffsValue, pcx);
+        }else
+            V_UNION(&((*pptvd)->vardesc),oInst)=pVarRec->OffsValue;
+        pptvd=&((*pptvd)->next);
+        recoffset += reclength;
+    }
+}
+/* fill in data for a hreftype (offset). When the refernced type is contained
+ * in the typelib, its just an (file) offset in the type info base dir.
+ * If comes fom import, its an offset+1 in the ImpInfo table
+ * */
+static void TLB_DoRefType(TLBContext *pcx, 
+                          int offset, TLBRefType ** pprtd)
+{
+    int j;
+    if(!HREFTYPE_INTHISFILE( offset)) {
+        /* external typelib */
+        TLBImpInfo impinfo;
+        TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
+        TLB_Read(&impinfo, sizeof(impinfo), pcx, 
+            pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
+        for(j=0;pImpLib;j++){   /* search the known offsets of all import libraries */
+            if(pImpLib->offset==impinfo.oImpFile) break;
+            pImpLib=pImpLib->next;
+        }
+        if(pImpLib){
+            (*pprtd)->reference=offset;
+            (*pprtd)->pImpTLInfo=pImpLib;
+            TLB_ReadGuid(&(*pprtd)->guid, impinfo.oGuid, pcx);
+        }else{
+            ERR_(typelib)("Cannot find a reference\n");
+            (*pprtd)->reference=-1;
+            (*pprtd)->pImpTLInfo=(tagTLBImpLib*)-1;
+        }
+    }else{
+        /* in this typelib */
+        (*pprtd)->reference=offset;
+        (*pprtd)->pImpTLInfo=(tagTLBImpLib*)-2;
+    }
+}
+
+/* process Implemented Interfaces of a com class */
+static void TLB_DoImplTypes(TLBContext *pcx, int count,
+                          int offset, TLBRefType ** pprtd)
+{
+    int i;
+    TLBRefRecord refrec;
+    for(i=0;i<count;i++){
+        if(offset<0) break; /* paranoia */
+        *pprtd=(TLBRefType*)TLB_Alloc(sizeof(TLBRefType));
+        TLB_Read(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
+        TLB_DoRefType(pcx, refrec.reftype, pprtd);
+        (*pprtd)->flags=refrec.flags;
+        (*pprtd)->ctCustData=
+            TLB_CustData(pcx, refrec.oCustData, &(*pprtd)->pCustData);
+        offset=refrec.onext;
+        pprtd=&((*pprtd)->next);
+    }
+}
+/*
+ * process a typeinfo record
+ */
+TLBTypeInfo * TLB_DoTypeInfo(TLBContext *pcx, int count, TLBLibInfo* pLibInfo)
+{
+    TLBTypeInfoBase tiBase;
+    TLBTypeInfo *ptiRet;
+    ptiRet=(TLBTypeInfo*)TLB_Alloc(sizeof(TLBTypeInfo));
+    ptiRet->lpvtbl = &tinfvt;
+    ptiRet->ref=1;
+    TLB_Read(&tiBase, sizeof(tiBase) ,pcx ,
+        pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
+/* this where we are coming from */
+    ptiRet->pTypeLib=pLibInfo;
+    ptiRet->index=count;
+/* fill in the typeattr fields */
+    TLB_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
+    ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid;   /* FIXME: correct? */
+    ptiRet->TypeAttr.memidConstructor=MEMBERID_NIL ;/* FIXME */
+    ptiRet->TypeAttr.memidDestructor=MEMBERID_NIL ; /* FIXME */
+    ptiRet->TypeAttr.lpstrSchema=NULL;              /* reserved */
+    ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
+    ptiRet->TypeAttr.typekind=(tagTYPEKIND)(tiBase.typekind & 0xF);
+    ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
+    ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
+    ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
+    ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
+    ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
+    ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
+    ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
+    ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
+    if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
+        TLB_GetTdesc(pcx, tiBase.datatype1, 
+            &ptiRet->TypeAttr.tdescAlias) ;
+/*  FIXME: */
+/*    IDLDESC  idldescType; *//* never saw this one != zero  */
+
+/* name, eventually add to a hash table */
+    ptiRet->Name=TLB_ReadName(pcx, tiBase.NameOffset);
+    TRACE_(typelib)("reading %s\n", ptiRet->Name);
+    /* help info */
+    ptiRet->DocString=TLB_ReadString(pcx, tiBase.docstringoffs);
+    ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
+    ptiRet->dwHelpContext=tiBase.helpcontext;
+/* note: InfoType's Help file and HelpStringDll come from the containing
+ * library. Further HelpString and Docstring appear to be the same thing :(
+ */
+    /* functions */
+    if(ptiRet->TypeAttr.cFuncs >0 )
+        TLB_DoFuncs(pcx, ptiRet->TypeAttr.cFuncs ,ptiRet->TypeAttr.cVars, 
+        tiBase.memoffset, & ptiRet->funclist);
+    /* variables */
+    if(ptiRet->TypeAttr.cVars >0 )
+        TLB_DoVars(pcx, ptiRet->TypeAttr.cFuncs ,ptiRet->TypeAttr.cVars, 
+        tiBase.memoffset, & ptiRet->varlist);
+    if(ptiRet->TypeAttr.cImplTypes >0 ){
+        if(ptiRet->TypeAttr.typekind == TKIND_COCLASS)
+            TLB_DoImplTypes(pcx, ptiRet->TypeAttr.cImplTypes , 
+                tiBase.datatype1, & ptiRet->impltypelist);
+        else if(ptiRet->TypeAttr.typekind != TKIND_DISPATCH){
+            ptiRet->impltypelist=(TLBRefType*)TLB_Alloc(sizeof(TLBRefType));
+            TLB_DoRefType(pcx, tiBase.datatype1, & ptiRet->impltypelist);
+        }
+	}
+    ptiRet->ctCustData=
+        TLB_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
+    return ptiRet;
+}
+
+
+long TLB_FindTlb(TLBContext *pcx)
+{/* FIXME: should parse the file properly
+  * hack to find our tlb data
+  */
+#define TLBBUFSZ 1024
+    char buff[TLBBUFSZ+1]; /* room for a trailing '\0' */
+    long ret=0,found=0;
+    int count;
+    char *pChr;
+
+#define LOOK_FOR_MAGIC(magic)				\
+    count=TLB_Read(buff, TLBBUFSZ, pcx, 0);		\
+    do {						\
+        buff[count]='\0';				\
+	pChr = buff;					\
+	while (pChr) {					\
+	    pChr = (char *)memchr(pChr,magic[0],count-(pChr-buff));\
+	    if (pChr) {					\
+		if (!memcmp(pChr,magic,4)) {		\
+		    ret+= pChr-buff;			\
+		    found = 1;				\
+		    break;				\
+		}					\
+		pChr++;					\
+	    }						\
+	}						\
+	if (found) break;				\
+        ret+=count;					\
+	count=TLB_Read(buff, TLBBUFSZ, pcx, DO_NOT_SEEK);\
+    } while(count>0);
+
+
+    LOOK_FOR_MAGIC(TLBMAGIC2);
+    if(count)
+        return ret;
+
+    LOOK_FOR_MAGIC(TLBMAGIC1);
+    if(count)
+        ERR_(ole)("type library format not (yet) implemented\n");
+    else
+        ERR_(ole)("not type library found in this file\n");
+    return -1;
+}
+#undef LOOK_FOR_MAGIC
+
+int TLB_ReadTypeLib(PCHAR file, ITypeLib **ppTypeLib)
+{
+    TLBContext cx;
+    OFSTRUCT ofStruct;
+    long oStart,lPSegDir;
+    TLBLibInfo* pLibInfo=NULL;
+    TLB2Header tlbHeader;
+    TLBSegDir tlbSegDir;
+    if((cx.hFile=OpenFile(file, &ofStruct, OF_READWRITE))==HFILE_ERROR) {
+	ERR_(typelib)("cannot open %s error 0x%lx\n",file, GetLastError());
+	return E_FAIL;
+    }
+    /* get pointer to beginning of typelib data */
+    if((oStart=TLB_FindTlb(&cx))<0){
+        if(oStart==-1)
+            ERR_(typelib)("cannot locate typelib in  %s\n",file);
+        else
+            ERR_(typelib)("unsupported typelib format in  %s\n",file);
+        return E_FAIL;
+    }
+    cx.oStart=oStart;
+    pLibInfo=(TLBLibInfo*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TLBLibInfo));
+    if (!pLibInfo){
+	CloseHandle(cx.hFile);
+        return E_OUTOFMEMORY;
+    }
+    pLibInfo->lpvtbl = &tlbvt;
+    pLibInfo->ref=1;
+    cx.pLibInfo=pLibInfo;
+    /* read header */
+    TLB_Read((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
+    /* there is a small number of information here until the next important
+     * part:
+     * the segment directory . Try to calculate the amount of data */
+    lPSegDir=sizeof(tlbHeader)+
+            (tlbHeader.nrtypeinfos)*4+
+            (tlbHeader.varflags & HELPDLLFLAG? 4 :0);
+    /* now read the segment directory */
+    TLB_Read((void*)&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);  
+    cx.pTblDir=&tlbSegDir;
+    /* just check two entries */
+    if (	tlbSegDir.pTypeInfoTab.res0c != 0x0F ||
+		tlbSegDir.pImpInfo.res0c != 0x0F
+    ) {
+        ERR_(typelib)("cannot find the table directory, ptr=0x%lx\n",lPSegDir);
+	CloseHandle(cx.hFile);
+        return E_FAIL;
+    }
+    /* now fill our internal data */
+    /* TLIBATTR fields */
+    TLB_ReadGuid(&pLibInfo->LibAttr.guid, tlbHeader.posguid, &cx);
+    pLibInfo->LibAttr.lcid=tlbHeader.lcid;
+    pLibInfo->LibAttr.syskind=(tagSYSKIND)(tlbHeader.varflags & 0x0f); /* check the mask */
+    pLibInfo->LibAttr.wMajorVerNum=LOWORD(tlbHeader.version);
+    pLibInfo->LibAttr.wMinorVerNum=HIWORD(tlbHeader.version);
+    pLibInfo->LibAttr.wLibFlags=(WORD) tlbHeader.flags & 0xffff;/* check mask */
+    /* name, eventually add to a hash table */
+    pLibInfo->Name=TLB_ReadName(&cx, tlbHeader.NameOffset);
+    /* help info */
+    pLibInfo->DocString=TLB_ReadString(&cx, tlbHeader.helpstring);
+    pLibInfo->HelpFile=TLB_ReadString(&cx, tlbHeader.helpfile);
+    if( tlbHeader.varflags & HELPDLLFLAG){
+            int offset;
+            TLB_Read(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
+            pLibInfo->HelpStringDll=TLB_ReadString(&cx, offset);
+    }
+
+    pLibInfo->dwHelpContext=tlbHeader.helpstringcontext;
+    /* custom data */
+    if(tlbHeader.CustomDataOffset >= 0) {
+        pLibInfo->ctCustData=
+            TLB_CustData(&cx, tlbHeader.CustomDataOffset, &pLibInfo->pCustData);
+    }
+    /* fill in typedescriptions */
+    if(tlbSegDir.pTypdescTab.length >0){
+        int i, j, cTD=tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
+        INT16 td[4];
+        pLibInfo->pTypeDesc=(TYPEDESC*)
+            TLB_Alloc( cTD * sizeof(TYPEDESC));
+        TLB_Read(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
+        for(i=0;i<cTD;){
+            /* FIXME: add several sanity checks here */
+            pLibInfo->pTypeDesc[i].vt=td[0] & VT_TYPEMASK;
+            if(td[0]==VT_PTR ||td[0]==VT_SAFEARRAY){/* FIXME: check safearray */
+                if(td[3]<0)
+                    V_UNION(&(pLibInfo->pTypeDesc[i]),lptdesc)=
+                        & stndTypeDesc[td[2]];
+                else
+                    V_UNION(&(pLibInfo->pTypeDesc[i]),lptdesc)=
+                        & pLibInfo->pTypeDesc[td[3]/8];
+            }else if(td[0]==VT_CARRAY)
+                V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)=
+                    (tagARRAYDESC*)((int) td[2]);  /* temp store offset in*/
+                                            /* array descr table here */
+            else if(td[0]==VT_USERDEFINED)
+                V_UNION(&(pLibInfo->pTypeDesc[i]),hreftype)=MAKELONG(td[2],td[3]);
+            if(++i<cTD) TLB_Read(td, sizeof(td), &cx, DO_NOT_SEEK);
+        }
+        /* second time around to fill the array subscript info */
+        for(i=0;i<cTD;i++){
+            if(pLibInfo->pTypeDesc[i].vt != VT_CARRAY) continue;
+            if(tlbSegDir.pArrayDescriptions.offset>0){
+                TLB_Read(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset +
+                    (int) V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc));
+                V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)=(tagARRAYDESC*)
+                    TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
+                if(td[1]<0)
+                    V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)->tdescElem.vt=td[0] & VT_TYPEMASK;
+                else
+                    V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)->tdescElem=stndTypeDesc[td[0]/8];
+                V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)->cDims=td[2];
+                for(j=0;j<td[2];j++){
+                    TLB_Read(& V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)->rgbounds[j].cElements, 
+                        sizeof(INT), &cx, DO_NOT_SEEK);
+                    TLB_Read(& V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)
+                        ->rgbounds[j].lLbound, 
+                        sizeof(INT), &cx, DO_NOT_SEEK);
+                }
+            }else{
+                V_UNION(&(pLibInfo->pTypeDesc[i]),lpadesc)=NULL;
+                ERR_(ole)("didn't find array description data\n");
+            }
+        }
+    }
+    /* imported type libs */
+    if(tlbSegDir.pImpFiles.offset>0){
+        TLBImpLib **ppImpLib=&(pLibInfo->pImpLibs);
+        int offset=tlbSegDir.pImpFiles.offset;
+        int oGuid;
+        UINT16 size;
+        while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length){
+            *ppImpLib=(TLBImpLib*)TLB_Alloc(sizeof(TLBImpLib));
+            (*ppImpLib)->offset=offset - tlbSegDir.pImpFiles.offset;
+            TLB_Read(&oGuid, sizeof(INT), &cx, offset);
+            TLB_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
+            /* we are skipping some unknown info here */
+            TLB_Read(& size,sizeof(UINT16), &cx, offset+3*(sizeof(INT)));
+            size >>=2;
+            (*ppImpLib)->name=(CHAR*)TLB_Alloc(size+1);
+            TLB_Read((*ppImpLib)->name,size, &cx, DO_NOT_SEEK);
+            offset=(offset+3*(sizeof(INT))+sizeof(UINT16)+size+3) & 0xfffffffc;
+
+            ppImpLib=&(*ppImpLib)->next;
+        }
+    }
+    /* type info's */
+    if(tlbHeader.nrtypeinfos >=0 ){
+        /*pLibInfo->TypeInfoCount=tlbHeader.nrtypeinfos; */
+        TLBTypeInfo **ppTI=&(pLibInfo->pTypeInfo);
+        int i;
+        for(i=0;i<(int)tlbHeader.nrtypeinfos;i++){
+            *ppTI=TLB_DoTypeInfo(&cx, i, pLibInfo);
+            ppTI=&((*ppTI)->next);
+            (pLibInfo->TypeInfoCount)++;
+        }
+    }
+
+    CloseHandle(cx.hFile);
+    *ppTypeLib=(LPTYPELIB)pLibInfo;
+    return S_OK;
+}
+
+/*================== ITypeLib(2) Methods ===================================*/
+
+/* ITypeLib::QueryInterface
+ */
+static HRESULT WINAPI ITypeLib_fnQueryInterface( LPTYPELIB This, REFIID riid,
+    VOID **ppvObject)
+{
+    if(TRACE_ON(typelib)){
+        char xriid[50];
+        WINE_StringFromCLSID((LPCLSID)riid,xriid);
+        TRACE_(typelib)("(%p)->(IID: %s)\n",This,xriid);
+    }
+    *ppvObject=NULL;
+    if(IsEqualIID(riid, &IID_IUnknown) || 
+            IsEqualIID(riid,&IID_ITypeLib)||
+            IsEqualIID(riid,&IID_ITypeLib2))
+        *ppvObject = This;
+    if(*ppvObject){
+        (*(LPTYPELIB*)ppvObject)->lpvtbl->fnAddRef(This);
+        TRACE_(typelib)("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
+        return S_OK;
+    }
+    TRACE_(typelib)("-- Interface: E_NOINTERFACE\n");
+    return E_NOINTERFACE;
+}
+
+/* ITypeLib::AddRef
+ */
+static ULONG WINAPI ITypeLib_fnAddRef( LPTYPELIB iface)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    TRACE_(typelib)("(%p)->ref is %u\n",This, This->ref);
+    return ++(This->ref);
+}
+
+/* ITypeLib::Release
+ */
+static ULONG WINAPI ITypeLib_fnRelease( LPTYPELIB iface)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    FIXME_(typelib)("(%p)->ref is %u:   stub\n",This, This->ref);
+    (This->ref)--;
+    return S_OK;
+}
+
+/* ITypeLib::GetTypeInfoCount
+ * 
+ * Returns the number of type descriptions in the type library
+ */
+static UINT WINAPI ITypeLib_fnGetTypeInfoCount( LPTYPELIB iface)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    TRACE_(typelib)("(%p)->count is %d\n",This, This->TypeInfoCount);
+    return This->TypeInfoCount;
+}
+
+/* ITypeLib::GetTypeInfo
+ *
+ *etrieves the specified type description in the library.
+ */
+static HRESULT WINAPI ITypeLib_fnGetTypeInfo( LPTYPELIB iface, UINT index, 
+    ITypeInfo **ppTInfo)
+{
+    int i;
+	ICOM_THIS( TLBLibInfo, iface);
+	TLBTypeInfo **ppTLBTInfo=(TLBTypeInfo **)ppTInfo;
+    TRACE_(typelib)("(%p) index %d \n",This, index);
+    for(i=0,*ppTLBTInfo=This->pTypeInfo;*ppTLBTInfo && i != index;i++)
+        *ppTLBTInfo=(*ppTLBTInfo)->next;
+    if(*ppTLBTInfo){
+        (*ppTLBTInfo)->lpvtbl->fnAddRef(*ppTInfo);
+        TRACE_(typelib)("-- found (%p)->(%p)\n",ppTLBTInfo,*ppTLBTInfo);
+        return S_OK;
+    }
+    TRACE_(typelib)("-- element not found\n");
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+/* ITypeLibs::GetTypeInfoType
+ *
+ * Retrieves the type of a type description.
+ */
+static HRESULT WINAPI ITypeLib_fnGetTypeInfoType( LPTYPELIB iface, UINT index,
+    TYPEKIND *pTKind)
+{
+    int i;
+    TLBTypeInfo *pTInfo;
+	ICOM_THIS( TLBLibInfo, iface);
+    TRACE_(typelib)("(%p) index %d \n",This, index);
+    for(i=0,pTInfo=This->pTypeInfo;pTInfo && i != index;i++)
+        pTInfo=(pTInfo)->next;
+    if(pTInfo){
+        *pTKind=pTInfo->TypeAttr.typekind;
+        TRACE_(typelib)("-- found Type (%p)->%d\n",pTKind,*pTKind);
+        return S_OK;
+    }
+    TRACE_(typelib)("-- element not found\n");
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+/* ITypeLib::GetTypeInfoOfGuid
+ *
+ * Retrieves the type description that corresponds to the specified GUID.
+ *
+ */
+static HRESULT WINAPI ITypeLib_fnGetTypeInfoOfGuid( LPTYPELIB iface,
+				REFGUID guid, ITypeInfo **ppTInfo)
+{
+    int i;
+	ICOM_THIS( TLBLibInfo, iface);
+	TLBTypeInfo **ppTLBTInfo=(TLBTypeInfo **)ppTInfo;
+    if(TRACE_ON(typelib)){
+        char xriid[50];
+        WINE_StringFromCLSID((LPCLSID)guid,xriid);
+        TRACE_(typelib)("(%p) guid %sx)\n",This,xriid);
+    }
+    for(i=0,*ppTLBTInfo=This->pTypeInfo;*ppTLBTInfo && 
+            !IsEqualIID(guid,&(*ppTLBTInfo)->TypeAttr.guid);i++)
+        *ppTLBTInfo=(*ppTLBTInfo)->next;
+    if(*ppTLBTInfo){
+        (*ppTLBTInfo)->lpvtbl->fnAddRef(*ppTInfo);
+        TRACE_(typelib)("-- found (%p)->(%p)\n",ppTLBTInfo,*ppTLBTInfo);
+        return S_OK;
+    }
+    TRACE_(typelib)("-- element not found\n");
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+/* ITypeLib::GetLibAttr
+ *
+ * Retrieves the structure that contains the library's attributes.
+ *
+ */
+static HRESULT WINAPI ITypeLib_fnGetLibAttr( LPTYPELIB iface, 
+    LPTLIBATTR *ppTLibAttr)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    TRACE_(typelib)("(%p)\n",This);
+    /* FIXME: must do a copy here */
+    *ppTLibAttr=&This->LibAttr;
+    return S_OK;
+}
+
+/* ITypeLib::GetTypeComp
+ *
+ * Enables a client compiler to bind to a library's types, variables,
+ * constants, and global functions.
+ *
+ */
+static HRESULT WINAPI ITypeLib_fnGetTypeComp( LPTYPELIB iface,
+    ITypeComp **ppTComp)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    FIXME_(typelib)("(%p): stub!\n",This);
+    return E_NOTIMPL;
+}
+
+/* ITypeLib::GetDocumentation
+ *
+ * Retrieves the library's documentation string, the complete Help file name
+ * and path, and the context identifier for the library Help topic in the Help
+ * file.
+ *
+ */
+static HRESULT WINAPI ITypeLib_fnGetDocumentation( LPTYPELIB iface, INT index,
+    BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, 
+    BSTR *pBstrHelpFile)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    HRESULT result;
+    ITypeInfo *pTInfo;
+    TRACE_(typelib)("(%p) index %d Name(%p) DocString(%p)"
+           " HelpContext(%p) HelpFile(%p)\n",
+        This, index, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
+    if(index<0){ /* documentation for the typelib */
+        if(pBstrName)
+            *pBstrName=TLB_DupAtoBstr(This->Name);
+        if(pBstrDocString)
+            *pBstrName=TLB_DupAtoBstr(This->DocString);
+        if(pdwHelpContext)
+            *pdwHelpContext=This->dwHelpContext;
+        if(pBstrHelpFile)
+            *pBstrName=TLB_DupAtoBstr(This->HelpFile);
+    }else {/* for a typeinfo */
+        result=ITypeLib_fnGetTypeInfo(iface, index, &pTInfo);
+        if(SUCCEEDED(result)){
+            result=ITypeInfo_GetDocumentation(pTInfo, MEMBERID_NIL,  pBstrName,
+                pBstrDocString, pdwHelpContext, pBstrHelpFile);
+            ITypeInfo_Release(pTInfo);
+        }
+        if(!SUCCEEDED(result))
+            return result;
+    }
+    return S_OK;
+}
+
+/* ITypeLib::IsName
+ *
+ * Indicates whether a passed-in string contains the name of a type or member
+ * described in the library.
+ *
+ */
+static HRESULT WINAPI ITypeLib_fnIsName( LPTYPELIB iface, LPOLESTR szNameBuf,
+    ULONG lHashVal, BOOL *pfName)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    TLBTypeInfo *pTInfo;
+    TLBFuncDesc *pFInfo;
+    TLBVarDesc *pVInfo;
+    int i;
+    PCHAR astr= HEAP_strdupWtoA( GetProcessHeap(), 0, szNameBuf );
+    *pfName=TRUE;
+    if(!strcmp(astr,This->Name)) goto ITypeLib_fnIsName_exit;
+    for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
+        if(!strcmp(astr,pTInfo->Name)) goto ITypeLib_fnIsName_exit;
+        for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
+            if(!strcmp(astr,pFInfo->Name)) goto ITypeLib_fnIsName_exit;
+            for(i=0;i<pFInfo->funcdesc.cParams;i++)
+                if(!strcmp(astr,pFInfo->pParamDesc[i].Name))
+                    goto ITypeLib_fnIsName_exit;
+        }
+        for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) ;
+            if(!strcmp(astr,pVInfo->Name)) goto ITypeLib_fnIsName_exit;
+       
+    }
+    *pfName=FALSE;
+
+ITypeLib_fnIsName_exit:
+    TRACE_(typelib)("(%p)slow! search for %s: %s found!\n", This,
+            debugstr_a(astr), *pfName?"NOT":"");
+    
+    HeapFree( GetProcessHeap(), 0, astr );
+    return S_OK;
+}
+
+/* ITypeLib::FindName
+ *
+ * Finds occurrences of a type description in a type library. This may be used
+ * to quickly verify that a name exists in a type library.
+ *
+ */
+static HRESULT WINAPI ITypeLib_fnFindName( LPTYPELIB iface, LPOLESTR szNameBuf,
+    ULONG lHashVal, ITypeInfo **ppTInfo, MEMBERID *rgMemId, UINT16 *pcFound)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    TLBTypeInfo *pTInfo;
+    TLBFuncDesc *pFInfo;
+    TLBVarDesc *pVInfo;
+    int i,j = 0;
+    PCHAR astr= HEAP_strdupWtoA( GetProcessHeap(), 0, szNameBuf );
+    for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
+        if(!strcmp(astr,pTInfo->Name)) goto ITypeLib_fnFindName_exit;
+        for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
+            if(!strcmp(astr,pFInfo->Name)) goto ITypeLib_fnFindName_exit;
+            for(i=0;i<pFInfo->funcdesc.cParams;i++)
+                if(!strcmp(astr,pFInfo->pParamDesc[i].Name))
+                    goto ITypeLib_fnFindName_exit;
+        }
+        for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) ;
+            if(!strcmp(astr,pVInfo->Name)) goto ITypeLib_fnFindName_exit;
+        continue;
+ITypeLib_fnFindName_exit:
+        pTInfo->lpvtbl->fnAddRef((LPTYPEINFO)pTInfo);
+        ppTInfo[j]=(LPTYPEINFO)pTInfo;
+        j++;
+    }
+    TRACE_(typelib)("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
+            This, *pcFound, debugstr_a(astr), j);
+
+    *pcFound=j;
+    
+    HeapFree( GetProcessHeap(), 0, astr );
+    return S_OK;
+}
+
+/* ITypeLib::ReleaseTLibAttr
+ *
+ * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
+ *
+ */
+static VOID WINAPI ITypeLib_fnReleaseTLibAttr( LPTYPELIB iface, TLIBATTR *pTLibAttr)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    TRACE_(typelib)("freeing (%p)\n",This);
+    /* nothing to do */
+}
+
+/* ITypeLib2::GetCustData
+ *
+ * gets the custom data
+ */
+static HRESULT WINAPI ITypeLib2_fnGetCustData( ITypeLib * iface, REFGUID guid, 
+        VARIANT *pVarVal)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    TLBCustData *pCData;
+    for(pCData=This->pCustData; pCData; pCData = pCData->next)
+        if( IsEqualIID(guid, &pCData->guid)) break;
+    if(TRACE_ON(typelib)){
+        char xriid[50];
+        WINE_StringFromCLSID((LPCLSID)guid,xriid);
+        TRACE_(typelib)("(%p) guid %s %s found!x)\n",This,xriid,
+                pCData? "" : "NOT");
+    }
+    if(pCData){
+        VariantInit( pVarVal);
+        VariantCopy( pVarVal, &pCData->data);
+        return S_OK;
+    }
+    return E_INVALIDARG;  /* FIXME: correct? */
+}
+
+/* ITypeLib2::GetLibStatistics
+ *
+ * Returns statistics about a type library that are required for efficient
+ * sizing of hash tables.
+ *
+ */
+static HRESULT WINAPI ITypeLib2_fnGetLibStatistics( ITypeLib * iface, 
+        UINT *pcUniqueNames, UINT *pcchUniqueNames)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    FIXME_(typelib)("(%p): stub!\n", This);
+    if(pcUniqueNames) *pcUniqueNames=1;
+    if(pcchUniqueNames) *pcchUniqueNames=1;
+    return S_OK;
+}
+
+/* ITypeLib2::GetDocumentation2
+ *
+ * Retrieves the library's documentation string, the complete Help file name
+ * and path, the localization context to use, and the context ID for the
+ * library Help topic in the Help file.
+ *
+ */
+static HRESULT WINAPI ITypeLib2_fnGetDocumentation2( ITypeLib * iface, 
+        INT index, LCID lcid, BSTR *pbstrHelpString,
+        INT *pdwHelpStringContext, BSTR *pbstrHelpStringDll)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    HRESULT result;
+    ITypeInfo *pTInfo;
+    FIXME_(typelib)("(%p) index %d lcid %ld half implemented stub!\n", This,
+            index, lcid);
+    /* the help string should be obtained from the helpstringdll,
+     * using the _DLLGetDocumentation function, based on the supplied
+     * lcid. Nice to do sometime...
+     */
+    if(index<0){ /* documentation for the typelib */
+        if(pbstrHelpString)
+            *pbstrHelpString=TLB_DupAtoBstr(This->DocString);
+        if(pdwHelpStringContext)
+            *pdwHelpStringContext=This->dwHelpContext;
+        if(pbstrHelpStringDll)
+            *pbstrHelpStringDll=TLB_DupAtoBstr(This->HelpStringDll);
+    }else {/* for a typeinfo */
+        result=ITypeLib_fnGetTypeInfo(iface, index, &pTInfo);
+        if(SUCCEEDED(result)){
+            result=ITypeInfo2_fnGetDocumentation2(pTInfo, MEMBERID_NIL, lcid,
+                pbstrHelpString, pdwHelpStringContext, pbstrHelpStringDll);
+            ITypeInfo_Release(pTInfo);
+        }
+        if(!SUCCEEDED(result))
+            return result;
+    }
+    return S_OK;
+}
+
+/* ITypeLib2::GetAllCustData
+ *
+ * Gets all custom data items for the library. 
+ *
+ */
+static HRESULT WINAPI ITypeLib2_fnGetAllCustData( ITypeLib * iface,
+        CUSTDATA *pCustData)
+{
+	ICOM_THIS( TLBLibInfo, iface);
+    TLBCustData *pCData;
+    int i;
+    TRACE_(typelib)("(%p) returning %d items\n", This, This->ctCustData); 
+    pCustData->prgCustData = (tagCUSTDATAITEM*)TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
+    if(pCustData->prgCustData ){
+        pCustData->cCustData=This->ctCustData;
+        for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
+            pCustData->prgCustData[i].guid=pCData->guid;
+            VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
+        }
+    }else{
+        ERR_(typelib)(" OUT OF MEMORY! \n");
+        return E_OUTOFMEMORY;
+    }
+    return S_OK;
+}
+
+
+/*================== ITypeInfo(2) Methods ===================================*/
+
+/* ITypeInfo::QueryInterface
+ */
+static HRESULT WINAPI ITypeInfo_fnQueryInterface( LPTYPEINFO iface, REFIID riid,
+    VOID **ppvObject)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    if(TRACE_ON(typelib)){
+        char xriid[50];
+        WINE_StringFromCLSID((LPCLSID)riid,xriid);
+        TRACE_(typelib)("(%p)->(IID: %s)\n",This,xriid);
+    }
+    *ppvObject=NULL;
+    if(IsEqualIID(riid, &IID_IUnknown) || 
+            IsEqualIID(riid,&IID_ITypeInfo)||
+            IsEqualIID(riid,&IID_ITypeInfo2))
+        *ppvObject = This;
+    if(*ppvObject){
+        (*(LPTYPEINFO*)ppvObject)->lpvtbl->fnAddRef(iface);
+        TRACE_(typelib)("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
+        return S_OK;
+    }
+    TRACE_(typelib)("-- Interface: E_NOINTERFACE\n");
+    return E_NOINTERFACE;
+}
+
+/* ITypeInfo::AddRef
+ */
+static ULONG WINAPI ITypeInfo_fnAddRef( LPTYPEINFO iface)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TRACE_(typelib)("(%p)->ref is %u\n",This, This->ref);
+    (This->pTypeLib->ref)++;
+    return ++(This->ref);
+}
+
+/* ITypeInfo::Release
+ */
+static ULONG WINAPI ITypeInfo_fnRelease( LPTYPEINFO iface)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    FIXME_(typelib)("(%p)->ref is %u:   stub\n",This, This->ref);
+    (This->ref)--;
+    (This->pTypeLib->ref)--;
+    return S_OK;
+}
+
+/* ITypeInfo::GetTypeAttr
+ *
+ * Retrieves a TYPEATTR structure that contains the attributes of the type
+ * description.
+ *
+ */
+static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( LPTYPEINFO iface,
+        LPTYPEATTR  *ppTypeAttr)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+     TRACE_(typelib)("(%p)\n",This);
+    /* FIXME: must do a copy here */
+    *ppTypeAttr=&This->TypeAttr;
+    return S_OK;
+}
+
+/* ITypeInfo::GetTypeComp
+ *
+ * Retrieves the ITypeComp interface for the type description, which enables a
+ * client compiler to bind to the type description's members.
+ *
+ */
+static HRESULT WINAPI ITypeInfo_fnGetTypeComp( LPTYPEINFO iface,
+        ITypeComp  * *ppTComp)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    FIXME_(typelib)("(%p) stub!\n", This);
+    return S_OK;
+}
+
+/* ITypeInfo::GetFuncDesc
+ *
+ * Retrieves the FUNCDESC structure that contains information about a
+ * specified function.
+ *
+ */
+static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( LPTYPEINFO iface, UINT index,
+        LPFUNCDESC  *ppFuncDesc)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    int i;
+    TLBFuncDesc * pFDesc; 
+    TRACE_(typelib)("(%p) index %d\n", This, index);
+    for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
+        ;
+    if(pFDesc){
+        /* FIXME: must do a copy here */
+        *ppFuncDesc=&pFDesc->funcdesc;
+        return S_OK;
+    }
+    return E_INVALIDARG;
+}
+
+/* ITypeInfo::GetVarDesc
+ *
+ * Retrieves a VARDESC structure that describes the specified variable. 
+ *
+ */
+static HRESULT WINAPI ITypeInfo_fnGetVarDesc( LPTYPEINFO iface, UINT index,
+        LPVARDESC  *ppVarDesc)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    int i;
+    TLBVarDesc * pVDesc; 
+    TRACE_(typelib)("(%p) index %d\n", This, index);
+    for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next)
+        ;
+    if(pVDesc){
+        /* FIXME: must do a copy here */
+        *ppVarDesc=&pVDesc->vardesc;
+        return S_OK;
+    }
+    return E_INVALIDARG;
+}
+
+/* ITypeInfo_GetNames
+ *
+ * Retrieves the variable with the specified member ID (or the name of the
+ * property or method and its parameters) that correspond to the specified
+ * function ID.
+ */
+static HRESULT WINAPI ITypeInfo_fnGetNames( LPTYPEINFO iface, MEMBERID memid,
+        BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBFuncDesc * pFDesc; 
+    TLBVarDesc * pVDesc; 
+    int i;
+    TRACE_(typelib)("(%p) memid=0x%08lx Maxname=%d\n", This, memid,
+            cMaxNames);
+    for(pFDesc=This->funclist; pFDesc->funcdesc.memid != memid && pFDesc;
+            pFDesc=pFDesc->next)
+        ;
+    if(pFDesc){
+        /* function found, now return function and parameter names */
+        for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++){
+            if(!i) *rgBstrNames=TLB_DupAtoBstr(pFDesc->Name);
+            else
+                rgBstrNames[i]=TLB_DupAtoBstr(pFDesc->pParamDesc[i-1].Name);
+                
+        }
+        *pcNames=i;
+    }else{
+        for(pVDesc=This->varlist; pVDesc->vardesc.memid != memid && pVDesc;
+                pVDesc=pVDesc->next)
+            ;
+        if(pVDesc){
+            *rgBstrNames=TLB_DupAtoBstr(pFDesc->Name);
+            *pcNames=1;
+        }else{
+            if(This->TypeAttr.typekind==TKIND_INTERFACE && 
+                    This->TypeAttr.cImplTypes ){
+                /* recursive search */
+                ITypeInfo *pTInfo;
+                HRESULT result;
+                result=This->lpvtbl->fnGetRefTypeInfo(iface, 
+                        This->impltypelist->reference, &pTInfo);
+                if(SUCCEEDED(result)){
+                    result=pTInfo->lpvtbl->fnGetNames(pTInfo, memid, rgBstrNames,
+                            cMaxNames, pcNames);
+                    pTInfo->lpvtbl->fnRelease(pTInfo);
+                    return result;
+                }
+                WARN_(typelib)("Could not search inherited interface!\n");
+            } else
+                WARN_(typelib)("no names found\n");
+            *pcNames=0;
+            return TYPE_E_ELEMENTNOTFOUND;
+        }
+    }
+    return S_OK;
+}
+
+
+/* ITypeInfo::GetRefTypeOfImplType
+ *
+ * If a type description describes a COM class, it retrieves the type
+ * description of the implemented interface types. For an interface,
+ * GetRefTypeOfImplType returns the type information for inherited interfaces,
+ * if any exist.
+ *
+ */
+static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType( LPTYPEINFO iface,
+        UINT index, HREFTYPE  *pRefType)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    int(i);
+    TLBRefType *pIref;
+    TRACE_(typelib)("(%p) index %d\n", This, index);
+    for(i=0, pIref=This->impltypelist; i<index && pIref;
+            i++, pIref=pIref->next)
+        ;
+    if(i==index){
+        *pRefType=pIref->reference;
+        return S_OK;
+    }
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+/* ITypeInfo::GetImplTypeFlags
+ * 
+ * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface 
+ * or base interface in a type description.
+ */
+static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( LPTYPEINFO iface,
+        UINT index, INT  *pImplTypeFlags)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    int(i);
+    TLBRefType *pIref;
+    TRACE_(typelib)("(%p) index %d\n", This, index);
+    for(i=0, pIref=This->impltypelist; i<index && pIref; i++, pIref=pIref->next)
+        ;
+    if(i==index && pIref){
+        *pImplTypeFlags=pIref->flags;
+        return S_OK;
+    }
+    *pImplTypeFlags=0;
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+/* GetIDsOfNames
+ * Maps between member names and member IDs, and parameter names and
+ * parameter IDs.
+ */
+static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( LPTYPEINFO iface,
+        LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBFuncDesc * pFDesc; 
+    TLBVarDesc * pVDesc; 
+    HRESULT ret=S_OK;
+    PCHAR aszName= HEAP_strdupWtoA( GetProcessHeap(), 0, *rgszNames);
+    TRACE_(typelib)("(%p) Name %s cNames %d\n", This, debugstr_a(aszName),
+            cNames);
+    for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
+        int i, j;
+        if( !strcmp(aszName, pFDesc->Name)) {
+            if(cNames) *pMemId=pFDesc->funcdesc.memid;
+            for(i=1; i < cNames; i++){
+                PCHAR aszPar= HEAP_strdupWtoA( GetProcessHeap(), 0,
+                        rgszNames[i]);
+                for(j=0; j<pFDesc->funcdesc.cParams; j++)
+                    if(strcmp(aszPar,pFDesc->pParamDesc[j].Name))
+                            break;
+                if( j<pFDesc->funcdesc.cParams)
+                    pMemId[i]=j;
+                else
+                   ret=DISP_E_UNKNOWNNAME;
+                HeapFree( GetProcessHeap(), 0, aszPar);         
+            };
+            HeapFree (GetProcessHeap(), 0, aszName);
+            return ret;
+        }
+    }   
+    for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
+        if( !strcmp(aszName, pVDesc->Name)) {
+            if(cNames) *pMemId=pVDesc->vardesc.memid;
+            HeapFree (GetProcessHeap(), 0, aszName);
+            return ret;
+        }
+    }
+    /* not found, see if this is and interface with an inheritance */       
+    if(This->TypeAttr.typekind==TKIND_INTERFACE && 
+            This->TypeAttr.cImplTypes ){
+        /* recursive search */
+        ITypeInfo *pTInfo;
+        ret=This->lpvtbl->fnGetRefTypeInfo(iface, 
+                This->impltypelist->reference, &pTInfo);
+        if(SUCCEEDED(ret)){
+            ret=pTInfo->lpvtbl->fnGetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
+            pTInfo->lpvtbl->fnRelease(pTInfo);
+            return ret;
+        }
+        WARN_(typelib)("Could not search inherited interface!\n");
+    } else
+        WARN_(typelib)("no names found\n");
+    return DISP_E_UNKNOWNNAME;
+}
+
+/* ITypeInfo::Invoke
+ * 
+ * Invokes a method, or accesses a property of an object, that implements the
+ * interface described by the type description.
+ */
+static HRESULT WINAPI ITypeInfo_fnInvoke( LPTYPEINFO iface, VOID  *pIUnk,
+        MEMBERID memid, UINT16 dwFlags, DISPPARAMS  *pDispParams,
+        VARIANT  *pVarResult, EXCEPINFO  *pExcepInfo, UINT  *pArgErr)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    FIXME_(typelib)("(%p) stub!", This);
+    return S_OK;
+}
+
+/* ITypeInfo::GetDocumentation
+ * 
+ * Retrieves the documentation string, the complete Help file name and path,
+ * and the context ID for the Help topic for a specified type description.
+ */
+static HRESULT WINAPI ITypeInfo_fnGetDocumentation( LPTYPEINFO iface,
+        MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
+        DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBFuncDesc * pFDesc; 
+    TLBVarDesc * pVDesc; 
+    TRACE_(typelib)("(%p) memid %ld Name(%p) DocString(%p)"
+           " HelpContext(%p) HelpFile(%p)\n",
+        This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
+    if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
+        if(pBstrName)
+            *pBstrName=TLB_DupAtoBstr(This->Name);
+        if(pBstrDocString)
+            *pBstrDocString=TLB_DupAtoBstr(This->DocString);
+        if(pdwHelpContext)
+            *pdwHelpContext=This->dwHelpContext;
+        if(pBstrHelpFile)
+            *pBstrHelpFile=TLB_DupAtoBstr(This->DocString);/* FIXME */
+        return S_OK;
+    }else {/* for a member */
+    for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
+        if(pFDesc->funcdesc.memid==memid){
+            return S_OK;
+        }
+    for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
+        if(pVDesc->vardesc.memid==memid){
+            return S_OK;
+        }
+    }
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+/*  ITypeInfo::GetDllEntry
+ * 
+ * Retrieves a description or specification of an entry point for a function
+ * in a DLL.
+ */
+static HRESULT WINAPI ITypeInfo_fnGetDllEntry( LPTYPEINFO iface, MEMBERID memid,
+        INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
+        WORD  *pwOrdinal)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    FIXME_(typelib)("(%p) stub!\n", This);
+    return E_FAIL;
+}
+
+/* ITypeInfo::GetRefTypeInfo
+ * 
+ * If a type description references other type descriptions, it retrieves
+ * the referenced type descriptions.
+ */
+static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( LPTYPEINFO iface,
+        HREFTYPE hRefType, ITypeInfo  * *ppTInfo)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    HRESULT result;
+    if(HREFTYPE_INTHISFILE(hRefType)){
+        ITypeLib *pTLib;
+        int Index;
+        result=This->lpvtbl->fnGetContainingTypeLib(iface, &pTLib, 
+                (UINT*)&Index);
+        if(SUCCEEDED(result)){
+            result=pTLib->lpvtbl->fnGetTypeInfo(pTLib,
+                    HREFTYPE_INDEX(hRefType),
+                    ppTInfo);
+            pTLib->lpvtbl->fnRelease(pTLib );
+        }
+    } else{
+        /* imported type lib */
+        TLBRefType * pRefType;
+        TLBLibInfo *pTypeLib;
+        for( pRefType=This->impltypelist; pRefType &&
+                pRefType->reference != hRefType; pRefType=pRefType->next)
+            ;
+        if(!pRefType)
+            return TYPE_E_ELEMENTNOTFOUND; /* FIXME : correct? */
+        pTypeLib=pRefType->pImpTLInfo->pImpTypeLib;
+        if(pTypeLib) /* typelib already loaded */
+            result=pTypeLib->lpvtbl->fnGetTypeInfoOfGuid(
+                    (LPTYPELIB)pTypeLib, &pRefType->guid, ppTInfo);
+        else{
+            result=LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
+                    0,0,0, /* FIXME */
+                    (LPTYPELIB *)&pTypeLib);
+            if(!SUCCEEDED(result)){
+                BSTR libnam=TLB_DupAtoBstr(pRefType->pImpTLInfo->name);
+                result=LoadTypeLib(libnam, (LPTYPELIB *)&pTypeLib);
+                SysFreeString(libnam);
+            }
+            if(SUCCEEDED(result)){
+                result=pTypeLib->lpvtbl->fnGetTypeInfoOfGuid(
+                        (LPTYPELIB)pTypeLib, &pRefType->guid, ppTInfo);
+                pRefType->pImpTLInfo->pImpTypeLib=pTypeLib;
+           }
+        }
+    }
+    TRACE_(typelib)("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType,
+            SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
+    return result;
+}
+
+/* ITypeInfo::AddressOfMember
+ * 
+ * Retrieves the addresses of static functions or variables, such as those
+ * defined in a DLL.
+ */
+static HRESULT WINAPI ITypeInfo_fnAddressOfMember( LPTYPEINFO iface,
+        MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    FIXME_(typelib)("(%p) stub!\n", This);
+    return S_OK;
+}
+
+/* ITypeInfo::CreateInstance
+ * 
+ * Creates a new instance of a type that describes a component object class 
+ * (coclass).
+ */
+static HRESULT WINAPI ITypeInfo_fnCreateInstance( LPTYPEINFO iface, 
+        IUnknown *pUnk, REFIID riid, VOID  **ppvObj) 
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    FIXME_(typelib)("(%p) stub!\n", This);
+    return S_OK;
+}
+
+/* ITypeInfo::GetMops
+ *
+ * Retrieves marshaling information.
+ */
+static HRESULT WINAPI ITypeInfo_fnGetMops( LPTYPEINFO iface, MEMBERID memid,
+				BSTR  *pBstrMops)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    FIXME_(typelib)("(%p) stub!\n", This);
+    return S_OK;
+}
+
+/* ITypeInfo::GetContainingTypeLib
+ * 
+ * Retrieves the containing type library and the index of the type description
+ * within that type library.
+ */
+static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( LPTYPEINFO iface,
+        ITypeLib  * *ppTLib, UINT  *pIndex)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    *ppTLib=(LPTYPELIB )(This->pTypeLib);
+    *pIndex=This->index;
+    (*ppTLib)->lpvtbl->fnAddRef(*ppTLib);
+    TRACE_(typelib)("(%p) returns (%p) index %d!\n", This, *ppTLib, *pIndex);
+    return S_OK;
+}
+
+/* ITypeInfo::ReleaseTypeAttr
+ *
+ * Releases a TYPEATTR previously returned by GetTypeAttr.
+ *
+ */
+static HRESULT WINAPI ITypeInfo_fnReleaseTypeAttr( LPTYPEINFO iface,
+        TYPEATTR* pTypeAttr)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TRACE_(typelib)("(%p)->(%p)\n", This, pTypeAttr);
+    return S_OK;
+}
+
+/* ITypeInfo::ReleaseFuncDesc
+ *
+ * Releases a FUNCDESC previously returned by GetFuncDesc. *
+ */
+static HRESULT WINAPI ITypeInfo_fnReleaseFuncDesc( LPTYPEINFO iface,
+        FUNCDESC *pFuncDesc)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TRACE_(typelib)("(%p)->(%p)\n", This, pFuncDesc);
+    return S_OK;
+}
+
+/* ITypeInfo::ReleaseVarDesc
+ *
+ * Releases a VARDESC previously returned by GetVarDesc.
+ */
+static HRESULT WINAPI ITypeInfo_fnReleaseVarDesc( LPTYPEINFO iface,
+        VARDESC *pVarDesc)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TRACE_(typelib)("(%p)->(%p)\n", This, pVarDesc);
+    return S_OK;
+}
+
+/* ITypeInfo2::GetTypeKind
+ *
+ * Returns the TYPEKIND enumeration quickly, without doing any allocations.
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo * iface,
+    TYPEKIND *pTypeKind)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    *pTypeKind=This->TypeAttr.typekind;
+    TRACE_(typelib)("(%p) type 0x%0x\n", This,*pTypeKind);
+    return S_OK;
+}
+
+/* ITypeInfo2::GetTypeFlags
+ *
+ * Returns the type flags without any allocations. This returns a DWORD type
+ * flag, which expands the type flags without growing the TYPEATTR (type
+ * attribute). 
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo * iface,
+    UINT *pTypeFlags)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    *pTypeFlags=This->TypeAttr.wTypeFlags;
+    TRACE_(typelib)("(%p) flags 0x%04x\n", This,*pTypeFlags);
+     return S_OK;
+}
+
+/* ITypeInfo2::GetFuncIndexOfMemId
+ * Binds to a specific member based on a known DISPID, where the member name
+ * is not known (for example, when binding to a default member).
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo * iface,
+    MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBFuncDesc *pFuncInfo;
+    int i;
+    HRESULT result;
+    /* FIXME: should check for invKind??? */
+    for(i=0, pFuncInfo=This->funclist;pFuncInfo && 
+            memid != pFuncInfo->funcdesc.memid; i++, pFuncInfo=pFuncInfo->next);
+    if(pFuncInfo){
+        *pFuncIndex=i;
+        result= S_OK;
+    }else{
+        *pFuncIndex=0;
+        result=E_INVALIDARG;
+    }
+    TRACE_(typelib)("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This,
+            memid, invKind, SUCCEEDED(result)? "SUCCES":"FAILED");
+    return result;
+}
+
+/* TypeInfo2::GetVarIndexOfMemId
+ *
+ * Binds to a specific member based on a known DISPID, where the member name
+ * is not known (for example, when binding to a default member). 
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo * iface,
+    MEMBERID memid, UINT *pVarIndex)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBVarDesc *pVarInfo;
+    int i;
+    HRESULT result;
+    for(i=0, pVarInfo=This->varlist; pVarInfo && 
+            memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next)
+        ;
+    if(pVarInfo){
+        *pVarIndex=i;
+        result= S_OK;
+    }else{
+        *pVarIndex=0;
+        result=E_INVALIDARG;
+    }
+    TRACE_(typelib)("(%p) memid 0x%08lx -> %s\n", This,
+            memid, SUCCEEDED(result)? "SUCCES":"FAILED");
+    return result;
+}
+
+/* ITypeInfo2::GetCustData
+ *
+ * Gets the custom data
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetCustData( ITypeInfo * iface,
+    REFGUID guid, VARIANT *pVarVal)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBCustData *pCData;
+    for(pCData=This->pCustData; pCData; pCData = pCData->next)
+        if( IsEqualIID(guid, &pCData->guid)) break;
+    if(TRACE_ON(typelib)){
+        char xriid[50];
+        WINE_StringFromCLSID((LPCLSID)guid,xriid);
+        TRACE_(typelib)("(%p) guid %s %s found!x)\n", This, xriid,
+                pCData? "" : "NOT");
+    }
+    if(pCData){
+        VariantInit( pVarVal);
+        VariantCopy( pVarVal, &pCData->data);
+        return S_OK;
+    }
+    return E_INVALIDARG;  /* FIXME: correct? */
+}
+
+/* ITypeInfo2::GetFuncCustData
+ *
+ * Gets the custom data
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData( ITypeInfo * iface,
+    UINT index, REFGUID guid, VARIANT *pVarVal)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBCustData *pCData=NULL;
+    TLBFuncDesc * pFDesc; 
+    int i;
+    for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
+            pFDesc=pFDesc->next)
+        ;
+    if(pFDesc)
+        for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next)
+            if( IsEqualIID(guid, &pCData->guid)) break;
+    if(TRACE_ON(typelib)){
+        char xriid[50];
+        WINE_StringFromCLSID((LPCLSID)guid,xriid);
+        TRACE_(typelib)("(%p) guid %s %s found!x)\n",This,xriid,
+                pCData? "" : "NOT");
+    }
+    if(pCData){
+        VariantInit( pVarVal);
+        VariantCopy( pVarVal, &pCData->data);
+        return S_OK;
+    }
+    return E_INVALIDARG;  /* FIXME: correct? */
+}
+
+/* ITypeInfo2::GetParamCustData
+ *
+ * Gets the custom data
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetParamCustData( ITypeInfo * iface,
+    UINT indexFunc, UINT indexParam, REFGUID guid, VARIANT *pVarVal)
+{   
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBCustData *pCData=NULL;
+    TLBFuncDesc * pFDesc; 
+    int i;
+    for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
+            pFDesc=pFDesc->next)
+        ;
+    if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams)
+        for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData; 
+                pCData = pCData->next)
+            if( IsEqualIID(guid, &pCData->guid)) break;
+    if(TRACE_ON(typelib)){
+        char xriid[50];
+        WINE_StringFromCLSID((LPCLSID)guid,xriid);
+        TRACE_(typelib)("(%p) guid %s %s found!x)\n",This,xriid,
+                pCData? "" : "NOT");
+    }
+    if(pCData){
+        VariantInit( pVarVal);
+        VariantCopy( pVarVal, &pCData->data);
+        return S_OK;
+    }
+    return E_INVALIDARG;  /* FIXME: correct? */
+}
+
+/* ITypeInfo2::GetVarcCustData
+ *
+ * Gets the custom data
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetVarCustData( ITypeInfo * iface,
+    UINT index, REFGUID guid, VARIANT *pVarVal)
+{   
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBCustData *pCData=NULL;
+    TLBVarDesc * pVDesc; 
+    int i;
+    for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
+            pVDesc=pVDesc->next)
+        ;
+    if(pVDesc)
+        for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next)
+            if( IsEqualIID(guid, &pCData->guid)) break;
+    if(TRACE_ON(typelib)){
+        char xriid[50];
+        WINE_StringFromCLSID((LPCLSID)guid,xriid);
+        TRACE_(typelib)("(%p) guid %s %s found!x)\n",This,xriid,
+                pCData? "" : "NOT");
+    }
+    if(pCData){
+        VariantInit( pVarVal);
+        VariantCopy( pVarVal, &pCData->data);
+        return S_OK;
+    }
+    return E_INVALIDARG;  /* FIXME: correct? */
+}
+
+/* ITypeInfo2::GetImplcCustData
+ *
+ * Gets the custom data
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData( ITypeInfo * iface,
+    UINT index, REFGUID guid, VARIANT *pVarVal)
+{   
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBCustData *pCData=NULL;
+    TLBRefType * pRDesc; 
+    int i;
+    for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
+            pRDesc=pRDesc->next)
+        ;
+    if(pRDesc)
+        for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next)
+            if( IsEqualIID(guid, &pCData->guid)) break;
+    if(TRACE_ON(typelib)){
+        char xriid[50];
+        WINE_StringFromCLSID((LPCLSID)guid,xriid);
+        TRACE_(typelib)("(%p) guid %s %s found!x)\n",This,xriid,
+                pCData? "" : "NOT");
+    }
+    if(pCData){
+        VariantInit( pVarVal);
+        VariantCopy( pVarVal, &pCData->data);
+        return S_OK;
+    }
+    return E_INVALIDARG;  /* FIXME: correct? */
+}
+
+/* ITypeInfo2::GetDocumentation2
+ * 
+ * Retrieves the documentation string, the complete Help file name and path,
+ * the localization context to use, and the context ID for the library Help
+ * topic in the Help file.
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2( ITypeInfo * iface,
+    MEMBERID memid, LCID lcid, BSTR *pbstrHelpString,
+    INT *pdwHelpStringContext, BSTR *pbstrHelpStringDll)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBFuncDesc * pFDesc; 
+    TLBVarDesc * pVDesc; 
+    TRACE_(typelib)("(%p) memid %ld lcid(0x%lx)  HelpString(%p) "
+           "HelpStringContext(%p) HelpStringDll(%p)\n",
+        This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
+        pbstrHelpStringDll );
+    /* the help string should be obtained from the helpstringdll,
+     * using the _DLLGetDocumentation function, based on the supplied
+     * lcid. Nice to do sometime...
+     */
+    if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
+        if(pbstrHelpString)
+            *pbstrHelpString=TLB_DupAtoBstr(This->Name);
+        if(pdwHelpStringContext)
+            *pdwHelpStringContext=This->dwHelpStringContext;
+        if(pbstrHelpStringDll)
+            *pbstrHelpStringDll=
+                TLB_DupAtoBstr(This->pTypeLib->HelpStringDll);/* FIXME */
+        return S_OK;
+    }else {/* for a member */
+    for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
+        if(pFDesc->funcdesc.memid==memid){
+             if(pbstrHelpString)
+                *pbstrHelpString=TLB_DupAtoBstr(pFDesc->HelpString);
+            if(pdwHelpStringContext)
+                *pdwHelpStringContext=pFDesc->HelpStringContext;
+            if(pbstrHelpStringDll)
+                *pbstrHelpStringDll=
+                    TLB_DupAtoBstr(This->pTypeLib->HelpStringDll);/* FIXME */
+        return S_OK;
+    }
+    for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
+        if(pVDesc->vardesc.memid==memid){
+             if(pbstrHelpString)
+                *pbstrHelpString=TLB_DupAtoBstr(pVDesc->HelpString);
+            if(pdwHelpStringContext)
+                *pdwHelpStringContext=pVDesc->HelpStringContext;
+            if(pbstrHelpStringDll)
+                *pbstrHelpStringDll=
+                    TLB_DupAtoBstr(This->pTypeLib->HelpStringDll);/* FIXME */
+            return S_OK;
+        }
+    }
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+/* ITypeInfo2::GetAllCustData
+ *
+ * Gets all custom data items for the Type info. 
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetAllCustData( ITypeInfo * iface,
+    CUSTDATA *pCustData)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBCustData *pCData;
+    int i;
+    TRACE_(typelib)("(%p) returning %d items\n", This, This->ctCustData); 
+    pCustData->prgCustData = (tagCUSTDATAITEM*)TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM));
+    if(pCustData->prgCustData ){
+        pCustData->cCustData=This->ctCustData;
+        for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){
+            pCustData->prgCustData[i].guid=pCData->guid;
+            VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
+        }
+    }else{
+        ERR_(typelib)(" OUT OF MEMORY! \n");
+        return E_OUTOFMEMORY;
+    }
+    return S_OK;
+}
+
+/* ITypeInfo2::GetAllFuncCustData
+ *
+ * Gets all custom data items for the specified Function
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData( ITypeInfo * iface,
+    UINT index, CUSTDATA *pCustData)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBCustData *pCData;
+    TLBFuncDesc * pFDesc; 
+    int i;
+    TRACE_(typelib)("(%p) index %d\n", This, index); 
+    for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
+            pFDesc=pFDesc->next)
+        ;
+    if(pFDesc){
+        pCustData->prgCustData =(tagCUSTDATAITEM*)
+            TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM));
+        if(pCustData->prgCustData ){
+            pCustData->cCustData=pFDesc->ctCustData;
+            for(i=0, pCData=pFDesc->pCustData; pCData; i++,
+                    pCData = pCData->next){
+                pCustData->prgCustData[i].guid=pCData->guid;
+                VariantCopy(& pCustData->prgCustData[i].varValue,
+                        & pCData->data);
+            }
+        }else{
+            ERR_(typelib)(" OUT OF MEMORY! \n");
+            return E_OUTOFMEMORY;
+        }
+        return S_OK;
+    }
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+/* ITypeInfo2::GetAllParamCustData
+ *
+ * Gets all custom data items for the Functions
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo * iface,
+    UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBCustData *pCData=NULL;
+    TLBFuncDesc * pFDesc; 
+    int i;
+    TRACE_(typelib)("(%p) index %d\n", This, indexFunc); 
+    for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,
+            pFDesc=pFDesc->next)
+        ;
+    if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){
+        pCustData->prgCustData =(tagCUSTDATAITEM*) 
+            TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData *
+                    sizeof(CUSTDATAITEM));
+        if(pCustData->prgCustData ){
+            pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData;
+            for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData;
+                    pCData; i++, pCData = pCData->next){
+                pCustData->prgCustData[i].guid=pCData->guid;
+                VariantCopy(& pCustData->prgCustData[i].varValue,
+                        & pCData->data);
+            }
+        }else{
+            ERR_(typelib)(" OUT OF MEMORY! \n");
+            return E_OUTOFMEMORY;
+        }
+        return S_OK;
+    }
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+/* ITypeInfo2::GetAllVarCustData
+ *
+ * Gets all custom data items for the specified Variable
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo * iface,
+    UINT index, CUSTDATA *pCustData)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBCustData *pCData;
+    TLBVarDesc * pVDesc; 
+    int i;
+    TRACE_(typelib)("(%p) index %d\n", This, index); 
+    for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
+            pVDesc=pVDesc->next)
+        ;
+    if(pVDesc){
+        pCustData->prgCustData =(tagCUSTDATAITEM*)
+            TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM));
+        if(pCustData->prgCustData ){
+            pCustData->cCustData=pVDesc->ctCustData;
+            for(i=0, pCData=pVDesc->pCustData; pCData; i++,
+                    pCData = pCData->next){
+                pCustData->prgCustData[i].guid=pCData->guid;
+                VariantCopy(& pCustData->prgCustData[i].varValue,
+                        & pCData->data);
+            }
+        }else{
+            ERR_(typelib)(" OUT OF MEMORY! \n");
+            return E_OUTOFMEMORY;
+        }
+        return S_OK;
+    }
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+/* ITypeInfo2::GetAllImplCustData
+ *
+ * Gets all custom data items for the specified implementation type
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData( ITypeInfo * iface,
+    UINT index, CUSTDATA *pCustData)
+{
+	ICOM_THIS( TLBTypeInfo, iface);
+    TLBCustData *pCData;
+    TLBRefType * pRDesc; 
+    int i;
+    TRACE_(typelib)("(%p) index %d\n", This, index); 
+    for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
+            pRDesc=pRDesc->next)
+        ;
+    if(pRDesc){
+        pCustData->prgCustData =(tagCUSTDATAITEM*)
+            TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM));
+        if(pCustData->prgCustData ){
+            pCustData->cCustData=pRDesc->ctCustData;
+            for(i=0, pCData=pRDesc->pCustData; pCData; i++,
+                    pCData = pCData->next){
+                pCustData->prgCustData[i].guid=pCData->guid;
+                VariantCopy(& pCustData->prgCustData[i].varValue,
+                        & pCData->data);
+            }
+        }else{
+            ERR_(typelib)(" OUT OF MEMORY! \n");
+            return E_OUTOFMEMORY;
+        }
+        return S_OK;
+    }
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
Index: trunk/src/oleaut32/typelib.h
===================================================================
--- trunk/src/oleaut32/typelib.h	(revision 631)
+++ trunk/src/oleaut32/typelib.h	(revision 631)
@@ -0,0 +1,358 @@
+/*
+ * typelib.h  internal wine data structures
+ * used to decode typelib's
+ *
+ * Copyright 1999 Rein KLazes
+ *  
+ */
+#ifndef _WINE_TYPELIB_H
+#define _WINE_TYPELIB_H
+
+
+#include "ole2.h"
+#include "oleauto.h"
+#include "oaidl.h"
+
+
+#define TLBMAGIC2 "MSFT"
+#define TLBMAGIC1 "SLTG"
+#define HELPDLLFLAG (0x0100)
+#define DO_NOT_SEEK (-1)
+
+#define HREFTYPE_INTHISFILE(href) (!((href) & 3))
+#define HREFTYPE_INDEX(href) ((href) /sizeof(TLBTypeInfoBase))
+
+typedef struct tagTLBCustData {
+    GUID guid;
+    VARIANT data;
+    struct tagTLBCustData* next;
+} TLBCustData;
+
+/* internal Parameter data */
+typedef struct tagTLBParDesc{
+    PCHAR Name;
+    int ctCustData;
+    TLBCustData * pCustData;        /* linked list to cust data; */
+} TLBParDesc;
+
+
+/* internal Function data */
+typedef struct tagTLBFuncDesc{
+    FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
+    PCHAR Name;             /* the name of this function */
+    TLBParDesc *pParamDesc; /* array with name and custom data */
+    int helpcontext;
+    int HelpStringContext;
+    PCHAR HelpString;
+    PCHAR Entry;            /* if its Hiword==0, it numeric; -1 is not present*/
+    int ctCustData;
+    TLBCustData * pCustData;        /* linked list to cust data; */
+    struct tagTLBFuncDesc * next; 
+} TLBFuncDesc;
+
+/* internal Variable data */
+typedef struct tagTLBVarDesc{
+    VARDESC vardesc;        /* lots of info on the variable and its attributes. */
+    PCHAR Name;             /* the name of this variable */
+    int HelpContext;
+    int HelpStringContext;  /* fixme: where? */
+    PCHAR HelpString;
+    int ctCustData;
+    TLBCustData * pCustData;/* linked list to cust data; */
+    struct tagTLBVarDesc * next; 
+} TLBVarDesc;
+
+/* data for refernced types in a coclass, or an inherited interface */
+typedef struct tagTLBRefType {
+    GUID guid;              /* guid of the referenced type */
+                            /* (important if its a imported type) */
+    HREFTYPE reference;
+    int flags;
+    int ctCustData;
+    TLBCustData * pCustData;/* linked list to custom data; */
+    struct tagTLBImpLib *pImpTLInfo;
+    struct tagTLBRefType * next;
+    }TLBRefType;
+
+/* internal TypeInfo data */
+typedef struct tagTYPEINFO {
+    LPTYPEINFO_VTABLE lpvtbl;
+    UINT ref;
+    TYPEATTR TypeAttr ;         /* _lots_ of type information. */
+    struct tagTYPELIB * pTypeLib; /* back pointer to typelib */
+    int index;                  /* index in this typelib; */
+    /* type libs seem to store the doc strings in ascii 
+     * so why should we do it in unicode?
+     */
+    PCHAR Name;
+    PCHAR DocString;
+    unsigned long  dwHelpContext;
+    unsigned long  dwHelpStringContext;
+
+/* functions  */
+    TLBFuncDesc * funclist;     /* linked list with function descriptions */
+/* variables  */
+    TLBVarDesc * varlist;       /* linked list with variable descriptions */
+/* Implemented Interfaces  */
+    TLBRefType * impltypelist;      
+    int ctCustData;
+    TLBCustData * pCustData;        /* linked list to cust data; */
+    struct tagTYPEINFO * next;
+} TLBTypeInfo;
+
+/* data structure for import typelibs */
+typedef struct tagTLBImpLib {
+    int offset;                 /* offset in the file */
+    GUID guid;                  /* libid */
+    PCHAR name;                 /* name; */
+    struct tagTYPELIB *pImpTypeLib; /* pointer to loaded typelib */
+    struct tagTLBImpLib * next;
+    } TLBImpLib;
+
+/* internal TypeLib data */
+typedef struct tagTYPELIB  {
+    LPTYPELIB_VTABLE lpvtbl;
+    UINT ref;
+    TLIBATTR LibAttr;               /* guid,lcid,syskind,version,flags */
+    /* type libs seem to store the doc strings in ascii 
+     * so why should we do it in unicode?
+     */
+    PCHAR Name;
+    PCHAR DocString;
+    PCHAR HelpFile;
+    PCHAR HelpStringDll;
+    unsigned long  dwHelpContext;
+    int TypeInfoCount;          /* nr of typeinfo's in librarry */
+    TLBTypeInfo *pTypeInfo;     /* linked list of type info data */
+    int ctCustData;             /* number of items in cust data list */
+    TLBCustData * pCustData;    /* linked list to cust data; */
+    TLBImpLib   * pImpLibs;     /* linked list to all imported typelibs */
+    TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the libary */
+} TLBLibInfo;
+
+/*-------------------------FILE STRUCTURES-----------------------------------*/
+
+
+/*
+ * structure of the typelib type2 header
+ * it is at the beginning of a type lib file
+ *  
+ */
+typedef struct tagTLB2Header {
+/*0x00*/INT magic1;       /* 0x5446534D "MSFT" */
+        INT   magic2;       /* 0x00010002 version nr? */
+        INT   posguid;      /* position of libid in guid table  */
+                            /* (should be,  else -1) */
+        INT   lcid;         /* locale id */
+/*0x10*/INT   lcid2;
+        INT   varflags;     /* (largely) unknown flags ,seems to be always 41 */
+                            /* becomes 0x51 with a helpfile defined */
+                            /* if help dll defined its 0x151 */
+                            /* update : the lower nibble is syskind */
+        INT   version;      /* set with SetVersion() */
+        INT   flags;        /* set with SetFlags() */
+/*0x20*/INT   nrtypeinfos;  /* number of typeinfo's (till so far) */
+        INT   helpstring;   /* position of help string in stringtable */
+        INT   helpstringcontext;
+        INT   helpcontext;
+/*0x30*/INT   nametablecount;   /* number of names in name table */
+        INT   nametablechars;   /* nr of characters in name table */
+        INT   NameOffset;       /* offset of name in name table */
+        INT   helpfile;         /* position of helpfile in stringtable */
+/*0x40*/INT   CustomDataOffset; /* if -1 no custom data, else it is offset */
+                                /* in customer data/guid offset table */
+        INT   res44;            /* unknown always: 0x20 */
+        INT   res48;            /* unknown always: 0x80 */
+        INT   dispatchpos;      /* gets a value (1+n*0x0c) with Idispatch interfaces */
+/*0x50*/INT   res50;            /* is zero becomes one when an interface is derived */
+} TLB2Header;
+
+/* segments in the type lib file have a structure like this: */
+typedef struct _tptag {
+        INT   offset;       /* absolute offset in file */
+        INT   length;       /* length of segment */
+        INT   res08;        /* unknown always -1 */
+        INT   res0c;        /* unknown always 0x0f in the header */
+                            /* 0x03 in the typeinfo_data */
+} pSeg;
+
+/* layout of the main segment directory */
+typedef struct tagTLBSegDir {
+/*1*/pSeg pTypeInfoTab; /* each type info get an entry of 0x64 bytes */
+                        /* (25 ints) */
+/*2*/pSeg pImpInfo;     /* table with info for imported types */
+/*3*/pSeg pImpFiles;    /* import libaries */
+/*4*/pSeg pRefTab;      /* References table */
+/*5*/pSeg pLibtab;      /* always exists, alway same size (0x80) */
+                        /* hash table w offsets to guid????? */
+/*6*/pSeg pGuidTab;     /* all guids are stored here together with  */
+                        /* offset in some table???? */
+/*7*/pSeg res07;        /* always created, alway same size (0x200) */
+                        /* purpose largely unknown */
+/*8*/pSeg pNametab;     /* name tables */
+/*9*/pSeg pStringtab;   /*string table */
+/*A*/pSeg pTypdescTab;  /* table with type descriptors */
+/*B*/pSeg pArrayDescriptions;
+/*C*/pSeg pCustData;    /*  data table, used for custom data and default */
+                        /* parameter values */
+/*D*/pSeg pCDGuids;     /* table with offsets for the guids and into the customer data table */
+/*E*/pSeg res0e;            /* unknown */
+/*F*/pSeg res0f;            /* unknown  */
+} TLBSegDir;
+
+
+/* base type info data */
+typedef struct tagTLBTypeInfoBase {
+/*000*/ INT   typekind;             /*  it is the TKIND_xxx */
+                                    /* some byte alignment stuf */
+        INT     memoffset;          /* points past the file, if no elements */
+        INT     res2;               /* zero if no element, N*0x40 */
+        INT     res3;               /* -1 if no lement, (N-1)*0x38 */
+/*010*/ INT     res4;               /* always? 3 */
+        INT     res5;               /* always? zero */
+        INT     cElement;           /* counts elements, HI=cVars, LO=cFuncs */
+        INT     res7;               /* always? zero */
+/*020*/ INT     res8;               /* always? zero */
+        INT     res9;               /* always? zero */
+        INT     resA;               /* always? zero */
+        INT     posguid;            /* position in guid table */
+/*030*/ INT     flags;              /* Typeflags */
+        INT     NameOffset;         /* offset in name table */
+        INT     version;            /* element version */
+        INT     docstringoffs;      /* offset of docstring in string tab */
+/*040*/ INT     helpstringcontext;  /*  */
+        INT     helpcontext;    /* */
+        INT     oCustData;          /* offset in customer data table */
+        INT16   cImplTypes;     /* nr of implemented interfaces */
+        INT16   cbSizeVft;      /* virtual table size, not including inherits */
+/*050*/ INT     size;           /* size in bytes, at least for structures */
+        /* fixme: name of this field */
+        INT     datatype1;      /* position in type description table */
+                                /* or in base intefaces */
+                                /* if coclass: offset in reftable */
+                                /* if interface: reference to inherited if */
+        INT     datatype2;      /* if 0x8000, entry above is valid */
+                                /* actually dunno */
+                                /* else it is zero? */
+        INT     res18;          /* always? 0 */
+/*060*/ INT     res19;          /* always? -1 */
+    } TLBTypeInfoBase;
+
+/* layout of an entry with information on imported types */
+typedef struct tagTLBImpInfo {
+    INT     res0;           /* unknown */
+    INT     oImpFile;       /* offset inthe Import File table */
+    INT     oGuid;          /* offset in Guid table */
+    } TLBImpInfo;
+
+/* function description data */
+typedef struct {
+/*  INT   recsize;       record size including some xtra stuff */
+    INT   DataType;     /* data type of the memeber, eg return of function */
+    INT   Flags;        /* something to do with attribute flags (LOWORD) */
+    INT16 VtableOffset; /* offset in vtable */
+    INT16 res3;         /* some offset into dunno what */
+    INT   FKCCIC;       /* bit string with the following  */
+                        /* meaning (bit 0 is the msb): */
+                        /* bit 2 indicates that oEntry is numeric */
+                        /* bit 3 that parameter has default values */
+                        /* calling convention (bits 4-7 ) */
+                        /* bit 8 indicates that custom data is present */
+                        /* Invokation kind (bits 9-12 ) */
+                        /* function kind (eg virtual), bits 13-15  */
+    INT16 nrargs;       /* number of arguments (including optional ????) */
+    INT16 nroargs;      /* nr of optional arguments */
+    /* optional attribute fields, the number of them is variable */
+    INT   OptAttr[1];
+/*
+0*  INT   helpcontext;
+1*  INT   oHelpString;
+2*  INT   oEntry;       // either offset in string table or numeric as it is //
+3*  INT   res9;         // unknown (-1) //
+4*  INT   resA;         // unknown (-1) //
+5*  INT   HelpStringContext;
+    // these are controlled by a bit set in the FKCCIC field  //
+6*  INT   oCustData;        // custom data for function //
+7*  INT   oArgCustData[1];  // custom data per argument //
+*/
+} TLBFuncRecord;
+
+/* after this may follow an array with default value pointers if the 
+ * appropriate bit in the FKCCIC field has been set: 
+ * INT   oDefautlValue[nrargs];
+ */
+
+    /* Parameter info one per argument*/
+typedef struct {
+        INT   DataType;
+        INT   oName;
+        INT   Flags;
+    } TLBParameterInfo;
+
+/* Variable description data */
+typedef struct {
+/*  INT   recsize;      // record size including some xtra stuff */
+    INT   DataType;     /* data type of the variable */
+    INT   Flags;        /* VarFlags (LOWORD) */
+    INT16 VarKind;      /* VarKind */
+    INT16 res3;         /* some offset into dunno what */
+    INT   OffsValue;    /* value of the variable or the offset  */
+                        /* in the data structure */
+    /* optional attribute fields, the number of them is variable */
+    /* controlled by record length */
+    INT   HelpContext;
+    INT   oHelpString;
+    INT   res9;         /* unknown (-1) */
+    INT   oCustData;        /* custom data for variable */
+    INT   HelpStringContext;
+
+} TLBVarRecord;
+
+/* Structure of the reference data  */
+typedef struct {
+    INT   reftype;  /* either offset in type info table, then its */
+                    /* a multiple of 64 */
+                    /* or offset in the external reference table */
+                    /* with an offset of 1 */
+    INT   flags;
+    INT   oCustData;    /* custom data */
+    INT   onext;    /* next offset, -1 if last */
+} TLBRefRecord;
+
+/* this is how a guid is stored */
+typedef struct {
+    GUID guid;
+    INT   unk10;        /* differntiate with libid, classid etc? */
+                        /* its -2 for a libary */
+                        /* it's 0 for an interface */
+    INT   unk14;        /* always? -1 */
+} TLBGuidEntry;
+/* some data preceding entries in the name table */
+typedef struct {
+    INT   unk00;        /* sometimes -1 (lib, parameter) ,
+                           sometimes 0 (interface, func) */
+    INT   unk10;        /* sometimes -1 (lib) , sometimes 0 (interface, func),
+                           sometime 0x10 (par) */
+    INT   namelen;      /* only lower 8 bits are valid */
+} TLBNameIntro;
+/* the custom data table directory has enties like this */
+typedef struct {
+    INT   GuidOffset;
+    INT   DataOffset;
+    INT   next;     /* next offset in the table, -1 if its the last */
+} TLBCDGuid;
+
+
+
+/*---------------------------END--------------------------------------------*/
+
+typedef struct tagTLBContext {
+    HANDLE   hFile;            /* open typelib file  */
+    long oStart;                /* start of TLB in file */
+    TLBSegDir * pTblDir;
+    TLBLibInfo* pLibInfo;
+} TLBContext;
+
+
+#endif
+
Index: trunk/src/oleaut32/variant.cpp
===================================================================
--- trunk/src/oleaut32/variant.cpp	(revision 631)
+++ trunk/src/oleaut32/variant.cpp	(revision 631)
@@ -0,0 +1,4296 @@
+/*
+ * VARIANT
+ *
+ * Copyright 1998 Jean-Claude Cote
+ *
+ * Copyright 1999 Sander van Leeuwen (WINE OS/2 Port 990815)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ * NOTES
+ *   This implements the low-level and hi-level APIs for manipulating VARIANTs.
+ *   The low-level APIs are used to do data coercion between different data types.
+ *   The hi-level APIs are built on top of these low-level APIs and handle
+ *   initialization, copying, destroying and changing the type of VARIANTs.
+ *
+ * TODO:
+ *   - The Variant APIs are do not support international languages, currency
+ *     types, number formating and calendar.  They only support U.S. English format.
+ *   - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
+ *     The prototypes for these are commented out in the oleauto.h file.  They need
+ *     to be implemented and cases need to be added to the switches of the  existing APIs.
+ *   - The parsing of date for the VarDateFromStr is not complete.
+ *   - The date manipulations do not support date prior to 1900.
+ *   - The parsing does not accept has many formats has the Windows implementation.
+ */
+ 
+#include "oleaut32.h"
+#include "windef.h"
+#include "oleauto.h"
+#include "heap.h"
+#include "debugtools.h"
+#include "winerror.h"
+#include "parsedt.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+//#ifdef HAVE_FLOAT_H
+# include <float.h>
+//#endif
+
+#ifndef FLT_MAX
+# ifdef MAXFLOAT
+#  define FLT_MAX MAXFLOAT
+# else
+#  error "Can't find #define for MAXFLOAT/FLT_MAX"
+# endif
+#endif
+
+#undef CHAR_MAX
+#undef CHAR_MIN
+static const char CHAR_MAX = 127;
+static const char CHAR_MIN = -128;
+static const BYTE UI1_MAX = 255;
+static const BYTE UI1_MIN = 0;
+static const unsigned short UI2_MAX = 65535;
+static const unsigned short UI2_MIN = 0;
+static const short I2_MAX = 32767;
+static const short I2_MIN =  -32768;
+static const unsigned long UI4_MAX = 4294967295U;
+static const unsigned long UI4_MIN = 0;
+static const long I4_MAX = 2147483647;
+static const long I4_MIN = -(2147483648U);
+static const DATE DATE_MIN = -657434;
+static const DATE DATE_MAX = 2958465;
+
+
+/* This mask is used to set a flag in wReserved1 of
+ * the VARIANTARG structure. The flag indicates if
+ * the API function is using an inner variant or not.
+ */
+#define PROCESSING_INNER_VARIANT 0x0001
+
+/* General use buffer.
+ */
+#define BUFFER_MAX 1024
+static char pBuffer[BUFFER_MAX];
+
+/*
+ * Note a leap year is one that is a multiple of 4
+ * but not of a 100.  Except if it is a multiple of
+ * 400 then it is a leap year.
+ */
+/* According to postgeSQL date parsing functions there is
+ * a leap year when this expression is true.
+ * (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
+ * So according to this there is 365.2515 days in one year.
+ * One + every four years: 1/4 -> 365.25
+ * One - every 100 years: 1/100 -> 365.001
+ * One + every 400 years: 1/400 -> 365.0025
+ */
+static const double DAYS_IN_ONE_YEAR = 365.2515;
+
+
+
+/******************************************************************************
+ *	   DateTimeStringToTm	[INTERNAL]
+ *
+ * Converts a string representation of a date and/or time to a tm structure.
+ *
+ * Note this function uses the postgresql date parsing functions found
+ * in the parsedt.c file.
+ *
+ * Returns TRUE if successfull.
+ *
+ * Note: This function does not parse the day of the week,
+ * daylight savings time. It will only fill the followin fields in
+ * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
+ *
+ ******************************************************************************/
+static BOOL DateTimeStringToTm( OLECHAR* strIn, LCID lcid, struct tm* pTm )
+{
+	BOOL res = FALSE;
+	double		fsec;
+	int 		tzp;
+	int 		dtype;
+	int 		nf;
+	char	   *field[MAXDATEFIELDS];
+	int 		ftype[MAXDATEFIELDS];
+	char		lowstr[MAXDATELEN + 1];
+	char* strDateTime = NULL;
+
+	/* Convert the string to ASCII since this is the only format
+	 * postgesql can handle.
+	 */
+	strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+
+	if( strDateTime != NULL )
+	{
+		/* Make sure we don't go over the maximum length
+		 * accepted by postgesql.
+		 */
+		if( strlen( strDateTime ) <= MAXDATELEN )
+		{
+			if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
+			{
+				if( lcid & VAR_DATEVALUEONLY )
+				{
+					/* Get the date information.
+					 * It returns 0 if date information was
+					 * present and 1 if only time information was present.
+					 * -1 if an error occures.
+					 */
+					if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
+					{
+						/* Eliminate the time information since we
+						 * were asked to get date information only.
+						 */
+						pTm->tm_sec = 0;
+						pTm->tm_min = 0;
+						pTm->tm_hour = 0;
+						res = TRUE;
+					}
+				}
+				if( lcid & VAR_TIMEVALUEONLY )
+				{
+					/* Get time information only.
+					 */
+					if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
+					{
+						res = TRUE;
+					}
+				}
+				else
+				{
+					/* Get both date and time information.
+					 * It returns 0 if date information was
+					 * present and 1 if only time information was present.
+					 * -1 if an error occures.
+					 */
+					if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
+					{
+						res = TRUE;
+					}
+				}
+			}
+		}
+		HeapFree( GetProcessHeap(), 0, strDateTime );
+	}
+
+	return res;
+}
+
+
+
+
+
+
+/******************************************************************************
+ *	   TmToDATE 	[INTERNAL]
+ *
+ * The date is implemented using an 8 byte floating-point number.
+ * Days are represented by whole numbers increments starting with 0.00 has
+ * being December 30 1899, midnight.
+ * The hours are expressed as the fractional part of the number.
+ * December 30 1899 at midnight = 0.00
+ * January 1 1900 at midnight = 2.00
+ * January 4 1900 at 6 AM = 5.25
+ * January 4 1900 at noon = 5.50
+ * December 29 1899 at midnight = -1.00
+ * December 18 1899 at midnight = -12.00
+ * December 18 1899 at 6AM = -12.25
+ * December 18 1899 at 6PM = -12.75
+ * December 19 1899 at midnight = -11.00
+ * The tm structure is as follows:
+ * struct tm {
+ *		  int tm_sec;	   seconds after the minute - [0,59]
+ *		  int tm_min;	   minutes after the hour - [0,59]
+ *		  int tm_hour;	   hours since midnight - [0,23]
+ *		  int tm_mday;	   day of the month - [1,31]
+ *		  int tm_mon;	   months since January - [0,11]
+ *		  int tm_year;	   years
+ *		  int tm_wday;	   days since Sunday - [0,6]
+ *		  int tm_yday;	   days since January 1 - [0,365]
+ *		  int tm_isdst;    daylight savings time flag
+ *		  };
+ *
+ * Note: This function does not use the tm_wday, tm_yday, tm_wday,
+ * and tm_isdst fields of the tm structure. And only converts years
+ * after 1900.
+ *
+ * Returns TRUE if successfull.
+ */
+static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
+{
+	if( (pTm->tm_year - 1900) >= 0 )
+	{
+		int leapYear = 0;
+		
+		/* Start at 1. This is the way DATE is defined.
+		 * January 1, 1900 at Midnight is 1.00.
+		 * January 1, 1900 at 6AM is 1.25.
+		 * and so on.
+		 */
+		*pDateOut = 1;
+
+		/* Add the number of days corresponding to
+		 * tm_year.
+		 */
+		*pDateOut += (pTm->tm_year - 1900) * 365;
+
+		/* Add the leap days in the previous years between now and 1900.
+		 * Note a leap year is one that is a multiple of 4
+		 * but not of a 100.  Except if it is a multiple of
+		 * 400 then it is a leap year.
+		 */
+		*pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
+		*pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
+		*pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
+
+		/* Set the leap year flag if the
+		 * current year specified by tm_year is a
+		 * leap year. This will be used to add a day
+		 * to the day count.
+		 */
+		if( isleap( pTm->tm_year ) )
+			leapYear = 1;
+		
+		/* Add the number of days corresponding to
+		 * the month.
+		 */
+		switch( pTm->tm_mon )
+		{
+		case 2:
+			*pDateOut += 31;
+			break;
+		case 3:
+			*pDateOut += ( 59 + leapYear );
+			break;
+		case 4:
+			*pDateOut += ( 90 + leapYear );
+			break;
+		case 5:
+			*pDateOut += ( 120 + leapYear );
+			break;
+		case 6:
+			*pDateOut += ( 151 + leapYear );
+			break;
+		case 7:
+			*pDateOut += ( 181 + leapYear );
+			break;
+		case 8:
+			*pDateOut += ( 212 + leapYear );
+			break;
+		case 9:
+			*pDateOut += ( 243 + leapYear );
+			break;
+		case 10:
+			*pDateOut += ( 273 + leapYear );
+			break;
+		case 11:
+			*pDateOut += ( 304 + leapYear );
+			break;
+		case 12:
+			*pDateOut += ( 334 + leapYear );
+			break;
+		}
+		/* Add the number of days in this month.
+		 */
+		*pDateOut += pTm->tm_mday;
+	
+		/* Add the number of seconds, minutes, and hours
+		 * to the DATE. Note these are the fracionnal part
+		 * of the DATE so seconds / number of seconds in a day.
+		 */
+		*pDateOut += pTm->tm_hour / 24.0;
+		*pDateOut += pTm->tm_min / 1440.0;
+		*pDateOut += pTm->tm_sec / 86400.0;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/******************************************************************************
+ *	   DateToTm 	[INTERNAL]
+ *
+ * This function converst a windows DATE to a tm structure.
+ *
+ * It does not fill all the fields of the tm structure.
+ * Here is a list of the fields that are filled:
+ * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
+ *
+ * Note this function does not support dates before the January 1, 1900
+ * or ( dateIn < 2.0 ).
+ *
+ * Returns TRUE if successfull.
+ */
+static BOOL DateToTm( DATE dateIn, LCID lcid, struct tm* pTm )
+{
+	/* Do not process dates smaller than January 1, 1900.
+	 * Which corresponds to 2.0 in the windows DATE format.
+	 */
+	if( dateIn >= 2.0 )
+	{
+		double decimalPart = 0.0;
+		double wholePart = 0.0;
+
+		memset(pTm,0,sizeof(*pTm));
+	
+		/* Because of the nature of DATE format witch
+		 * associates 2.0 to January 1, 1900. We will
+		 * remove 1.0 from the whole part of the DATE
+		 * so that in the following code 1.0
+		 * will correspond to January 1, 1900.
+		 * This simplyfies the processing of the DATE value.
+		 */
+		dateIn -= 1.0;
+
+		wholePart = (double) floor( dateIn );
+		decimalPart = fmod( dateIn, wholePart );
+
+		if( !(lcid & VAR_TIMEVALUEONLY) )
+		{
+			int nDay = 0;
+			int leapYear = 0;
+			double yearsSince1900 = 0;
+			/* Start at 1900, this where the DATE time 0.0 starts.
+			 */
+			pTm->tm_year = 1900;
+			/* find in what year the day in the "wholePart" falls into.
+			 * add the value to the year field.
+			 */
+			yearsSince1900 = floor( wholePart / DAYS_IN_ONE_YEAR );
+			pTm->tm_year += yearsSince1900;
+			/* determine if this is a leap year.
+			 */
+			if( isleap( pTm->tm_year ) )
+				leapYear = 1;
+			/* find what day of that year does the "wholePart" corresponds to.
+			 * Note: nDay is in [1-366] format
+			 */
+			nDay = (int) ( wholePart - floor( yearsSince1900 * DAYS_IN_ONE_YEAR ) );
+			/* Set the tm_yday value.
+			 * Note: The day is must be converted from [1-366] to [0-365]
+			 */
+			/*pTm->tm_yday = nDay - 1;*/
+			/* find which mount this day corresponds to.
+			 */
+			if( nDay <= 31 )
+			{
+				pTm->tm_mday = nDay;
+				pTm->tm_mon = 0;
+			}
+			else if( nDay <= ( 59 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - 31;
+				pTm->tm_mon = 1;
+			}
+			else if( nDay <= ( 90 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 59 + leapYear );
+				pTm->tm_mon = 2;
+			}
+			else if( nDay <= ( 120 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 90 + leapYear );
+				pTm->tm_mon = 3;
+			}
+			else if( nDay <= ( 151 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 120 + leapYear );
+				pTm->tm_mon = 4;
+			}
+			else if( nDay <= ( 181 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 151 + leapYear );
+				pTm->tm_mon = 5;
+			}
+			else if( nDay <= ( 212 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 181 + leapYear );
+				pTm->tm_mon = 6;
+			}
+			else if( nDay <= ( 243 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 212 + leapYear );
+				pTm->tm_mon = 7;
+			}
+			else if( nDay <= ( 273 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 243 + leapYear );
+				pTm->tm_mon = 8;
+			}
+			else if( nDay <= ( 304 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 273 + leapYear );
+				pTm->tm_mon = 9;
+			}
+			else if( nDay <= ( 334 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 304 + leapYear );
+				pTm->tm_mon = 10;
+			}
+			else if( nDay <= ( 365 + leapYear ) )
+			{
+				pTm->tm_mday = nDay - ( 334 + leapYear );
+				pTm->tm_mon = 11;
+			}
+		}
+		if( !(lcid & VAR_DATEVALUEONLY) )
+		{
+			/* find the number of seconds in this day.
+			 * fractional part times, hours, minutes, seconds.
+			 */
+			pTm->tm_hour = (int) ( decimalPart * 24 );
+			pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
+			pTm->tm_sec = (int) ( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 );
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
+
+
+/******************************************************************************
+ *	   SizeOfVariantData   	[INTERNAL]
+ *
+ * This function finds the size of the data referenced by a Variant based
+ * the type "vt" of the Variant.
+ */
+static int SizeOfVariantData( VARIANT* parg )
+{
+    int size = 0;
+    switch( parg->vt & VT_TYPEMASK )
+    {
+    case( VT_I2 ):
+        size = sizeof(short);
+        break;
+    case( VT_INT ):
+        size = sizeof(int);
+        break;
+    case( VT_I4 ):
+        size = sizeof(long);
+        break;
+    case( VT_UI1 ):
+        size = sizeof(BYTE);
+        break;
+    case( VT_UI2 ):
+        size = sizeof(unsigned short);
+        break;
+    case( VT_UINT ):
+        size = sizeof(unsigned int);
+        break;
+    case( VT_UI4 ):
+        size = sizeof(unsigned long);
+        break;
+    case( VT_R4 ):
+        size = sizeof(float);
+        break;
+    case( VT_R8 ):
+        size = sizeof(double);
+        break;
+    case( VT_DATE ):
+        size = sizeof(DATE);
+        break;
+    case( VT_BOOL ):
+        size = sizeof(VARIANT_BOOL);
+        break;
+    case( VT_BSTR ):
+        size = sizeof(void*);
+        break;
+    case( VT_CY ):
+    case( VT_DISPATCH ):
+    case( VT_UNKNOWN ):
+    case( VT_DECIMAL ):
+    default:
+        FIXME("Add size information for type vt=%d\n", parg->vt & VT_TYPEMASK );
+        break;
+    }
+
+    return size;
+}
+/******************************************************************************
+ *	   StringDupAtoBstr		[INTERNAL]
+ * 
+ */
+static BSTR StringDupAtoBstr( char* strIn )
+{
+	BSTR bstr = NULL;
+	OLECHAR* pNewString = NULL;
+	pNewString = HEAP_strdupAtoW( GetProcessHeap(), 0, strIn );
+	bstr = SysAllocString( pNewString );
+	HeapFree( GetProcessHeap(), 0, pNewString );
+	return bstr;
+}
+
+/******************************************************************************
+ *		round		[INTERNAL]
+ *
+ * Round the double value to the nearest integer value.
+ */
+static double round( double d )
+{
+   double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
+    BOOL bEvenNumber = FALSE;
+    int nSign = 0;
+
+    /* Save the sign of the number
+     */
+   nSign = (d >= 0.0) ? 1 : -1;
+    d = fabs( d );
+    
+	/* Remove the decimals.
+	 */
+   integerValue = floor( d );
+
+    /* Set the Even flag.  This is used to round the number when
+     * the decimals are exactly 1/2.  If the integer part is
+     * odd the number is rounded up. If the integer part
+     * is even the number is rounded down.  Using this method
+     * numbers are rounded up|down half the time.
+     */
+   bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
+
+    /* Remove the integral part of the number.
+     */
+    decimals = d - integerValue;
+
+	/* Note: Ceil returns the smallest integer that is greater that x.
+	 * and floor returns the largest integer that is less than or equal to x.
+	 */
+    if( decimals > 0.5 )
+    {
+        /* If the decimal part is greater than 1/2
+         */
+        roundedValue = ceil( d );
+    }
+    else if( decimals < 0.5 )
+    {
+        /* If the decimal part is smaller than 1/2
+         */
+        roundedValue = floor( d );
+    }
+    else
+    {
+        /* the decimals are exactly 1/2 so round according to
+         * the bEvenNumber flag.
+         */
+        if( bEvenNumber )
+        {
+            roundedValue = floor( d );
+        }
+        else
+        {
+            roundedValue = ceil( d );
+        }
+    }
+
+	return roundedValue * nSign;
+}
+
+/******************************************************************************
+ *		RemoveCharacterFromString		[INTERNAL]
+ *
+ * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
+ */
+static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
+{
+	LPSTR pNewString = NULL;
+	LPSTR strToken = NULL;
+
+
+	/* Check if we have a valid argument
+	 */
+	if( str != NULL )
+	{
+		pNewString = strdup( str );
+		str[0] = '\0';
+		strToken = strtok( pNewString, strOfCharToRemove );
+		while( strToken != NULL ) { 
+			strcat( str, strToken );
+			strToken = strtok( NULL, strOfCharToRemove );
+		}
+		free( pNewString );
+	}
+	return;
+}
+
+/******************************************************************************
+ *		GetValidRealString		[INTERNAL]
+ *
+ * Checks if the string is of proper format to be converted to a real value.
+ */
+static BOOL IsValidRealString( LPSTR strRealString )
+{
+	/* Real values that have a decimal point are required to either have
+	 * digits before or after the decimal point.  We will assume that
+	 * we do not have any digits at either position. If we do encounter
+	 * some we will disable this flag.
+	 */
+	BOOL bDigitsRequired = TRUE;
+	/* Processed fields in the string representation of the real number.
+	 */
+	BOOL bWhiteSpaceProcessed = FALSE;
+	BOOL bFirstSignProcessed = FALSE;
+	BOOL bFirstDigitsProcessed = FALSE;
+	BOOL bDecimalPointProcessed = FALSE;
+	BOOL bSecondDigitsProcessed = FALSE;
+	BOOL bExponentProcessed = FALSE;
+	BOOL bSecondSignProcessed = FALSE;
+	BOOL bThirdDigitsProcessed = FALSE;
+	/* Assume string parameter "strRealString" is valid and try to disprove it.
+	 */
+	BOOL bValidRealString = TRUE;
+
+	/* Used to count the number of tokens in the "strRealString".
+	 */
+	LPSTR strToken = NULL;
+	int nTokens = 0;
+	LPSTR pChar = NULL;
+	
+	/* Check if we have a valid argument
+	 */
+	if( strRealString == NULL )
+	{
+		bValidRealString = FALSE;
+	}
+
+	if( bValidRealString == TRUE )
+	{
+		/* Make sure we only have ONE token in the string.
+		 */
+		strToken = strtok( strRealString, " " );
+		while( strToken != NULL ) { 
+			nTokens++;		
+			strToken = strtok( NULL, " " );	
+		}
+
+		if( nTokens != 1 )
+		{
+			bValidRealString = FALSE;
+		}
+	}
+
+
+	/* Make sure this token contains only valid characters.
+	 * The string argument to atof has the following form:
+	 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
+	 * Whitespace consists of space and|or <TAB> characters, which are ignored.
+     * Sign is either plus '+' or minus '-'.
+     * Digits are one or more decimal digits.
+     * Note: If no digits appear before the decimal point, at least one must
+     * appear after the decimal point.
+     * The decimal digits may be followed by an exponent.
+     * An Exponent consists of an introductory letter ( D, d, E, or e) and
+	 * an optionally signed decimal integer.
+	 */
+	pChar = strRealString;
+	while( bValidRealString == TRUE && *pChar != '\0' )
+	{
+		switch( *pChar )
+		{
+		/* If whitespace...
+		 */
+		case ' ':
+		case '\t':
+			if( bWhiteSpaceProcessed ||
+				bFirstSignProcessed ||
+				bFirstDigitsProcessed ||
+				bDecimalPointProcessed ||
+				bSecondDigitsProcessed ||
+				bExponentProcessed ||
+				bSecondSignProcessed ||
+				bThirdDigitsProcessed )
+			{
+				bValidRealString = FALSE;
+			}
+			break;
+		/* If sign...
+		 */
+		case '+':
+		case '-':
+			if( bFirstSignProcessed == FALSE )
+			{
+				if( bFirstDigitsProcessed ||
+					bDecimalPointProcessed ||
+					bSecondDigitsProcessed ||
+					bExponentProcessed ||
+					bSecondSignProcessed ||
+					bThirdDigitsProcessed )
+				{
+					bValidRealString = FALSE;
+				}
+				bWhiteSpaceProcessed = TRUE;
+				bFirstSignProcessed = TRUE;
+			}
+			else if( bSecondSignProcessed == FALSE )
+			{
+                /* Note: The exponent must be present in
+				 * order to accept the second sign...
+				 */
+				if( bExponentProcessed == FALSE ||
+					bThirdDigitsProcessed ||
+					bDigitsRequired )
+				{
+					bValidRealString = FALSE;
+				}
+				bFirstSignProcessed = TRUE;
+				bWhiteSpaceProcessed = TRUE;
+				bFirstDigitsProcessed = TRUE;
+				bDecimalPointProcessed = TRUE;
+				bSecondDigitsProcessed = TRUE;
+				bSecondSignProcessed = TRUE;
+			}
+			break;
+
+		/* If decimals...
+		 */
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9': 
+			if( bFirstDigitsProcessed == FALSE )
+			{
+				if( bDecimalPointProcessed ||
+					bSecondDigitsProcessed ||
+					bExponentProcessed ||
+					bSecondSignProcessed ||
+					bThirdDigitsProcessed )
+				{
+					bValidRealString = FALSE;
+				}
+				bFirstSignProcessed = TRUE;
+				bWhiteSpaceProcessed = TRUE;
+				/* We have found some digits before the decimal point
+				 * so disable the "Digits required" flag.
+				 */
+				bDigitsRequired = FALSE;
+			}
+			else if( bSecondDigitsProcessed == FALSE )
+			{
+				if( bExponentProcessed ||
+					bSecondSignProcessed ||
+					bThirdDigitsProcessed )
+				{
+					bValidRealString = FALSE;
+				}
+				bFirstSignProcessed = TRUE;
+				bWhiteSpaceProcessed = TRUE;
+				bFirstDigitsProcessed = TRUE;
+				bDecimalPointProcessed = TRUE;
+				/* We have found some digits after the decimal point
+				 * so disable the "Digits required" flag.
+				 */
+				bDigitsRequired = FALSE;
+			}
+			else if( bThirdDigitsProcessed == FALSE )
+			{
+				/* Getting here means everything else should be processed.
+                 * If we get anything else than a decimal following this
+                 * digit it will be flagged by the other cases, so
+				 * we do not really need to do anything in here.
+				 */
+			}
+			break;
+		/* If DecimalPoint...
+		 */
+		case '.': 
+			if( bDecimalPointProcessed ||
+				bSecondDigitsProcessed ||
+				bExponentProcessed ||
+				bSecondSignProcessed ||
+				bThirdDigitsProcessed )
+			{
+				bValidRealString = FALSE;
+			}
+			bFirstSignProcessed = TRUE;
+			bWhiteSpaceProcessed = TRUE;
+			bFirstDigitsProcessed = TRUE;
+			bDecimalPointProcessed = TRUE;
+			break;
+		/* If Exponent...
+		 */
+		case 'e':
+		case 'E':
+		case 'd':
+		case 'D':
+			if( bExponentProcessed ||
+				bSecondSignProcessed ||
+				bThirdDigitsProcessed ||
+				bDigitsRequired )
+			{
+				bValidRealString = FALSE;
+			}
+			bFirstSignProcessed = TRUE;
+			bWhiteSpaceProcessed = TRUE;
+			bFirstDigitsProcessed = TRUE;
+			bDecimalPointProcessed = TRUE;
+			bSecondDigitsProcessed = TRUE;
+			bExponentProcessed = TRUE;
+			break;
+		default:
+			bValidRealString = FALSE;
+			break;
+		}
+		/* Process next character.
+		 */
+		pChar++;
+	}
+
+	/* If the required digits were not present we have an invalid
+	 * string representation of a real number.
+	 */
+	if( bDigitsRequired == TRUE )
+	{
+		bValidRealString = FALSE;
+	}
+
+	return bValidRealString;
+}
+
+
+/******************************************************************************
+ *		Coerce	[INTERNAL]
+ *
+ * This function dispatches execution to the proper conversion API
+ * to do the necessary coercion.
+ */
+static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
+{
+	HRESULT res = S_OK;
+	unsigned short vtFrom = 0;
+	vtFrom = ps->vt & VT_TYPEMASK;
+	
+    /* Note: Since "long" and "int" values both have 4 bytes and are both signed integers
+     * "int" will be treated as "long" in the following code.
+     * The same goes for there unsigned versions.
+	 */
+
+	switch( vt )
+	{
+
+    case( VT_EMPTY ):
+        res = VariantClear( pd );
+        break;
+    case( VT_NULL ):
+        res = VariantClear( pd );
+        if( res == S_OK )
+        {
+            pd->vt = VT_NULL;
+        }
+        break;
+	case( VT_I1 ):
+		switch( vtFrom )
+        {
+        case( VT_I1 ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_I2 ):
+			res = VarI1FromI2( ps->u.iVal, &(pd->u.cVal) );
+			break;
+		case( VT_INT ):
+		case( VT_I4 ):
+			res = VarI1FromI4( ps->u.lVal, &(pd->u.cVal) );
+			break;
+		case( VT_UI1 ):
+			res = VarI1FromUI1( ps->u.bVal, &(pd->u.cVal) );
+			break;
+		case( VT_UI2 ):
+			res = VarI1FromUI2( ps->u.uiVal, &(pd->u.cVal) );
+			break;
+		case( VT_UINT ):
+		case( VT_UI4 ):
+			res = VarI1FromUI4( ps->u.ulVal, &(pd->u.cVal) );
+			break;
+		case( VT_R4 ):
+			res = VarI1FromR4( ps->u.fltVal, &(pd->u.cVal) );
+			break;
+		case( VT_R8 ):
+			res = VarI1FromR8( ps->u.dblVal, &(pd->u.cVal) );
+			break;
+		case( VT_DATE ):
+			res = VarI1FromDate( ps->u.date, &(pd->u.cVal) );
+			break;
+		case( VT_BOOL ):
+			res = VarI1FromBool( ps->u.boolVal, &(pd->u.cVal) );
+			break;
+		case( VT_BSTR ):
+			res = VarI1FromStr( ps->u.bstrVal, lcid, dwFlags, &(pd->u.cVal) );
+			break;
+		case( VT_CY ):
+	     res = VarI1FromCy( ps->u.cyVal, &(pd->u.cVal) );
+		case( VT_DISPATCH ):
+			/*res = VarI1FromDisp32( ps->u.pdispVal, lcid, &(pd->u.cVal) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarI1From32( ps->u.lVal, &(pd->u.cVal) );*/
+		case( VT_DECIMAL ):
+			/*res = VarI1FromDec32( ps->u.decVal, &(pd->u.cVal) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+
+	case( VT_I2 ):
+		switch( vtFrom )
+		{
+		case( VT_I1 ):
+			res = VarI2FromI1( ps->u.cVal, &(pd->u.iVal) );
+			break;
+        case( VT_I2 ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_INT ):
+		case( VT_I4 ):
+			res = VarI2FromI4( ps->u.lVal, &(pd->u.iVal) );
+			break;
+		case( VT_UI1 ):
+			res = VarI2FromUI1( ps->u.bVal, &(pd->u.iVal) );
+			break;
+		case( VT_UI2 ):
+			res = VarI2FromUI2( ps->u.uiVal, &(pd->u.iVal) );
+			break;
+		case( VT_UINT ):
+		case( VT_UI4 ):
+			res = VarI2FromUI4( ps->u.ulVal, &(pd->u.iVal) );
+			break;
+		case( VT_R4 ):
+			res = VarI2FromR4( ps->u.fltVal, &(pd->u.iVal) );
+			break;
+		case( VT_R8 ):
+			res = VarI2FromR8( ps->u.dblVal, &(pd->u.iVal) );
+			break;
+		case( VT_DATE ):
+			res = VarI2FromDate( ps->u.date, &(pd->u.iVal) );
+			break;
+		case( VT_BOOL ):
+			res = VarI2FromBool( ps->u.boolVal, &(pd->u.iVal) );
+			break;
+		case( VT_BSTR ):
+			res = VarI2FromStr( ps->u.bstrVal, lcid, dwFlags, &(pd->u.iVal) );
+			break;
+		case( VT_CY ):
+	     res = VarI2FromCy( ps->u.cyVal, &(pd->u.iVal) );
+		case( VT_DISPATCH ):
+			/*res = VarI2FromDisp32( ps->u.pdispVal, lcid, &(pd->u.iVal) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarI2From32( ps->u.lVal, &(pd->u.iVal) );*/
+		case( VT_DECIMAL ):
+			/*res = VarI2FromDec32( ps->u.deiVal, &(pd->u.iVal) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+
+	case( VT_INT ):
+	case( VT_I4 ):
+		switch( vtFrom )
+		{
+		case( VT_I1 ):
+			res = VarI4FromI1( ps->u.cVal, &(pd->u.lVal) );
+			break;
+		case( VT_I2 ):
+			res = VarI4FromI2( ps->u.iVal, &(pd->u.lVal) );
+            break;
+        case( VT_INT ):
+        case( VT_I4 ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_UI1 ):
+			res = VarI4FromUI1( ps->u.bVal, &(pd->u.lVal) );
+			break;
+		case( VT_UI2 ):
+			res = VarI4FromUI2( ps->u.uiVal, &(pd->u.lVal) );
+			break;
+		case( VT_UINT ):
+		case( VT_UI4 ):
+			res = VarI4FromUI4( ps->u.ulVal, &(pd->u.lVal) );
+			break;
+		case( VT_R4 ):
+			res = VarI4FromR4( ps->u.fltVal, &(pd->u.lVal) );
+			break;
+		case( VT_R8 ):
+			res = VarI4FromR8( ps->u.dblVal, &(pd->u.lVal) );
+			break;
+		case( VT_DATE ):
+			res = VarI4FromDate( ps->u.date, &(pd->u.lVal) );
+			break;
+		case( VT_BOOL ):
+			res = VarI4FromBool( ps->u.boolVal, &(pd->u.lVal) );
+			break;
+		case( VT_BSTR ):
+			res = VarI4FromStr( ps->u.bstrVal, lcid, dwFlags, &(pd->u.lVal) );
+			break;
+		case( VT_CY ):
+	     res = VarI4FromCy( ps->u.cyVal, &(pd->u.lVal) );
+		case( VT_DISPATCH ):
+			/*res = VarI4FromDisp32( ps->u.pdispVal, lcid, &(pd->u.lVal) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarI4From32( ps->u.lVal, &(pd->u.lVal) );*/
+		case( VT_DECIMAL ):
+			/*res = VarI4FromDec32( ps->u.deiVal, &(pd->u.lVal) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+
+	case( VT_UI1 ):
+		switch( vtFrom )
+		{
+		case( VT_I1 ):
+			res = VarUI1FromI1( ps->u.cVal, &(pd->u.bVal) );
+			break;
+		case( VT_I2 ):
+			res = VarUI1FromI2( ps->u.iVal, &(pd->u.bVal) );
+			break;
+		case( VT_INT ):
+		case( VT_I4 ):
+			res = VarUI1FromI4( ps->u.lVal, &(pd->u.bVal) );
+			break;
+        case( VT_UI1 ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_UI2 ):
+			res = VarUI1FromUI2( ps->u.uiVal, &(pd->u.bVal) );
+			break;
+		case( VT_UINT ):
+		case( VT_UI4 ):
+			res = VarUI1FromUI4( ps->u.ulVal, &(pd->u.bVal) );
+			break;
+		case( VT_R4 ):
+			res = VarUI1FromR4( ps->u.fltVal, &(pd->u.bVal) );
+			break;
+		case( VT_R8 ):
+			res = VarUI1FromR8( ps->u.dblVal, &(pd->u.bVal) );
+			break;
+		case( VT_DATE ):
+			res = VarUI1FromDate( ps->u.date, &(pd->u.bVal) );
+			break;
+		case( VT_BOOL ):
+			res = VarUI1FromBool( ps->u.boolVal, &(pd->u.bVal) );
+			break;
+		case( VT_BSTR ):
+			res = VarUI1FromStr( ps->u.bstrVal, lcid, dwFlags, &(pd->u.bVal) );
+			break;
+		case( VT_CY ):
+	     res = VarUI1FromCy( ps->u.cyVal, &(pd->u.bVal) );
+		case( VT_DISPATCH ):
+			/*res = VarUI1FromDisp32( ps->u.pdispVal, lcid, &(pd->u.bVal) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarUI1From32( ps->u.lVal, &(pd->u.bVal) );*/
+		case( VT_DECIMAL ):
+			/*res = VarUI1FromDec32( ps->u.deiVal, &(pd->u.bVal) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+
+	case( VT_UI2 ):
+		switch( vtFrom )
+		{
+		case( VT_I1 ):
+			res = VarUI2FromI1( ps->u.cVal, &(pd->u.uiVal) );
+			break;
+		case( VT_I2 ):
+			res = VarUI2FromI2( ps->u.iVal, &(pd->u.uiVal) );
+			break;
+		case( VT_INT ):
+		case( VT_I4 ):
+			res = VarUI2FromI4( ps->u.lVal, &(pd->u.uiVal) );
+			break;
+		case( VT_UI1 ):
+			res = VarUI2FromUI1( ps->u.bVal, &(pd->u.uiVal) );
+			break;
+        case( VT_UI2 ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_UINT ):
+		case( VT_UI4 ):
+			res = VarUI2FromUI4( ps->u.ulVal, &(pd->u.uiVal) );
+			break;
+		case( VT_R4 ):
+			res = VarUI2FromR4( ps->u.fltVal, &(pd->u.uiVal) );
+			break;
+		case( VT_R8 ):
+			res = VarUI2FromR8( ps->u.dblVal, &(pd->u.uiVal) );
+			break;
+		case( VT_DATE ):
+			res = VarUI2FromDate( ps->u.date, &(pd->u.uiVal) );
+			break;
+		case( VT_BOOL ):
+			res = VarUI2FromBool( ps->u.boolVal, &(pd->u.uiVal) );
+			break;
+		case( VT_BSTR ):
+			res = VarUI2FromStr( ps->u.bstrVal, lcid, dwFlags, &(pd->u.uiVal) );
+			break;
+		case( VT_CY ):
+	     res = VarUI2FromCy( ps->u.cyVal, &(pd->u.uiVal) );
+		case( VT_DISPATCH ):
+			/*res = VarUI2FromDisp32( ps->u.pdispVal, lcid, &(pd->u.uiVal) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarUI2From32( ps->u.lVal, &(pd->u.uiVal) );*/
+		case( VT_DECIMAL ):
+			/*res = VarUI2FromDec32( ps->u.deiVal, &(pd->u.uiVal) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+
+	case( VT_UINT ):
+	case( VT_UI4 ):
+		switch( vtFrom )
+		{
+		case( VT_I1 ):
+			res = VarUI4FromI1( ps->u.cVal, &(pd->u.ulVal) );
+			break;
+		case( VT_I2 ):
+			res = VarUI4FromI2( ps->u.iVal, &(pd->u.ulVal) );
+			break;
+		case( VT_INT ):
+		case( VT_I4 ):
+			res = VarUI4FromI4( ps->u.lVal, &(pd->u.ulVal) );
+			break;
+		case( VT_UI1 ):
+			res = VarUI4FromUI1( ps->u.bVal, &(pd->u.ulVal) );
+			break;
+		case( VT_UI2 ):
+			res = VarUI4FromUI2( ps->u.uiVal, &(pd->u.ulVal) );
+			break;
+        case( VT_UI4 ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_R4 ):
+			res = VarUI4FromR4( ps->u.fltVal, &(pd->u.ulVal) );
+			break;
+		case( VT_R8 ):
+			res = VarUI4FromR8( ps->u.dblVal, &(pd->u.ulVal) );
+			break;
+		case( VT_DATE ):
+			res = VarUI4FromDate( ps->u.date, &(pd->u.ulVal) );
+			break;
+		case( VT_BOOL ):
+			res = VarUI4FromBool( ps->u.boolVal, &(pd->u.ulVal) );
+			break;
+		case( VT_BSTR ):
+			res = VarUI4FromStr( ps->u.bstrVal, lcid, dwFlags, &(pd->u.ulVal) );
+			break;
+		case( VT_CY ):
+	     res = VarUI4FromCy( ps->u.cyVal, &(pd->u.ulVal) );
+		case( VT_DISPATCH ):
+			/*res = VarUI4FromDisp32( ps->u.pdispVal, lcid, &(pd->u.ulVal) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarUI4From32( ps->u.lVal, &(pd->u.ulVal) );*/
+		case( VT_DECIMAL ):
+			/*res = VarUI4FromDec32( ps->u.deiVal, &(pd->u.ulVal) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+		
+	case( VT_R4 ):
+		switch( vtFrom )
+		{
+		case( VT_I1 ):
+			res = VarR4FromI1( ps->u.cVal, &(pd->u.fltVal) );
+			break;
+		case( VT_I2 ):
+			res = VarR4FromI2( ps->u.iVal, &(pd->u.fltVal) );
+			break;
+		case( VT_INT ):
+		case( VT_I4 ):
+			res = VarR4FromI4( ps->u.lVal, &(pd->u.fltVal) );
+			break;
+		case( VT_UI1 ):
+			res = VarR4FromUI1( ps->u.bVal, &(pd->u.fltVal) );
+			break;
+		case( VT_UI2 ):
+			res = VarR4FromUI2( ps->u.uiVal, &(pd->u.fltVal) );
+			break;
+		case( VT_UINT ):
+		case( VT_UI4 ):
+			res = VarR4FromUI4( ps->u.ulVal, &(pd->u.fltVal) );
+			break;
+        case( VT_R4 ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_R8 ):
+			res = VarR4FromR8( ps->u.dblVal, &(pd->u.fltVal) );
+			break;
+		case( VT_DATE ):
+			res = VarR4FromDate( ps->u.date, &(pd->u.fltVal) );
+			break;
+		case( VT_BOOL ):
+			res = VarR4FromBool( ps->u.boolVal, &(pd->u.fltVal) );
+			break;
+		case( VT_BSTR ):
+			res = VarR4FromStr( ps->u.bstrVal, lcid, dwFlags, &(pd->u.fltVal) );
+			break;
+		case( VT_CY ):
+	     res = VarR4FromCy( ps->u.cyVal, &(pd->u.fltVal) );
+		case( VT_DISPATCH ):
+			/*res = VarR4FromDisp32( ps->u.pdispVal, lcid, &(pd->u.fltVal) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarR4From32( ps->u.lVal, &(pd->u.fltVal) );*/
+		case( VT_DECIMAL ):
+			/*res = VarR4FromDec32( ps->u.deiVal, &(pd->u.fltVal) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+
+	case( VT_R8 ):
+		switch( vtFrom )
+		{
+		case( VT_I1 ):
+			res = VarR8FromI1( ps->u.cVal, &(pd->u.dblVal) );
+			break;
+		case( VT_I2 ):
+			res = VarR8FromI2( ps->u.iVal, &(pd->u.dblVal) );
+			break;
+		case( VT_INT ):
+		case( VT_I4 ):
+			res = VarR8FromI4( ps->u.lVal, &(pd->u.dblVal) );
+			break;
+		case( VT_UI1 ):
+			res = VarR8FromUI1( ps->u.bVal, &(pd->u.dblVal) );
+			break;
+		case( VT_UI2 ):
+			res = VarR8FromUI2( ps->u.uiVal, &(pd->u.dblVal) );
+			break;
+		case( VT_UINT ):
+		case( VT_UI4 ):
+			res = VarR8FromUI4( ps->u.ulVal, &(pd->u.dblVal) );
+			break;
+		case( VT_R4 ):
+			res = VarR8FromR4( ps->u.fltVal, &(pd->u.dblVal) );
+			break;
+        case( VT_R8 ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_DATE ):
+			res = VarR8FromDate( ps->u.date, &(pd->u.dblVal) );
+			break;
+		case( VT_BOOL ):
+			res = VarR8FromBool( ps->u.boolVal, &(pd->u.dblVal) );
+			break;
+		case( VT_BSTR ):
+			res = VarR8FromStr( ps->u.bstrVal, lcid, dwFlags, &(pd->u.dblVal) );
+			break;
+		case( VT_CY ):
+	     res = VarR8FromCy( ps->u.cyVal, &(pd->u.dblVal) );
+		case( VT_DISPATCH ):
+			/*res = VarR8FromDisp32( ps->u.pdispVal, lcid, &(pd->u.dblVal) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarR8From32( ps->u.lVal, &(pd->u.dblVal) );*/
+		case( VT_DECIMAL ):
+			/*res = VarR8FromDec32( ps->u.deiVal, &(pd->u.dblVal) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+
+	case( VT_DATE ):
+		switch( vtFrom )
+		{
+		case( VT_I1 ):
+			res = VarDateFromI1( ps->u.cVal, &(pd->u.date) );
+			break;
+		case( VT_I2 ):
+			res = VarDateFromI2( ps->u.iVal, &(pd->u.date) );
+			break;
+		case( VT_INT ):
+			res = VarDateFromInt( ps->u.intVal, &(pd->u.date) );
+			break;
+		case( VT_I4 ):
+			res = VarDateFromI4( ps->u.lVal, &(pd->u.date) );
+			break;
+		case( VT_UI1 ):
+			res = VarDateFromUI1( ps->u.bVal, &(pd->u.date) );
+			break;
+		case( VT_UI2 ):
+			res = VarDateFromUI2( ps->u.uiVal, &(pd->u.date) );
+			break;
+		case( VT_UINT ):
+			res = VarDateFromUint( ps->u.uintVal, &(pd->u.date) );
+			break;
+		case( VT_UI4 ):
+			res = VarDateFromUI4( ps->u.ulVal, &(pd->u.date) );
+			break;
+		case( VT_R4 ):
+			res = VarDateFromR4( ps->u.fltVal, &(pd->u.date) );
+			break;
+		case( VT_R8 ):
+			res = VarDateFromR8( ps->u.dblVal, &(pd->u.date) );
+			break;
+        case( VT_DATE ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_BOOL ):
+			res = VarDateFromBool( ps->u.boolVal, &(pd->u.date) );
+			break;
+		case( VT_BSTR ):
+			res = VarDateFromStr( ps->u.bstrVal, lcid, dwFlags, &(pd->u.date) );
+			break;
+		case( VT_CY ):
+	     res = VarDateFromCy( ps->u.cyVal, &(pd->u.date) );
+		case( VT_DISPATCH ):
+			/*res = VarDateFromDisp32( ps->u.pdispVal, lcid, &(pd->u.date) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarDateFrom32( ps->u.lVal, &(pd->u.date) );*/
+		case( VT_DECIMAL ):
+			/*res = VarDateFromDec32( ps->u.deiVal, &(pd->u.date) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+
+	case( VT_BOOL ):
+		switch( vtFrom )
+		{
+		case( VT_I1 ):
+			res = VarBoolFromI1( ps->u.cVal, &(pd->u.boolVal) );
+			break;
+		case( VT_I2 ):
+			res = VarBoolFromI2( ps->u.iVal, &(pd->u.boolVal) );
+			break;
+		case( VT_INT ):
+			res = VarBoolFromInt( ps->u.intVal, &(pd->u.boolVal) );
+			break;
+		case( VT_I4 ):
+			res = VarBoolFromI4( ps->u.lVal, &(pd->u.boolVal) );
+			break;
+		case( VT_UI1 ):
+			res = VarBoolFromUI1( ps->u.bVal, &(pd->u.boolVal) );
+			break;
+		case( VT_UI2 ):
+			res = VarBoolFromUI2( ps->u.uiVal, &(pd->u.boolVal) );
+			break;
+		case( VT_UINT ):
+			res = VarBoolFromUint( ps->u.uintVal, &(pd->u.boolVal) );
+			break;
+		case( VT_UI4 ):
+			res = VarBoolFromUI4( ps->u.ulVal, &(pd->u.boolVal) );
+			break;
+		case( VT_R4 ):
+			res = VarBoolFromR4( ps->u.fltVal, &(pd->u.boolVal) );
+			break;
+		case( VT_R8 ):
+			res = VarBoolFromR8( ps->u.dblVal, &(pd->u.boolVal) );
+			break;
+		case( VT_DATE ):
+			res = VarBoolFromDate( ps->u.date, &(pd->u.boolVal) );
+			break;
+        case( VT_BOOL ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_BSTR ):
+			res = VarBoolFromStr( ps->u.bstrVal, lcid, dwFlags, &(pd->u.boolVal) );
+			break;
+		case( VT_CY ):
+	     res = VarBoolFromCy( ps->u.cyVal, &(pd->u.boolVal) );
+		case( VT_DISPATCH ):
+			/*res = VarBoolFromDisp32( ps->u.pdispVal, lcid, &(pd->u.boolVal) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarBoolFrom32( ps->u.lVal, &(pd->u.boolVal) );*/
+		case( VT_DECIMAL ):
+			/*res = VarBoolFromDec32( ps->u.deiVal, &(pd->u.boolVal) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+
+	case( VT_BSTR ):
+		switch( vtFrom )
+		{
+		case( VT_I1 ):
+			res = VarBstrFromI1( ps->u.cVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_I2 ):
+			res = VarBstrFromI2( ps->u.iVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_INT ):
+			res = VarBstrFromInt( ps->u.intVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_I4 ):
+			res = VarBstrFromI4( ps->u.lVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_UI1 ):
+			res = VarBstrFromUI1( ps->u.bVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_UI2 ):
+			res = VarBstrFromUI2( ps->u.uiVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_UINT ):
+			res = VarBstrFromUint( ps->u.uintVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_UI4 ):
+			res = VarBstrFromUI4( ps->u.ulVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_R4 ):
+			res = VarBstrFromR4( ps->u.fltVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_R8 ):
+			res = VarBstrFromR8( ps->u.dblVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_DATE ):
+			res = VarBstrFromDate( ps->u.date, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+		case( VT_BOOL ):
+			res = VarBstrFromBool( ps->u.boolVal, lcid, dwFlags, &(pd->u.bstrVal) );
+			break;
+        case( VT_BSTR ):
+            res = VariantCopy( pd, ps );
+            break;
+		case( VT_CY ):
+	     /*res = VarBstrFromCy32( ps->u.cyVal, lcid, dwFlags, &(pd->u.bstrVal) );*/
+		case( VT_DISPATCH ):
+			/*res = VarBstrFromDisp32( ps->u.pdispVal, lcid, lcid, dwFlags, &(pd->u.bstrVal) );*/
+		case( VT_UNKNOWN ):
+			/*res = VarBstrFrom32( ps->u.lVal, lcid, dwFlags, &(pd->u.bstrVal) );*/
+		case( VT_DECIMAL ):
+			/*res = VarBstrFromDec32( ps->u.deiVal, lcid, dwFlags, &(pd->u.bstrVal) );*/
+		default:
+			res = DISP_E_TYPEMISMATCH;
+			FIXME("Coercion from %d to %d\n", vtFrom, vt );
+			break;
+		}
+		break;
+
+     case( VT_CY ):
+	switch( vtFrom )
+	  {
+	  case( VT_I1 ):
+	     res = VarCyFromI1( ps->u.cVal, &(pd->u.cyVal) );
+	     break;
+	  case( VT_I2 ):
+	     res = VarCyFromI2( ps->u.iVal, &(pd->u.cyVal) );
+	     break;
+	  case( VT_INT ):
+	     res = VarCyFromInt( ps->u.intVal, &(pd->u.cyVal) );
+	     break;
+	  case( VT_I4 ):
+	     res = VarCyFromI4( ps->u.lVal, &(pd->u.cyVal) );
+	     break;
+	  case( VT_UI1 ):
+	     res = VarCyFromUI1( ps->u.bVal, &(pd->u.cyVal) );
+	     break;
+	  case( VT_UI2 ):
+	     res = VarCyFromUI2( ps->u.uiVal, &(pd->u.cyVal) );
+	     break;
+	  case( VT_UINT ):
+	     res = VarCyFromUint( ps->u.uintVal, &(pd->u.cyVal) );
+	     break;
+	  case( VT_UI4 ):
+	     res = VarCyFromUI4( ps->u.ulVal, &(pd->u.cyVal) );
+	     break;
+	  case( VT_R4 ):
+	     res = VarCyFromR4( ps->u.fltVal, &(pd->u.cyVal) );
+	     break;
+	  case( VT_R8 ):
+	     res = VarCyFromR8( ps->u.dblVal, &(pd->u.cyVal) );
+	     break;
+	  case( VT_DATE ):
+	     res = VarCyFromDate( ps->u.date, &(pd->u.cyVal) );
+	     break;
+	  case( VT_BOOL ):
+	     res = VarCyFromBool( ps->u.date, &(pd->u.cyVal) );
+	     break;
+	  case( VT_CY ):
+	     res = VariantCopy( pd, ps );
+	     break;
+	  case( VT_BSTR ):
+	     /*res = VarCyFromStr32( ps->u.bstrVal, lcid, dwFlags, &(pd->u.cyVal) );*/
+	  case( VT_DISPATCH ):
+	     /*res = VarCyFromDisp32( ps->u.pdispVal, lcid, &(pd->u.boolVal) );*/
+	  case( VT_UNKNOWN ):
+	     /*res = VarCyFrom32( ps->u.lVal, &(pd->u.boolVal) );*/
+	  case( VT_DECIMAL ):
+	     /*res = VarCyFromDec32( ps->u.deiVal, &(pd->u.boolVal) );*/
+	  default:
+	     res = DISP_E_TYPEMISMATCH;
+	     FIXME("Coercion from %d to %d\n", vtFrom, vt );
+	     break;
+	  }
+	break;
+
+	default:
+		res = DISP_E_TYPEMISMATCH;
+		FIXME("Coercion from %d to %d\n", vtFrom, vt );
+		break;
+	}
+	
+	return res;
+}
+
+/******************************************************************************
+ *		ValidateVtRange	[INTERNAL]
+ *
+ * Used internally by the hi-level Variant API to determine
+ * if the vartypes are valid.
+ */
+static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
+{
+    /* if by value we must make sure it is in the
+     * range of the valid types.
+     */
+    if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
+    {
+        return DISP_E_BADVARTYPE;
+    }
+    return S_OK;
+}
+
+
+/******************************************************************************
+ *		ValidateVartype	[INTERNAL]
+ *
+ * Used internally by the hi-level Variant API to determine
+ * if the vartypes are valid.
+ */
+static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
+{
+	HRESULT res = S_OK;
+
+	/* check if we have a valid argument.
+	 */
+	if( vt & VT_BYREF )
+    {
+        /* if by reference check that the type is in
+         * the valid range and that it is not of empty or null type
+         */
+        if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
+            ( vt & VT_TYPEMASK ) == VT_NULL ||
+			( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
+		{
+			res = E_INVALIDARG;
+		}
+			
+    }
+    else
+    {
+        res = ValidateVtRange( vt );
+    }
+		
+	return res;
+}
+
+/******************************************************************************
+ *		ValidateVt	[INTERNAL]
+ *
+ * Used internally by the hi-level Variant API to determine
+ * if the vartypes are valid.
+ */
+static HRESULT WINAPI ValidateVt( VARTYPE vt )
+{
+	HRESULT res = S_OK;
+
+	/* check if we have a valid argument.
+	 */
+	if( vt & VT_BYREF )
+    {
+        /* if by reference check that the type is in
+         * the valid range and that it is not of empty or null type
+         */
+        if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
+            ( vt & VT_TYPEMASK ) == VT_NULL ||
+			( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
+		{
+			res = DISP_E_BADVARTYPE;
+		}
+			
+    }
+    else
+    {
+        res = ValidateVtRange( vt );
+    }
+		
+	return res;
+}
+
+
+
+
+
+/******************************************************************************
+ *		VariantInit32	[OLEAUT32.8]
+ *
+ * Initializes the Variant.  Unlike VariantClear it does not interpret the current
+ * contents of the Variant.
+ */
+void WINAPI VariantInit(VARIANTARG* pvarg)
+{
+  TRACE("(%p),stub\n",pvarg);
+
+  memset(pvarg, 0, sizeof (VARIANTARG));
+  pvarg->vt = VT_EMPTY;
+
+  return;
+}
+
+/******************************************************************************
+ *		VariantClear32	[OLEAUT32.9]
+ *
+ * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
+ * sets the wReservedX field to 0.	The current contents of the VARIANT are
+ * freed.  If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
+ * released. If VT_ARRAY the array is freed.
+ */
+HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
+{
+  HRESULT res = S_OK;
+  TRACE("(%p)\n",pvarg);
+
+  res = ValidateVariantType( pvarg->vt );
+  if( res == S_OK )
+  {
+    if( !( pvarg->vt & VT_BYREF ) )
+    {
+      /*
+       * The VT_ARRAY flag is a special case of a safe array.
+       */
+      if ( (pvarg->vt & VT_ARRAY) != 0)
+      {
+	SafeArrayDestroy(pvarg->u.parray);
+      }
+      else
+      {
+	switch( pvarg->vt & VT_TYPEMASK )
+	{
+	  case( VT_BSTR ):
+	    SysFreeString( pvarg->u.bstrVal );
+	    break;
+	  case( VT_DISPATCH ):
+	    break;
+	  case( VT_VARIANT ):
+	    break;
+	  case( VT_UNKNOWN ):
+	    break;
+	  case( VT_SAFEARRAY ):
+	    SafeArrayDestroy(pvarg->u.parray);
+	    break;
+	  default:
+	    break;
+	}
+      }
+    }
+	
+    /*
+     * Empty all the fields and mark the type as empty.
+     */
+    memset(pvarg, 0, sizeof (VARIANTARG));
+    pvarg->vt = VT_EMPTY;
+  }
+
+  return res;
+}
+
+/******************************************************************************
+ *		VariantCopy32	[OLEAUT32.10]
+ *
+ * Frees up the designation variant and makes a copy of the source.
+ */
+HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
+{
+  HRESULT res = S_OK;
+
+  TRACE("(%p, %p)\n", pvargDest, pvargSrc);
+
+  res = ValidateVariantType( pvargSrc->vt );
+
+  /* If the pointer are to the same variant we don't need
+   * to do anything.
+   */
+  if( pvargDest != pvargSrc && res == S_OK )
+  {
+    res = VariantClear( pvargDest );
+		
+    if( res == S_OK )
+    {
+      if( pvargSrc->vt & VT_BYREF )
+      {
+	/* In the case of byreference we only need
+	 * to copy the pointer.
+	 */
+	pvargDest->u = pvargSrc->u;
+	pvargDest->vt = pvargSrc->vt;
+      }
+      else
+      {
+	/*
+	 * The VT_ARRAY flag is another way to designate a safe array.
+	 */
+	if (pvargSrc->vt & VT_ARRAY)
+	{
+	  SafeArrayCopy(pvargSrc->u.parray, &pvargDest->u.parray);
+	}
+	else
+	{
+	  /* In the case of by value we need to
+	   * copy the actuall value. In the case of
+	   * VT_BSTR a copy of the string is made,
+	   * if VT_DISPATCH or VT_IUNKNOWN AddReff is
+	   * called to increment the object's reference count.
+	   */
+	  switch( pvargSrc->vt & VT_TYPEMASK )
+	  {
+	    case( VT_BSTR ):
+	      pvargDest->u.bstrVal = SysAllocString( pvargSrc->u.bstrVal );
+	      break;
+	    case( VT_DISPATCH ):
+	      break;
+	    case( VT_VARIANT ):
+	      break;
+	    case( VT_UNKNOWN ):
+	      break;
+	    case( VT_SAFEARRAY ):
+	      SafeArrayCopy(pvargSrc->u.parray, &pvargDest->u.parray);
+	      break;
+	    default:
+	      pvargDest->u = pvargSrc->u;
+	      break;
+	  }
+	}
+	
+	pvargDest->vt = pvargSrc->vt;
+      }      
+    }
+  }
+
+  return res;
+}
+
+
+/******************************************************************************
+ *		VariantCopyInd32	[OLEAUT32.11]
+ *
+ * Frees up the destination variant and makes a copy of the source.  If
+ * the source is of type VT_BYREF it performs the necessary indirections.
+ */
+HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
+{
+  HRESULT res = S_OK;
+
+  TRACE("(%p, %p)\n", pvargDest, pvargSrc);
+
+  res = ValidateVariantType( pvargSrc->vt );
+
+  if( res != S_OK )
+    return res;
+  
+  if( pvargSrc->vt & VT_BYREF )
+  {
+    VARIANTARG varg;
+    VariantInit( &varg );
+
+    /* handle the in place copy.
+     */
+    if( pvargDest == pvargSrc )
+    {
+      /* we will use a copy of the source instead.
+       */
+      res = VariantCopy( &varg, pvargSrc );
+      pvargSrc = &varg;
+    }
+
+    if( res == S_OK )
+    {
+      res = VariantClear( pvargDest );
+
+      if( res == S_OK )
+      {
+	/*
+	 * The VT_ARRAY flag is another way to designate a safearray variant.
+	 */
+	if ( pvargSrc->vt & VT_ARRAY)
+	{
+	  SafeArrayCopy(*pvargSrc->u.pparray, &pvargDest->u.parray);
+	}
+	else
+	{
+	  /* In the case of by reference we need
+	   * to copy the date pointed to by the variant.
+	   */
+
+	  /* Get the variant type.
+	   */
+	  switch( pvargSrc->vt & VT_TYPEMASK )
+	  {
+	    case( VT_BSTR ):
+	      pvargDest->u.bstrVal = SysAllocString( *(pvargSrc->u.pbstrVal) );
+	      break;
+	    case( VT_DISPATCH ):
+	      break;
+	    case( VT_VARIANT ):
+	      {
+		/* Prevent from cycling.  According to tests on
+		 * VariantCopyInd in Windows and the documentation
+		 * this API dereferences the inner Variants to only one depth.
+		 * If the inner Variant itself contains an
+		 * other inner variant the E_INVALIDARG error is
+		 * returned. 
+		 */
+		if( pvargSrc->wReserved1 & PROCESSING_INNER_VARIANT )
+		{
+		  /* If we get here we are attempting to deference
+		   * an inner variant that that is itself contained
+		   * in an inner variant so report E_INVALIDARG error.
+		   */
+		  res = E_INVALIDARG;
+		}
+		else
+		{
+		  /* Set the processing inner variant flag.
+		   * We will set this flag in the inner variant
+		   * that will be passed to the VariantCopyInd function.
+		   */
+		  (pvargSrc->u.pvarVal)->wReserved1 |= PROCESSING_INNER_VARIANT;
+		  
+		  /* Dereference the inner variant.
+		   */
+		  res = VariantCopyInd( pvargDest, pvargSrc->u.pvarVal );
+		}
+	      }
+	      break;
+	    case( VT_UNKNOWN ):
+	      break;
+	    case( VT_SAFEARRAY ):
+	      SafeArrayCopy(*pvargSrc->u.pparray, &pvargDest->u.parray);
+	      break;
+	    default:
+	      /* This is a by reference Variant which means that the union
+	       * part of the Variant contains a pointer to some data of
+	       * type "pvargSrc->vt & VT_TYPEMASK".
+	       * We will deference this data in a generic fashion using
+	       * the void pointer "Variant.u.byref".
+	       * We will copy this data into the union of the destination
+	       * Variant.
+	       */
+	      memcpy( &pvargDest->u, pvargSrc->u.byref, SizeOfVariantData( pvargSrc ) );
+	      break;
+	  }
+	}
+	
+	pvargDest->vt = pvargSrc->vt & VT_TYPEMASK;
+      }
+    }
+
+    /* this should not fail.
+     */
+    VariantClear( &varg );
+  }
+  else
+  {
+    res = VariantCopy( pvargDest, pvargSrc );
+  }
+
+  return res;
+}
+
+/******************************************************************************
+ *		VariantChangeType32	[OLEAUT32.12]
+ */
+HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
+							USHORT wFlags, VARTYPE vt)
+{
+	return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
+}
+
+/******************************************************************************
+ *		VariantChangeTypeEx32	[OLEAUT32.147]
+ */
+HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
+							  LCID lcid, USHORT wFlags, VARTYPE vt)
+{
+	HRESULT res = S_OK;
+	VARIANTARG varg;
+	VariantInit( &varg );
+	
+	TRACE("(%p, %p, %ld, %u, %u),stub\n", pvargDest, pvargSrc, lcid, wFlags, vt);
+
+	/* validate our source argument.
+	 */
+	res = ValidateVariantType( pvargSrc->vt );
+
+	/* validate the vartype.
+	 */
+	if( res == S_OK )
+	{
+		res = ValidateVt( vt );
+	}
+
+	/* if we are doing an in-place conversion make a copy of the source.
+	 */
+	if( res == S_OK && pvargDest == pvargSrc )
+	{
+		res = VariantCopy( &varg, pvargSrc );
+		pvargSrc = &varg;
+	}
+
+	if( res == S_OK )
+	{
+		/* free up the destination variant.
+		 */
+		res = VariantClear( pvargDest );
+	}
+
+	if( res == S_OK )
+	{
+		if( pvargSrc->vt & VT_BYREF )
+		{
+			/* Convert the source variant to a "byvalue" variant.
+			 */
+			VARIANTARG Variant;
+			VariantInit( &Variant );
+			res = VariantCopyInd( &Variant, pvargSrc );
+			if( res == S_OK )
+			{
+				res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
+				/* this should not fail.
+				 */
+				VariantClear( &Variant );
+			}
+	
+		}
+		else
+		{
+			/* Use the current "byvalue" source variant.
+			 */
+			res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
+		}
+	}
+	/* this should not fail.
+	 */
+	VariantClear( &varg );
+	
+	/* set the type of the destination
+	 */
+	if ( res == S_OK )
+		pvargDest->vt = vt;
+
+	return res;
+}
+
+
+
+
+/******************************************************************************
+ *		VarUI1FromI232		[OLEAUT32.130]
+ */
+HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
+{
+	TRACE("( %d, %p ), stub\n", sIn, pbOut );
+
+	/* Check range of value.
+	 */
+	if( sIn < UI1_MIN || sIn > UI1_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pbOut = (BYTE) sIn;
+	
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI1FromI432		[OLEAUT32.131]
+ */
+HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
+{
+	TRACE("( %ld, %p ), stub\n", lIn, pbOut );
+
+	/* Check range of value.
+	 */
+	if( lIn < UI1_MIN || lIn > UI1_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pbOut = (BYTE) lIn;
+	
+	return S_OK;
+}
+
+
+/******************************************************************************
+ *		VarUI1FromR432		[OLEAUT32.132]
+ */
+HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
+{
+	TRACE("( %f, %p ), stub\n", fltIn, pbOut );
+
+	/* Check range of value.
+     */
+    fltIn = round( fltIn );
+	if( fltIn < UI1_MIN || fltIn > UI1_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pbOut = (BYTE) fltIn;
+	
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI1FromR832		[OLEAUT32.133]
+ */
+HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
+{
+	TRACE("( %f, %p ), stub\n", dblIn, pbOut );
+
+	/* Check range of value.
+     */
+    dblIn = round( dblIn );
+	if( dblIn < UI1_MIN || dblIn > UI1_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pbOut = (BYTE) dblIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI1FromDate32		[OLEAUT32.135]
+ */
+HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
+{
+	TRACE("( %f, %p ), stub\n", dateIn, pbOut );
+
+	/* Check range of value.
+     */
+    dateIn = round( dateIn );
+	if( dateIn < UI1_MIN || dateIn > UI1_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pbOut = (BYTE) dateIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI1FromBool32		[OLEAUT32.138]
+ */
+HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pbOut );
+
+	*pbOut = (BYTE) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI1FromI132		[OLEAUT32.237]
+ */
+HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pbOut );
+
+	*pbOut = cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI1FromUI232		[OLEAUT32.238]
+ */
+HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pbOut );
+
+	/* Check range of value.
+	 */
+	if( uiIn > UI1_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pbOut = (BYTE) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI1FromUI432		[OLEAUT32.239]
+ */
+HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
+{
+	TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
+
+	/* Check range of value.
+	 */
+	if( ulIn > UI1_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pbOut = (BYTE) ulIn;
+
+	return S_OK;
+}
+
+
+/******************************************************************************
+ *		VarUI1FromStr32		[OLEAUT32.54]
+ */
+HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
+{
+	double dValue = 0.0;
+	LPSTR pNewString = NULL;
+
+	TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
+
+	/* Check if we have a valid argument
+	 */
+	pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+	RemoveCharacterFromString( pNewString, "," );
+	if( IsValidRealString( pNewString ) == FALSE )
+	{
+		return DISP_E_TYPEMISMATCH;
+	}
+
+	/* Convert the valid string to a floating point number.
+	 */
+	dValue = atof( pNewString );
+	
+	/* We don't need the string anymore so free it.
+	 */
+	HeapFree( GetProcessHeap(), 0 , pNewString );
+
+	/* Check range of value.
+     */
+    dValue = round( dValue );
+	if( dValue < UI1_MIN || dValue > UI1_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pbOut = (BYTE) dValue;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarUI1FromCy32 [OLEAUT32.134]
+ * Convert currency to unsigned char
+ */
+HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
+   double t = round((((double)cyIn.u.Hi * 4294967296.0) + (double)cyIn.u.Lo) / 10000);
+   
+   if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
+   
+   *pbOut = (BYTE)t;
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromUI132		[OLEAUT32.48]
+ */
+HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
+{
+	TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
+
+	*psOut = (short) bIn;
+	
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromI432		[OLEAUT32.49]
+ */
+HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
+{
+	TRACE("( %lx, %p ), stub\n", lIn, psOut );
+
+	/* Check range of value.
+	 */
+	if( lIn < I2_MIN || lIn > I2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*psOut = (short) lIn;
+	
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromR432		[OLEAUT32.50]
+ */
+HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
+{
+	TRACE("( %f, %p ), stub\n", fltIn, psOut );
+
+	/* Check range of value.
+     */
+    fltIn = round( fltIn );
+	if( fltIn < I2_MIN || fltIn > I2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*psOut = (short) fltIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromR832		[OLEAUT32.51]
+ */
+HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
+{
+	TRACE("( %f, %p ), stub\n", dblIn, psOut );
+
+	/* Check range of value.
+     */
+    dblIn = round( dblIn );
+	if( dblIn < I2_MIN || dblIn > I2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*psOut = (short) dblIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromDate32		[OLEAUT32.53]
+ */
+HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
+{
+	TRACE("( %f, %p ), stub\n", dateIn, psOut );
+
+	/* Check range of value.
+     */
+    dateIn = round( dateIn );
+	if( dateIn < I2_MIN || dateIn > I2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*psOut = (short) dateIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromBool32		[OLEAUT32.56]
+ */
+HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, psOut );
+
+	*psOut = (short) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromI132		[OLEAUT32.48]
+ */
+HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, psOut );
+
+	*psOut = (short) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromUI232		[OLEAUT32.206]
+ */
+HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, psOut );
+
+	/* Check range of value.
+	 */
+	if( uiIn > I2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*psOut = (short) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromUI432		[OLEAUT32.49]
+ */
+HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
+{
+	TRACE("( %lx, %p ), stub\n", ulIn, psOut );
+
+	/* Check range of value.
+	 */
+	if( ulIn < I2_MIN || ulIn > I2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*psOut = (short) ulIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromStr32		[OLEAUT32.54]
+ */
+HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
+{
+	double dValue = 0.0;
+	LPSTR pNewString = NULL;
+
+	TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
+
+	/* Check if we have a valid argument
+	 */
+	pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+	RemoveCharacterFromString( pNewString, "," );
+	if( IsValidRealString( pNewString ) == FALSE )
+	{
+		return DISP_E_TYPEMISMATCH;
+	}
+
+	/* Convert the valid string to a floating point number.
+	 */
+	dValue = atof( pNewString );
+	
+	/* We don't need the string anymore so free it.
+	 */
+	HeapFree( GetProcessHeap(), 0, pNewString );
+
+	/* Check range of value.
+     */
+    dValue = round( dValue );
+	if( dValue < I2_MIN || dValue > I2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*psOut = (short)  dValue;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarI2FromCy32 [OLEAUT32.52]
+ * Convert currency to signed short
+ */
+HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
+   double t = round((((double)cyIn.u.Hi * 4294967296.0) + (double)cyIn.u.Lo) / 10000);
+   
+   if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
+   
+   *psOut = (SHORT)t;
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromUI132		[OLEAUT32.58]
+ */
+HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
+{
+	TRACE("( %X, %p ), stub\n", bIn, plOut );
+
+	*plOut = (LONG) bIn;
+
+	return S_OK;
+}
+
+
+/******************************************************************************
+ *		VarI4FromR432		[OLEAUT32.60]
+ */
+HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
+{
+	TRACE("( %f, %p ), stub\n", fltIn, plOut );
+
+	/* Check range of value.
+     */
+    fltIn = round( fltIn );
+	if( fltIn < I4_MIN || fltIn > I4_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*plOut = (LONG) fltIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromR832		[OLEAUT32.61]
+ */
+HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
+{
+	TRACE("( %f, %p ), stub\n", dblIn, plOut );
+
+	/* Check range of value.
+     */
+    dblIn = round( dblIn );
+	if( dblIn < I4_MIN || dblIn > I4_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*plOut = (LONG) dblIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromDate32		[OLEAUT32.63]
+ */
+HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
+{
+	TRACE("( %f, %p ), stub\n", dateIn, plOut );
+
+	/* Check range of value.
+     */
+    dateIn = round( dateIn );
+	if( dateIn < I4_MIN || dateIn > I4_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*plOut = (LONG) dateIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromBool32		[OLEAUT32.66]
+ */
+HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, plOut );
+
+	*plOut = (LONG) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromI132		[OLEAUT32.209]
+ */
+HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, plOut );
+
+	*plOut = (LONG) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromUI232		[OLEAUT32.210]
+ */
+HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, plOut );
+
+	*plOut = (LONG) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromUI432		[OLEAUT32.211]
+ */
+HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
+{
+	TRACE("( %lx, %p ), stub\n", ulIn, plOut );
+
+	/* Check range of value.
+	 */
+	if( ulIn < I4_MIN || ulIn > I4_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*plOut = (LONG) ulIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromI232		[OLEAUT32.59]
+ */
+HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
+{
+	TRACE("( %d, %p ), stub\n", sIn, plOut );
+
+	*plOut = (LONG) sIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromStr32		[OLEAUT32.64]
+ */
+HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
+{
+	double dValue = 0.0;
+	LPSTR pNewString = NULL;
+
+	TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
+
+	/* Check if we have a valid argument
+	 */
+	pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+	RemoveCharacterFromString( pNewString, "," );
+	if( IsValidRealString( pNewString ) == FALSE )
+	{
+		return DISP_E_TYPEMISMATCH;
+	}
+
+	/* Convert the valid string to a floating point number.
+	 */
+	dValue = atof( pNewString );
+	
+	/* We don't need the string anymore so free it.
+	 */
+	HeapFree( GetProcessHeap(), 0, pNewString );
+
+	/* Check range of value.
+     */
+    dValue = round( dValue );
+	if( dValue < I4_MIN || dValue > I4_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*plOut = (LONG) dValue;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarI4FromCy32 [OLEAUT32.62]
+ * Convert currency to signed long
+ */
+HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
+   double t = round((((double)cyIn.u.Hi * 4294967296.0) + (double)cyIn.u.Lo) / 10000);
+   
+   if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
+   
+   *plOut = (LONG)t;
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromUI132		[OLEAUT32.68]
+ */
+HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
+{
+	TRACE("( %X, %p ), stub\n", bIn, pfltOut );
+
+	*pfltOut = (FLOAT) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromI232		[OLEAUT32.69]
+ */
+HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
+{
+	TRACE("( %d, %p ), stub\n", sIn, pfltOut );
+
+	*pfltOut = (FLOAT) sIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromI432		[OLEAUT32.70]
+ */
+HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
+{
+	TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
+
+	*pfltOut = (FLOAT) lIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromR832		[OLEAUT32.71]
+ */
+HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
+{
+	TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
+
+	/* Check range of value.
+	 */
+	if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pfltOut = (FLOAT) dblIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromDate32		[OLEAUT32.73]
+ */
+HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
+{
+	TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
+
+	/* Check range of value.
+	 */
+	if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pfltOut = (FLOAT) dateIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromBool32		[OLEAUT32.76]
+ */
+HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
+
+	*pfltOut = (FLOAT) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromI132		[OLEAUT32.213]
+ */
+HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pfltOut );
+
+	*pfltOut = (FLOAT) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromUI232		[OLEAUT32.214]
+ */
+HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
+
+	*pfltOut = (FLOAT) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromUI432		[OLEAUT32.215]
+ */
+HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
+{
+	TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
+
+	*pfltOut = (FLOAT) ulIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromStr32		[OLEAUT32.74]
+ */
+HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
+{
+	double dValue = 0.0;
+	LPSTR pNewString = NULL;
+
+	TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
+
+	/* Check if we have a valid argument
+	 */
+	pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+	RemoveCharacterFromString( pNewString, "," );
+	if( IsValidRealString( pNewString ) == FALSE )
+	{
+		return DISP_E_TYPEMISMATCH;
+	}
+
+	/* Convert the valid string to a floating point number.
+	 */
+	dValue = atof( pNewString );
+	
+	/* We don't need the string anymore so free it.
+	 */
+	HeapFree( GetProcessHeap(), 0, pNewString );
+
+	/* Check range of value.
+	 */
+	if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pfltOut = (FLOAT) dValue;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarR4FromCy32 [OLEAUT32.72]
+ * Convert currency to float
+ */
+HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
+   *pfltOut = (FLOAT)((((double)cyIn.u.Hi * 4294967296.0) + (double)cyIn.u.Lo) / 10000);
+   
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromUI132		[OLEAUT32.68]
+ */
+HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
+{
+	TRACE("( %d, %p ), stub\n", bIn, pdblOut );
+
+	*pdblOut = (double) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromI232		[OLEAUT32.69]
+ */
+HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
+{
+	TRACE("( %d, %p ), stub\n", sIn, pdblOut );
+
+	*pdblOut = (double) sIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromI432		[OLEAUT32.70]
+ */
+HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
+{
+	TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
+
+	*pdblOut = (double) lIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromR432		[OLEAUT32.81]
+ */
+HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
+{
+	TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
+
+	*pdblOut = (double) fltIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromDate32		[OLEAUT32.83]
+ */
+HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
+{
+	TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
+
+	*pdblOut = (double) dateIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromBool32		[OLEAUT32.86]
+ */
+HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
+
+	*pdblOut = (double) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromI132		[OLEAUT32.217]
+ */
+HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pdblOut );
+
+	*pdblOut = (double) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromUI232		[OLEAUT32.218]
+ */
+HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
+
+	*pdblOut = (double) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromUI432		[OLEAUT32.219]
+ */
+HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
+{
+	TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
+
+	*pdblOut = (double) ulIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromStr32		[OLEAUT32.84]
+ */
+HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
+{
+	double dValue = 0.0;
+	LPSTR pNewString = NULL;
+
+	TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pdblOut );
+
+	/* Check if we have a valid argument
+	 */
+	pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+	RemoveCharacterFromString( pNewString, "," );
+	if( IsValidRealString( pNewString ) == FALSE )
+	{
+		return DISP_E_TYPEMISMATCH;
+	}
+
+	/* Convert the valid string to a floating point number.
+	 */
+	dValue = atof( pNewString );
+	
+	/* We don't need the string anymore so free it.
+	 */
+	HeapFree( GetProcessHeap(), 0, pNewString );
+
+	*pdblOut = dValue;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarR8FromCy32 [OLEAUT32.82]
+ * Convert currency to double
+ */
+HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
+   *pdblOut = (double)((((double)cyIn.u.Hi * 4294967296.0) + (double)cyIn.u.Lo) / 10000);
+   
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromUI132		[OLEAUT32.]
+ */
+HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
+{
+	TRACE("( %d, %p ), stub\n", bIn, pdateOut );
+
+	*pdateOut = (DATE) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromI232		[OLEAUT32.222]
+ */
+HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
+{
+	TRACE("( %d, %p ), stub\n", sIn, pdateOut );
+
+	*pdateOut = (DATE) sIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromI432		[OLEAUT32.90]
+ */
+HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
+{
+	TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
+
+	if( lIn < DATE_MIN || lIn > DATE_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pdateOut = (DATE) lIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromR432		[OLEAUT32.91]
+ */
+HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
+{
+    TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
+
+    if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pdateOut = (DATE) fltIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromR832		[OLEAUT32.92]
+ */
+HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
+{
+    TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
+
+	if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pdateOut = (DATE) dblIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromStr32		[OLEAUT32.94]
+ * The string representing the date is composed of two parts, a date and time.
+ *
+ * The format of the time is has follows:
+ * hh[:mm][:ss][AM|PM]
+ * Whitespace can be inserted anywhere between these tokens.  A whitespace consists
+ * of space and/or tab characters, which are ignored.
+ *
+ * The formats for the date part are has follows:
+ * mm/[dd/][yy]yy 
+ * [dd/]mm/[yy]yy
+ * [yy]yy/mm/dd 
+ * January dd[,] [yy]yy
+ * dd January [yy]yy
+ * [yy]yy January dd
+ * Whitespace can be inserted anywhere between these tokens.
+ *
+ * The formats for the date and time string are has follows.
+ * date[whitespace][time] 
+ * [time][whitespace]date
+ *
+ * These are the only characters allowed in a string representing a date and time:
+ * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
+ */
+HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
+{
+	HRESULT ret = S_OK;
+    struct tm TM = { 0,0,0,0,0,0,0,0,0 };
+
+    TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
+
+    if( DateTimeStringToTm( strIn, lcid, &TM ) )
+    {
+        if( TmToDATE( &TM, pdateOut ) == FALSE )
+        {
+            ret = E_INVALIDARG;
+        }
+    }
+    else
+    {
+        ret = DISP_E_TYPEMISMATCH;
+    }
+
+
+	return ret;
+}
+
+/******************************************************************************
+ *		VarDateFromI132		[OLEAUT32.221]
+ */
+HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pdateOut );
+
+	*pdateOut = (DATE) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromUI232		[OLEAUT32.222]
+ */
+HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
+
+	if( uiIn > DATE_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pdateOut = (DATE) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromUI432		[OLEAUT32.223]
+ */
+HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
+{
+	TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
+
+	if( ulIn < DATE_MIN || ulIn > DATE_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pdateOut = (DATE) ulIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromBool32		[OLEAUT32.96]
+ */
+HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
+
+	*pdateOut = (DATE) boolIn;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarDateFromCy32 [OLEAUT32.93]
+ * Convert currency to date
+ */
+HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
+   *pdateOut = (DATE)((((double)cyIn.u.Hi * 4294967296.0) + (double)cyIn.u.Lo) / 10000);
+
+   if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromUI132		[OLEAUT32.108]
+ */
+HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+	TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
+	sprintf( pBuffer, "%d", bVal );
+
+	*pbstrOut =  StringDupAtoBstr( pBuffer );
+	
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromI232		[OLEAUT32.109]
+ */
+HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+	TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
+	sprintf( pBuffer, "%d", iVal );
+	*pbstrOut = StringDupAtoBstr( pBuffer );
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromI432		[OLEAUT32.110]
+ */
+HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+	TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
+
+	sprintf( pBuffer, "%ld", lIn );
+	*pbstrOut = StringDupAtoBstr( pBuffer );
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromR432		[OLEAUT32.111]
+ */
+HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+	TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
+
+	sprintf( pBuffer, "%.7g", fltIn );
+	*pbstrOut = StringDupAtoBstr( pBuffer );
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromR832		[OLEAUT32.112]
+ */
+HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+	TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
+
+	sprintf( pBuffer, "%.15g", dblIn );
+	*pbstrOut = StringDupAtoBstr( pBuffer );
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *    VarBstrFromCy   [OLEAUT32.113]
+ */
+HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
+				/* FIXME */
+	return E_NOTIMPL;
+}
+
+ 
+/******************************************************************************
+ *		VarBstrFromDate32		[OLEAUT32.114]
+ *
+ * The date is implemented using an 8 byte floating-point number.
+ * Days are represented by whole numbers increments starting with 0.00 has
+ * being December 30 1899, midnight.
+ * The hours are expressed as the fractional part of the number.
+ * December 30 1899 at midnight = 0.00
+ * January 1 1900 at midnight = 2.00
+ * January 4 1900 at 6 AM = 5.25
+ * January 4 1900 at noon = 5.50
+ * December 29 1899 at midnight = -1.00
+ * December 18 1899 at midnight = -12.00
+ * December 18 1899 at 6AM = -12.25
+ * December 18 1899 at 6PM = -12.75
+ * December 19 1899 at midnight = -11.00
+ * The tm structure is as follows:
+ * struct tm {
+ *		  int tm_sec;	   seconds after the minute - [0,59]
+ *		  int tm_min;	   minutes after the hour - [0,59]
+ *		  int tm_hour;	   hours since midnight - [0,23]
+ *		  int tm_mday;	   day of the month - [1,31]
+ *		  int tm_mon;	   months since January - [0,11]
+ *		  int tm_year;	   years
+ *		  int tm_wday;	   days since Sunday - [0,6]
+ *		  int tm_yday;	   days since January 1 - [0,365]
+ *		  int tm_isdst;    daylight savings time flag
+ *		  };
+ */
+HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+		struct tm TM = {0,0,0,0,0,0,0,0,0};
+	 
+    TRACE("( %f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
+
+    if( DateToTm( dateIn, lcid, &TM ) == FALSE )
+			{
+        return E_INVALIDARG;
+		}
+
+		if( lcid & VAR_DATEVALUEONLY )
+			strftime( pBuffer, BUFFER_MAX, "%x", &TM );
+		else if( lcid & VAR_TIMEVALUEONLY )
+			strftime( pBuffer, BUFFER_MAX, "%X", &TM );
+		else
+        strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
+
+		*pbstrOut = StringDupAtoBstr( pBuffer );
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromBool32		[OLEAUT32.116]
+ */
+HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+	TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
+
+	if( boolIn == VARIANT_FALSE )
+	{
+		sprintf( pBuffer, "False" );
+	}
+	else
+	{
+		sprintf( pBuffer, "True" );
+	}
+
+	*pbstrOut = StringDupAtoBstr( pBuffer );
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromI132		[OLEAUT32.229]
+ */
+HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+	TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
+	sprintf( pBuffer, "%d", cIn );
+	*pbstrOut = StringDupAtoBstr( pBuffer );
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromUI232		[OLEAUT32.230]
+ */
+HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+	TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
+	sprintf( pBuffer, "%d", uiIn );
+	*pbstrOut = StringDupAtoBstr( pBuffer );
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromUI432		[OLEAUT32.231]
+ */
+HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
+{
+	TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
+	sprintf( pBuffer, "%ld", ulIn );
+	*pbstrOut = StringDupAtoBstr( pBuffer );
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBoolFromUI132		[OLEAUT32.118]
+ */
+HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
+{
+	TRACE("( %d, %p ), stub\n", bIn, pboolOut );
+
+	if( bIn == 0 )
+	{
+		*pboolOut = VARIANT_FALSE;
+	}
+	else
+	{
+		*pboolOut = VARIANT_TRUE;
+	}
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBoolFromI232		[OLEAUT32.119]
+ */
+HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
+{
+	TRACE("( %d, %p ), stub\n", sIn, pboolOut );
+
+	if( sIn == 0 )
+	{
+		*pboolOut = VARIANT_FALSE;
+	}
+	else
+	{
+		*pboolOut = VARIANT_TRUE;
+	}
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBoolFromI432		[OLEAUT32.120]
+ */
+HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
+{
+	TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
+
+	if( lIn == 0 )
+	{
+		*pboolOut = VARIANT_FALSE;
+	}
+	else
+	{
+		*pboolOut = VARIANT_TRUE;
+	}
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBoolFromR432		[OLEAUT32.121]
+ */
+HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
+{
+	TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
+
+	if( fltIn == 0.0 )
+	{
+		*pboolOut = VARIANT_FALSE;
+	}
+	else
+	{
+		*pboolOut = VARIANT_TRUE;
+	}
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBoolFromR832		[OLEAUT32.122]
+ */
+HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
+{
+	TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
+
+	if( dblIn == 0.0 )
+	{
+		*pboolOut = VARIANT_FALSE;
+	}
+	else
+	{
+		*pboolOut = VARIANT_TRUE;
+	}
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBoolFromDate32		[OLEAUT32.123]
+ */
+HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
+{
+	TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
+
+	if( dateIn == 0.0 )
+	{
+		*pboolOut = VARIANT_FALSE;
+	}
+	else
+	{
+		*pboolOut = VARIANT_TRUE;
+	}
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBoolFromStr32		[OLEAUT32.125]
+ */
+HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
+{
+	HRESULT ret = S_OK;
+	char* pNewString = NULL;
+
+	TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
+
+    pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+
+	if( pNewString == NULL || strlen( pNewString ) == 0 )
+	{
+		ret = DISP_E_TYPEMISMATCH;
+	}
+
+	if( ret == S_OK )
+	{
+//		if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
+		if( stricmp( pNewString, "True" ) == 0 )
+		{
+			*pboolOut = VARIANT_TRUE;
+		}
+//		else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
+		if( stricmp( pNewString, "False" ) == 0 )
+		{
+			*pboolOut = VARIANT_FALSE;
+		}
+		else
+		{
+			/* Try converting the string to a floating point number.
+			 */
+			double dValue = 0.0;
+			HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
+			if( res != S_OK )
+			{
+				ret = DISP_E_TYPEMISMATCH;
+			}
+			else if( dValue == 0.0 )
+			{
+				*pboolOut = VARIANT_FALSE;
+			}
+			else
+			{
+				*pboolOut = VARIANT_TRUE;
+			}
+		}
+	}
+
+	HeapFree( GetProcessHeap(), 0, pNewString );
+	
+	return ret;
+}
+
+/******************************************************************************
+ *		VarBoolFromI132		[OLEAUT32.233]
+ */
+HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pboolOut );
+
+	if( cIn == 0 )
+	{
+		*pboolOut = VARIANT_FALSE;
+	}
+	else
+	{
+		*pboolOut = VARIANT_TRUE;
+	}
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBoolFromUI232		[OLEAUT32.234]
+ */
+HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
+
+	if( uiIn == 0 )
+	{
+		*pboolOut = VARIANT_FALSE;
+	}
+	else
+	{
+		*pboolOut = VARIANT_TRUE;
+	}
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBoolFromUI432		[OLEAUT32.235]
+ */
+HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
+{
+	TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
+
+	if( ulIn == 0 )
+	{
+		*pboolOut = VARIANT_FALSE;
+	}
+	else
+	{
+		*pboolOut = VARIANT_TRUE;
+	}
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarBoolFromCy32 [OLEAUT32.124]
+ * Convert currency to boolean
+ */
+HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
+      if (cyIn.u.Hi || cyIn.u.Lo) *pboolOut = -1;
+      else *pboolOut = 0;
+      
+      return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromUI132		[OLEAUT32.244]
+ */
+HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
+{
+	TRACE("( %d, %p ), stub\n", bIn, pcOut );
+
+	/* Check range of value.
+	 */
+	if( bIn > CHAR_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pcOut = (CHAR) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromI232		[OLEAUT32.245]
+ */
+HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pcOut );
+
+	if( uiIn > CHAR_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pcOut = (CHAR) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromI432		[OLEAUT32.246]
+ */
+HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
+{
+	TRACE("( %ld, %p ), stub\n", lIn, pcOut );
+
+	if( lIn < CHAR_MIN || lIn > CHAR_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pcOut = (CHAR) lIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromR432		[OLEAUT32.247]
+ */
+HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
+{
+	TRACE("( %f, %p ), stub\n", fltIn, pcOut );
+
+    fltIn = round( fltIn );
+	if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pcOut = (CHAR) fltIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromR832		[OLEAUT32.248]
+ */
+HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
+{
+	TRACE("( %f, %p ), stub\n", dblIn, pcOut );
+
+    dblIn = round( dblIn );
+    if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pcOut = (CHAR) dblIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromDate32		[OLEAUT32.249]
+ */
+HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
+{
+	TRACE("( %f, %p ), stub\n", dateIn, pcOut );
+
+    dateIn = round( dateIn );
+	if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pcOut = (CHAR) dateIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromStr32		[OLEAUT32.251]
+ */
+HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
+{
+	double dValue = 0.0;
+	LPSTR pNewString = NULL;
+
+	TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
+
+	/* Check if we have a valid argument
+	 */
+	pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+	RemoveCharacterFromString( pNewString, "," );
+	if( IsValidRealString( pNewString ) == FALSE )
+	{
+		return DISP_E_TYPEMISMATCH;
+	}
+
+	/* Convert the valid string to a floating point number.
+	 */
+	dValue = atof( pNewString );
+  
+	/* We don't need the string anymore so free it.
+	 */
+	HeapFree( GetProcessHeap(), 0, pNewString );
+
+	/* Check range of value.
+     */
+    dValue = round( dValue );
+	if( dValue < CHAR_MIN || dValue > CHAR_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pcOut = (CHAR) dValue;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromBool32		[OLEAUT32.253]
+ */
+HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pcOut );
+
+	*pcOut = (CHAR) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromUI232		[OLEAUT32.254]
+ */
+HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pcOut );
+
+	if( uiIn > CHAR_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pcOut = (CHAR) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromUI432		[OLEAUT32.255]
+ */
+HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
+{
+	TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
+
+	if( ulIn > CHAR_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pcOut = (CHAR) ulIn;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarI1FromCy32 [OLEAUT32.250]
+ * Convert currency to signed char
+ */
+HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
+   double t = round((((double)cyIn.u.Hi * 4294967296.0) + (double)cyIn.u.Lo) / 10000);
+   
+   if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
+   
+   *pcOut = (CHAR)t;
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromUI132		[OLEAUT32.257]
+ */
+HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
+{
+	TRACE("( %d, %p ), stub\n", bIn, puiOut );
+
+	*puiOut = (USHORT) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromI232		[OLEAUT32.258]
+ */
+HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, puiOut );
+
+	if( uiIn < UI2_MIN )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*puiOut = (USHORT) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromI432		[OLEAUT32.259]
+ */
+HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
+{
+	TRACE("( %ld, %p ), stub\n", lIn, puiOut );
+
+	if( lIn < UI2_MIN || lIn > UI2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*puiOut = (USHORT) lIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromR432		[OLEAUT32.260]
+ */
+HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
+{
+	TRACE("( %f, %p ), stub\n", fltIn, puiOut );
+
+    fltIn = round( fltIn );
+	if( fltIn < UI2_MIN || fltIn > UI2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*puiOut = (USHORT) fltIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromR832		[OLEAUT32.261]
+ */
+HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
+{
+	TRACE("( %f, %p ), stub\n", dblIn, puiOut );
+
+    dblIn = round( dblIn );
+    if( dblIn < UI2_MIN || dblIn > UI2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*puiOut = (USHORT) dblIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromDate32		[OLEAUT32.262]
+ */
+HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
+{
+	TRACE("( %f, %p ), stub\n", dateIn, puiOut );
+
+    dateIn = round( dateIn );
+	if( dateIn < UI2_MIN || dateIn > UI2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*puiOut = (USHORT) dateIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromStr32		[OLEAUT32.264]
+ */
+HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
+{
+	double dValue = 0.0;
+	LPSTR pNewString = NULL;
+
+	TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
+
+	/* Check if we have a valid argument
+	 */
+	pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+	RemoveCharacterFromString( pNewString, "," );
+	if( IsValidRealString( pNewString ) == FALSE )
+	{
+		return DISP_E_TYPEMISMATCH;
+	}
+
+	/* Convert the valid string to a floating point number.
+	 */
+	dValue = atof( pNewString );
+  
+	/* We don't need the string anymore so free it.
+	 */
+	HeapFree( GetProcessHeap(), 0, pNewString );
+
+	/* Check range of value.
+     */
+    dValue = round( dValue );
+	if( dValue < UI2_MIN || dValue > UI2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*puiOut = (USHORT) dValue;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromBool32		[OLEAUT32.266]
+ */
+HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, puiOut );
+
+	*puiOut = (USHORT) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromI132		[OLEAUT32.267]
+ */
+HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, puiOut );
+
+	*puiOut = (USHORT) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromUI432		[OLEAUT32.268]
+ */
+HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
+{
+	TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
+
+	if( ulIn < UI2_MIN || ulIn > UI2_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*puiOut = (USHORT) ulIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromStr32		[OLEAUT32.277]
+ */
+HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
+{
+	double dValue = 0.0;
+	LPSTR pNewString = NULL;
+
+	TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
+
+	/* Check if we have a valid argument
+	 */
+	pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
+	RemoveCharacterFromString( pNewString, "," );
+	if( IsValidRealString( pNewString ) == FALSE )
+	{
+		return DISP_E_TYPEMISMATCH;
+	}
+
+	/* Convert the valid string to a floating point number.
+	 */
+	dValue = atof( pNewString );
+  
+	/* We don't need the string anymore so free it.
+	 */
+	HeapFree( GetProcessHeap(), 0, pNewString );
+
+	/* Check range of value.
+     */
+    dValue = round( dValue );
+	if( dValue < UI4_MIN || dValue > UI4_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pulOut = (ULONG) dValue;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarUI2FromCy32 [OLEAUT32.263]
+ * Convert currency to unsigned short
+ */
+HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
+   double t = round((((double)cyIn.u.Hi * 4294967296.0) + (double)cyIn.u.Lo) / 10000);
+   
+   if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
+      
+   *pusOut = (USHORT)t;
+   
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromUI132		[OLEAUT32.270]
+ */
+HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
+{
+	TRACE("( %d, %p ), stub\n", bIn, pulOut );
+
+	*pulOut = (USHORT) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromI232		[OLEAUT32.271]
+ */
+HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pulOut );
+
+	if( uiIn < UI4_MIN )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pulOut = (ULONG) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromI432		[OLEAUT32.272]
+ */
+HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
+{
+	TRACE("( %ld, %p ), stub\n", lIn, pulOut );
+
+	if( lIn < UI4_MIN )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pulOut = (ULONG) lIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromR432		[OLEAUT32.273]
+ */
+HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
+{
+    fltIn = round( fltIn );
+    if( fltIn < UI4_MIN || fltIn > UI4_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pulOut = (ULONG) fltIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromR832		[OLEAUT32.274]
+ */
+HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
+{
+	TRACE("( %f, %p ), stub\n", dblIn, pulOut );
+
+    dblIn = round( dblIn );
+	if( dblIn < UI4_MIN || dblIn > UI4_MAX )
+	{
+		return DISP_E_OVERFLOW;
+    }
+
+	*pulOut = (ULONG) dblIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromDate32		[OLEAUT32.275]
+ */
+HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
+{
+	TRACE("( %f, %p ), stub\n", dateIn, pulOut );
+
+    dateIn = round( dateIn );
+    if( dateIn < UI4_MIN || dateIn > UI4_MAX )
+	{
+		return DISP_E_OVERFLOW;
+	}
+
+	*pulOut = (ULONG) dateIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromBool32		[OLEAUT32.279]
+ */
+HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pulOut );
+
+	*pulOut = (ULONG) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromI132		[OLEAUT32.280]
+ */
+HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pulOut );
+
+	*pulOut = (ULONG) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromUI232		[OLEAUT32.281]
+ */
+HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pulOut );
+
+	*pulOut = (ULONG) uiIn;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarUI4FromCy32 [OLEAUT32.276]
+ * Convert currency to unsigned long
+ */
+HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
+   double t = round((((double)cyIn.u.Hi * 4294967296.0) + (double)cyIn.u.Lo) / 10000);
+   
+   if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
+
+   *pulOut = (ULONG)t;
+
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromUI132 [OLEAUT32.98]
+ * Convert unsigned char to currency
+ */
+HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
+   pcyOut->u.Hi = 0;
+   pcyOut->u.Lo = ((ULONG)bIn) * 10000;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromI232 [OLEAUT32.99]
+ * Convert signed short to currency
+ */
+HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
+   if (sIn < 0) pcyOut->u.Hi = -1;
+   else pcyOut->u.Hi = 0;
+   pcyOut->u.Lo = ((ULONG)sIn) * 10000;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromI432 [OLEAUT32.100]
+ * Convert signed long to currency
+ */
+HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
+      double t = (double)lIn * (double)10000;
+      pcyOut->u.Hi = (LONG)(t / (double)4294967296.0);
+      pcyOut->u.Lo = (ULONG)fmod(t, (double)4294967296.0);
+      if (lIn < 0) pcyOut->u.Hi--;
+   
+      return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromR432 [OLEAUT32.101]
+ * Convert float to currency
+ */
+HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
+   double t = round((double)fltIn * (double)10000);
+   pcyOut->u.Hi = (LONG)(t / (double)4294967296.0);
+   pcyOut->u.Lo = (ULONG)fmod(t, (double)4294967296.0);
+   if (fltIn < 0) pcyOut->u.Hi--;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromR832 [OLEAUT32.102]
+ * Convert double to currency
+ */
+HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
+   double t = round(dblIn * (double)10000);
+   pcyOut->u.Hi = (LONG)(t / (double)4294967296.0);
+   pcyOut->u.Lo = (ULONG)fmod(t, (double)4294967296.0);
+   if (dblIn < 0) pcyOut->u.Hi--;
+
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromDate32 [OLEAUT32.103]
+ * Convert date to currency
+ */
+HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
+   double t = round((double)dateIn * (double)10000);
+   pcyOut->u.Hi = (LONG)(t / (double)4294967296.0);
+   pcyOut->u.Lo = (ULONG)fmod(t, (double)4294967296.0);
+   if (dateIn < 0) pcyOut->u.Hi--;
+
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromDate32 [OLEAUT32.104]
+ */
+HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
+				/* FIXME */
+		return E_NOTIMPL;
+}
+
+ 
+/**********************************************************************
+ *              VarCyFromBool32 [OLEAUT32.106]
+ * Convert boolean to currency
+ */
+HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
+   if (boolIn < 0) pcyOut->u.Hi = -1;
+   else pcyOut->u.Hi = 0;
+   pcyOut->u.Lo = (ULONG)boolIn * (ULONG)10000;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromI132 [OLEAUT32.225]
+ * Convert signed char to currency
+ */
+HRESULT WINAPI VarCyFromI1(CHAR cIn, CY* pcyOut) {
+   if (cIn < 0) pcyOut->u.Hi = -1;
+   else pcyOut->u.Hi = 0;
+   pcyOut->u.Lo = (ULONG)cIn * (ULONG)10000;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromUI232 [OLEAUT32.226]
+ * Convert unsigned short to currency
+ */
+HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
+   pcyOut->u.Hi = 0;
+   pcyOut->u.Lo = (ULONG)usIn * (ULONG)10000;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromUI432 [OLEAUT32.227]
+ * Convert unsigned long to currency
+ */
+HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
+   double t = (double)ulIn * (double)10000;
+   pcyOut->u.Hi = (LONG)(t / (double)4294967296.0);
+   pcyOut->u.Lo = (ULONG)fmod(t, (double)4294967296.0);
+      
+   return S_OK;
+}
+
+
+/**********************************************************************
+ *              DosDateTimeToVariantTime [OLEAUT32.14]
+ * Convert dos representation of time to the date and time representation
+ * stored in a variant.
+ */
+INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
+                                    DATE *pvtime)
+{
+    struct tm t;
+
+    TRACE("( 0x%x, 0x%x, 0x%p ), stub\n", wDosDate, wDosTime, pvtime );
+    
+    t.tm_sec = (wDosTime & 0x001f) * 2;
+    t.tm_min = (wDosTime & 0x07e0) >> 5;
+    t.tm_hour = (wDosTime & 0xf800) >> 11;
+    
+    t.tm_mday = (wDosDate & 0x001f);
+    t.tm_mon = (wDosDate & 0x01e0) >> 5;
+    t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
+
+    return TmToDATE( &t, pvtime );
+}
+
