Index: trunk/src/oleaut32/connpt.c
===================================================================
--- trunk/src/oleaut32/connpt.c	(revision 4837)
+++ trunk/src/oleaut32/connpt.c	(revision 4837)
@@ -0,0 +1,630 @@
+/*
+ * Implementation of a generic ConnectionPoint object.
+ *
+ * Copyright 2000 Huw D M Davies for CodeWeavers
+ *
+ * See one exported function here is CreateConnectionPoint, see
+ * comments just above that function for information.
+ */
+
+#ifdef __WIN32OS2__
+#define HAVE_FLOAT_H
+#define WINE_LARGE_INTEGER
+#include "oleaut32.h"
+#endif
+
+#include <assert.h>
+#include "winerror.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "ole2.h"
+#include "olectl.h"
+#include "wine/obj_base.h"
+#include "wine/obj_connection.h"
+#include "connpt.h"
+
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole);
+
+#define MAXSINKS 10
+
+/************************************************************************
+ * Implementation of IConnectionPoint
+ */
+typedef struct ConnectionPointImpl {
+
+  ICOM_VTABLE(IConnectionPoint)       *lpvtbl;
+
+  /* IUnknown of our main object*/
+  IUnknown *Obj;
+
+  /* Reference count */
+  DWORD ref;
+
+  /* IID of sink interface */
+  IID iid;
+
+  /* Array of sink IUnknowns */
+  IUnknown **sinks;
+  DWORD maxSinks;
+
+  DWORD nSinks;
+} ConnectionPointImpl;
+
+static ICOM_VTABLE(IConnectionPoint) ConnectionPointImpl_VTable;
+
+
+/************************************************************************
+ * Implementation of IEnumConnections
+ */
+typedef struct EnumConnectionsImpl {
+
+  ICOM_VTABLE(IEnumConnections)       *lpvtbl;
+
+  DWORD ref;
+
+  /* IUnknown of ConnectionPoint, used for ref counting */
+  IUnknown *pUnk;
+
+  /* Connection Data */
+  CONNECTDATA *pCD;
+  DWORD nConns;
+  
+  /* Next connection to enumerate from */
+  DWORD nCur;
+
+} EnumConnectionsImpl;
+
+static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
+							  DWORD nSinks,
+							  CONNECTDATA *pCD);
+
+
+/************************************************************************
+ * ConnectionPointImpl_Construct
+ */
+static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk,
+							  REFIID riid)
+{
+  ConnectionPointImpl *Obj;
+
+  Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
+  Obj->lpvtbl = &ConnectionPointImpl_VTable;
+  Obj->Obj = pUnk;
+  Obj->ref = 1;
+  Obj->iid =  *riid;
+  Obj->maxSinks = MAXSINKS;
+  Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
+			 sizeof(IUnknown*) * MAXSINKS);
+  Obj->nSinks = 0;
+  return Obj;
+}
+
+/************************************************************************
+ * ConnectionPointImpl_Destroy
+ */
+static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj)
+{
+  DWORD i;
+  for(i = 0; i < Obj->maxSinks; i++) {
+    if(Obj->sinks[i]) {
+      IUnknown_Release(Obj->sinks[i]);
+      Obj->sinks[i] = NULL;
+    }
+  }
+  HeapFree(GetProcessHeap(), 0, Obj->sinks);
+  HeapFree(GetProcessHeap(), 0, Obj);
+  return;
+}
+
+static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface);
+/************************************************************************
+ * ConnectionPointImpl_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI ConnectionPointImpl_QueryInterface(
+  IConnectionPoint*  iface,
+  REFIID  riid,
+  void**  ppvObject)
+{
+  ICOM_THIS(ConnectionPointImpl, iface);
+  TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==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 = (IConnectionPoint*)This;
+  }
+  else if (memcmp(&IID_IConnectionPoint, riid, sizeof(IID_IConnectionPoint)) == 0) 
+  {
+    *ppvObject = (IConnectionPoint*)This;
+  }
+  
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+  {
+    FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
+    return E_NOINTERFACE;
+  }
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  ConnectionPointImpl_AddRef((IConnectionPoint*)This);
+
+  return S_OK;;
+}
+
+
+/************************************************************************
+ * ConnectionPointImpl_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
+{
+  ICOM_THIS(ConnectionPointImpl, iface);
+  TRACE("(%p)->(ref=%ld)\n", This, This->ref);
+  This->ref++;
+
+  return This->ref;
+}
+        
+/************************************************************************
+ * ConnectionPointImpl_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI ConnectionPointImpl_Release( 
+      IConnectionPoint* iface)
+{
+  ICOM_THIS(ConnectionPointImpl, iface);
+  TRACE("(%p)->(ref=%ld)\n", This, This->ref);
+
+  /*
+   * Decrease the reference count on this object.
+   */
+  This->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (This->ref==0)
+  {
+    ConnectionPointImpl_Destroy(This);
+
+    return 0;
+  }
+  
+  return This->ref;
+}
+
+/************************************************************************
+ * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
+ *
+ */
+static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
+					       IConnectionPoint *iface,
+					       IID              *piid)
+{
+  ICOM_THIS(ConnectionPointImpl, iface);
+  TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid)));
+  *piid = This->iid;
+  return S_OK;
+}
+
+/************************************************************************
+ * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
+ *
+ */
+static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
+				      IConnectionPoint           *iface,
+				      IConnectionPointContainer  **ppCPC)
+{
+  ICOM_THIS(ConnectionPointImpl, iface);
+  TRACE("(%p)->(%p)\n", This, ppCPC);
+
+  return IUnknown_QueryInterface(This->Obj,
+				 &IID_IConnectionPointContainer,
+				 (LPVOID)ppCPC);
+}
+
+/************************************************************************
+ * ConnectionPointImpl_Advise (IConnectionPoint)
+ *
+ */
+static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
+						 IUnknown *lpUnk,
+						 DWORD *pdwCookie)
+{
+  DWORD i;
+  ICOM_THIS(ConnectionPointImpl, iface);
+  IUnknown *lpSink;
+  TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
+
+  *pdwCookie = 0;
+  if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink)))
+    return CONNECT_E_CANNOTCONNECT;
+
+  for(i = 0; i < This->maxSinks; i++) {
+    if(This->sinks[i] == NULL)
+      break;
+  }
+  if(i == This->maxSinks) {
+    This->maxSinks += MAXSINKS;
+    This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
+			      This->maxSinks * sizeof(IUnknown *));
+  }
+  This->sinks[i] = lpSink;
+  This->nSinks++;
+  *pdwCookie = i + 1;
+  return S_OK;
+}
+
+
+/************************************************************************
+ * ConnectionPointImpl_Unadvise (IConnectionPoint)
+ *
+ */
+static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
+						   DWORD dwCookie)
+{
+  ICOM_THIS(ConnectionPointImpl, iface);
+  TRACE("(%p)->(%ld)\n", This, dwCookie);
+
+  if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
+
+  if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
+
+  IUnknown_Release(This->sinks[dwCookie-1]);
+  This->sinks[dwCookie-1] = NULL;
+  This->nSinks--;
+  return S_OK;
+}
+
+/************************************************************************
+ * ConnectionPointImpl_EnumConnections (IConnectionPoint)
+ *
+ */
+static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
+						    IConnectionPoint *iface,
+						    LPENUMCONNECTIONS *ppEnum)
+{ 
+  ICOM_THIS(ConnectionPointImpl, iface);
+  CONNECTDATA *pCD;
+  DWORD i, nextslot;
+  EnumConnectionsImpl *EnumObj;
+  HRESULT hr;
+
+  TRACE("(%p)->(%p)\n", This, ppEnum);
+  
+  *ppEnum = NULL;
+
+  if(This->nSinks == 0) return OLE_E_NOCONNECTION;
+
+  pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
+
+  for(i = 0, nextslot = 0; i < This->maxSinks; i++) {
+    if(This->sinks[i] != NULL) {
+      pCD[nextslot].pUnk = This->sinks[i];
+      pCD[nextslot].dwCookie = i + 1;
+      nextslot++;
+    }
+  }
+  assert(nextslot == This->nSinks);
+
+  /* Bump the ref count of this object up by one.  It gets Released in
+     IEnumConnections_Release */
+  IUnknown_AddRef((IUnknown*)This);
+
+  EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD);
+  hr = IEnumConnections_QueryInterface((IEnumConnections*)EnumObj,
+				  &IID_IEnumConnections, (LPVOID)ppEnum);
+  IEnumConnections_Release((IEnumConnections*)EnumObj);
+
+  HeapFree(GetProcessHeap(), 0, pCD);
+  return hr;
+}
+
+static ICOM_VTABLE(IConnectionPoint) ConnectionPointImpl_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  ConnectionPointImpl_QueryInterface,
+  ConnectionPointImpl_AddRef,
+  ConnectionPointImpl_Release,
+  ConnectionPointImpl_GetConnectionInterface,
+  ConnectionPointImpl_GetConnectionPointContainer,
+  ConnectionPointImpl_Advise,
+  ConnectionPointImpl_Unadvise,
+  ConnectionPointImpl_EnumConnections
+};
+
+
+static ICOM_VTABLE(IEnumConnections) EnumConnectionsImpl_VTable;
+static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface);
+
+/************************************************************************
+ * EnumConnectionsImpl_Construct
+ */
+static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
+							  DWORD nSinks,
+							  CONNECTDATA *pCD)
+{
+  EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
+  DWORD i;
+
+  Obj->lpvtbl = &EnumConnectionsImpl_VTable;
+  Obj->ref = 1;
+  Obj->pUnk = pUnk;
+  Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA));
+  Obj->nConns = nSinks;
+  Obj->nCur = 0;
+
+  for(i = 0; i < nSinks; i++) {
+    Obj->pCD[i] = pCD[i];
+    IUnknown_AddRef(Obj->pCD[i].pUnk);
+  }
+  return Obj;
+}
+
+/************************************************************************
+ * EnumConnectionsImpl_Destroy
+ */
+static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
+{
+  DWORD i;
+
+  for(i = 0; i < Obj->nConns; i++)
+    IUnknown_Release(Obj->pCD[i].pUnk);
+
+  HeapFree(GetProcessHeap(), 0, Obj->pCD);
+  HeapFree(GetProcessHeap(), 0, Obj);
+  return;
+}
+
+/************************************************************************
+ * EnumConnectionsImpl_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
+  IEnumConnections*  iface,
+  REFIID  riid,
+  void**  ppvObject)
+{
+  ICOM_THIS(ConnectionPointImpl, iface);
+  TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==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 = (IEnumConnections*)This;
+  }
+  else if (memcmp(&IID_IEnumConnections, riid, sizeof(IID_IEnumConnections)) == 0) 
+  {
+    *ppvObject = (IEnumConnections*)This;
+  }
+  
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+  {
+    FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
+    return E_NOINTERFACE;
+  }
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  EnumConnectionsImpl_AddRef((IEnumConnections*)This);
+
+  return S_OK;;
+}
+
+
+/************************************************************************
+ * EnumConnectionsImpl_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface)
+{
+  ICOM_THIS(EnumConnectionsImpl, iface);
+  TRACE("(%p)->(ref=%ld)\n", This, This->ref);
+  This->ref++;
+  IUnknown_AddRef(This->pUnk);
+  return This->ref;
+}
+        
+/************************************************************************
+ * EnumConnectionsImpl_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
+{
+  ICOM_THIS(EnumConnectionsImpl, iface);
+  TRACE("(%p)->(ref=%ld)\n", This, This->ref);
+
+  IUnknown_Release(This->pUnk);
+
+  /*
+   * Decrease the reference count on this object.
+   */
+  This->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (This->ref==0)
+  {
+    EnumConnectionsImpl_Destroy(This);
+
+    return 0;
+  }
+  
+  return This->ref;
+}
+
+/************************************************************************
+ * EnumConnectionsImpl_Next (IEnumConnections)
+ *
+ */
+static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface,
+					       ULONG cConn, LPCONNECTDATA pCD,
+					       ULONG *pEnum)
+{
+  ICOM_THIS(EnumConnectionsImpl, iface);
+  DWORD nRet = 0;
+  TRACE("(%p)->(%ld, %p, %p)\n", This, cConn, pCD, pEnum);
+
+  if(pEnum == NULL) {
+    if(cConn != 1)
+      return E_POINTER;
+  } else
+    *pEnum = 0;
+
+  if(This->nCur >= This->nConns)
+    return S_FALSE;
+
+  while(This->nCur < This->nConns && cConn) {
+    *pCD++ = This->pCD[This->nCur];
+    IUnknown_AddRef(This->pCD[This->nCur].pUnk);
+    This->nCur++;
+    cConn--;
+    nRet++;
+  }
+
+  if(pEnum)
+    *pEnum = nRet;
+
+  return S_OK;
+}
+
+
+/************************************************************************
+ * EnumConnectionsImpl_Skip (IEnumConnections)
+ *
+ */
+static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface,
+					       ULONG cSkip)
+{
+  ICOM_THIS(EnumConnectionsImpl, iface);
+  TRACE("(%p)->(%ld)\n", This, cSkip);
+
+  if(This->nCur + cSkip >= This->nConns)
+    return S_FALSE;
+
+  This->nCur += cSkip;
+
+  return S_OK;
+}
+
+
+/************************************************************************
+ * EnumConnectionsImpl_Reset (IEnumConnections)
+ *
+ */
+static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface)
+{
+  ICOM_THIS(EnumConnectionsImpl, iface);
+  TRACE("(%p)\n", This);
+
+  This->nCur = 0;
+
+  return S_OK;
+}
+
+
+/************************************************************************
+ * EnumConnectionsImpl_Clone (IEnumConnections)
+ *
+ */
+static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface,
+						LPENUMCONNECTIONS *ppEnum)
+{
+  ICOM_THIS(EnumConnectionsImpl, iface);
+  EnumConnectionsImpl *newObj;
+  TRACE("(%p)->(%p)\n", This, ppEnum);
+  
+  newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD);
+  newObj->nCur = This->nCur;
+  *ppEnum = (LPENUMCONNECTIONS)newObj;
+  IUnknown_AddRef(This->pUnk);
+  return S_OK;
+}
+  
+static ICOM_VTABLE(IEnumConnections) EnumConnectionsImpl_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  EnumConnectionsImpl_QueryInterface,
+  EnumConnectionsImpl_AddRef,
+  EnumConnectionsImpl_Release,
+  EnumConnectionsImpl_Next,
+  EnumConnectionsImpl_Skip,
+  EnumConnectionsImpl_Reset,
+  EnumConnectionsImpl_Clone
+};
+
+/************************************************************************
+ *
+ *  The exported function to create the connection point.
+ *  NB not a windows API
+ *
+ * PARAMS
+ * pUnk [in] IUnknown of object to which the ConnectionPoint is associated.
+ *           Needed to access IConnectionPointContainer.
+ *
+ * riid [in] IID of sink interface that this ConnectionPoint manages
+ *
+ * pCP [out] returns IConnectionPoint
+ *
+ */
+HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid,
+			      IConnectionPoint **pCP)
+{
+  ConnectionPointImpl *Obj;
+  HRESULT hr;
+
+  Obj = ConnectionPointImpl_Construct(pUnk, riid);
+  if(!Obj) return E_OUTOFMEMORY;
+
+  hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj, 
+				       &IID_IConnectionPoint, (LPVOID)pCP);
+  IConnectionPoint_Release((IConnectionPoint *)Obj);
+  return hr;
+}
Index: trunk/src/oleaut32/connpt.h
===================================================================
--- trunk/src/oleaut32/connpt.h	(revision 4837)
+++ trunk/src/oleaut32/connpt.h	(revision 4837)
@@ -0,0 +1,6 @@
+#ifndef _CONNPT_H
+#define _CONNPT_H
+
+HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid, IConnectionPoint **pCP);
+
+#endif /* _CONNPT_H */
Index: trunk/src/oleaut32/dispatch.c
===================================================================
--- trunk/src/oleaut32/dispatch.c	(revision 4837)
+++ trunk/src/oleaut32/dispatch.c	(revision 4837)
@@ -0,0 +1,128 @@
+/**
+ * Dispatch API functions
+ *
+ * Copyright 2000  Francois Jacques, Macadamian Technologies Inc.
+ *
+ * ---
+ *
+ * TODO: Type coercion is implemented in variant.c but not called yet.
+ */
+#ifdef __WIN32OS2__
+#define HAVE_FLOAT_H
+#define WINE_LARGE_INTEGER
+#include "oleaut32.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "winerror.h"
+#include "winreg.h"         /* for HKEY_LOCAL_MACHINE */
+#include "winnls.h"         /* for PRIMARYLANGID */
+#include "ole.h"
+#include "heap.h"
+#include "wine/obj_oleaut.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole);
+DECLARE_DEBUG_CHANNEL(typelib);
+
+
+/******************************************************************************
+ *         DispInvoke    (OLEAUT32.30)
+ *
+ *
+ * Calls method of an object through its IDispatch interface.
+ *
+ * NOTES
+ * 		- Defer	method invocation to ITypeInfo::Invoke()
+ *
+ * RETURNS
+ *
+ * 		S_OK on success.
+ */
+HRESULT WINAPI
+DispInvoke(VOID*            _this,          /* object instance */
+           ITypeInfo*       ptinfo,         /* object's type info */
+           DISPID           dispidMember,   /* member id */
+           USHORT           wFlags,         /* kind of method call */
+           DISPPARAMS*      pparams,        /* array of arguments */
+           VARIANT*         pvarResult,     /* result of method call */
+           EXCEPINFO*       pexcepinfo,     /* information about exception */
+           UINT*            puArgErr        /* index of bad argument(if any) */
+          )
+{
+    HRESULT hr = E_FAIL;
+
+    /**
+     * TODO:
+     * For each param, call DispGetParam to perform type coercion
+     */
+    FIXME("Coercion of arguments not implemented\n");
+
+    hr = ICOM_CALL7(Invoke,
+                    ptinfo,
+                    _this,
+                    dispidMember,
+                    wFlags,
+                    pparams, pvarResult, pexcepinfo, puArgErr);
+
+    return (hr);
+}
+
+
+/******************************************************************************
+ *         DispGetIDsOfNames (OLEAUT32.29)
+ *
+ * Convert a set of names to dispids, based on information 
+ * contained in object's type library.
+ * 
+ * NOTES
+ * 		- Defers to ITypeInfo::GetIDsOfNames()
+ *
+ * RETURNS
+ *
+ * 		S_OK on success.
+ */
+HRESULT WINAPI
+DispGetIDsOfNames(ITypeInfo* ptinfo,
+                  OLECHAR**  rgszNames,
+                  UINT       cNames,
+                  DISPID*    rgdispid)
+{
+    HRESULT hr = E_FAIL;
+
+    hr = ICOM_CALL3(GetIDsOfNames,
+                    ptinfo,
+                    rgszNames,
+                    cNames,
+                    rgdispid);
+    return (hr);
+}
+
+/******************************************************************************
+ *         DispGetParam    (OLEAUT32.30)
+ *
+ * Retrive a parameter from a DISPPARAMS structures and coerce it to
+ * specified variant type
+ *
+ * NOTES
+ * 		Coercion is done using system (0) locale.
+ *
+ * RETURNS
+ *
+ * 		S_OK on success.
+ */
+HRESULT WINAPI DispGetParam(DISPPARAMS* pdispparams, UINT position,
+            VARTYPE vtTarg, VARIANT* pvarResult, UINT* puArgErr)
+{
+    HRESULT hr = E_FAIL;
+
+    /**
+     * TODO : Call VariantChangeTypeEx with LCID 0 (system)
+     */
+
+    FIXME("Coercion of arguments not implemented\n");
+    return (hr);
+}
Index: trunk/src/oleaut32/makefile
===================================================================
--- trunk/src/oleaut32/makefile	(revision 4830)
+++ trunk/src/oleaut32/makefile	(revision 4837)
@@ -1,3 +1,3 @@
-# $Id: makefile,v 1.21 2000-12-02 23:40:50 bird Exp $
+# $Id: makefile,v 1.22 2000-12-24 14:39:54 sandervl Exp $
 
 #
@@ -26,16 +26,19 @@
 $(OBJDIR)\ole2disp.obj \
 $(OBJDIR)\parsedt.obj \
-$(OBJDIR)\iPicture.obj \
-$(OBJDIR)\iPictureNone.obj \
-$(OBJDIR)\iPictureBmp.obj \
-$(OBJDIR)\iPictureMeta.obj \
-$(OBJDIR)\iPictureIcon.obj \
-$(OBJDIR)\iPictureEmf.obj \
+$(OBJDIR)\olepicture.obj \
+#$(OBJDIR)\iPicture.obj \
+#$(OBJDIR)\iPictureNone.obj \
+#$(OBJDIR)\iPictureBmp.obj \
+#$(OBJDIR)\iPictureMeta.obj \
+#$(OBJDIR)\iPictureIcon.obj \
+#$(OBJDIR)\iPictureEmf.obj \
 $(OBJDIR)\typelib.obj \
-$(OBJDIR)\itypelib.obj \
-$(OBJDIR)\itypecomp.obj \
-$(OBJDIR)\itypeinfo.obj \
+#$(OBJDIR)\itypelib.obj \
+#$(OBJDIR)\itypecomp.obj \
+#$(OBJDIR)\itypeinfo.obj \
 $(OBJDIR)\hash.obj \
 $(OBJDIR)\safearray.obj \
+$(OBJDIR)\connpt.obj \
+$(OBJDIR)\dispatch.obj \
 $(OBJDIR)\stubs.obj \
 $(OBJDIR)\oleaut32rsrc.obj
Index: trunk/src/oleaut32/ole2disp.c
===================================================================
--- trunk/src/oleaut32/ole2disp.c	(revision 4837)
+++ trunk/src/oleaut32/ole2disp.c	(revision 4837)
@@ -0,0 +1,549 @@
+/*
+ *	OLE2DISP library
+ *
+ *	Copyright 1995	Martin von Loewis
+ */
+#ifdef __WIN32OS2__
+#define HAVE_FLOAT_H
+#define WINE_LARGE_INTEGER
+#include "oleaut32.h"
+#endif
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "wine/windef16.h"
+#include "ole2.h"
+#include "olectl.h"
+#include "oleauto.h"
+#include "heap.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole);
+
+#ifndef __WIN32OS2__
+/* This implementation of the BSTR API is 16-bit only. It
+   represents BSTR as a 16:16 far pointer, and the strings
+   as ISO-8859 */
+
+/******************************************************************************
+ *		BSTR_AllocBytes	[Internal]
+ */
+static BSTR16 BSTR_AllocBytes(int n)
+{
+    void *ptr = SEGPTR_ALLOC(n);
+    return (BSTR16)SEGPTR_GET(ptr);
+}
+
+/******************************************************************************
+ * BSTR_Free [INTERNAL]
+ */
+static void BSTR_Free(BSTR16 in)
+{
+    SEGPTR_FREE( MapSL((SEGPTR)in) );
+}
+
+/******************************************************************************
+ * BSTR_GetAddr [INTERNAL]
+ */
+static void* BSTR_GetAddr(BSTR16 in)
+{
+    return in ? MapSL((SEGPTR)in) : 0;
+}
+
+/******************************************************************************
+ *		SysAllocString16	[OLE2DISP.2]
+ */
+BSTR16 WINAPI SysAllocString16(LPCOLESTR16 in)
+{
+	BSTR16 out;
+    
+	if (!in) return 0;
+    
+	out = BSTR_AllocBytes(strlen(in)+1);
+	if(!out)return 0;
+	strcpy(BSTR_GetAddr(out),in);
+	return out;
+}
+#endif
+
+/******************************************************************************
+ *		SysAllocString	[OLEAUT32.2]
+ */
+BSTR WINAPI SysAllocString(LPCOLESTR in)
+{
+    if (!in) return 0;
+    
+    /* Delegate this to the SysAllocStringLen32 method. */
+    return SysAllocStringLen(in, lstrlenW(in));
+}
+
+#ifndef __WIN32OS2__
+/******************************************************************************
+ *		SysReAllocString16	[OLE2DISP.3]
+ */
+INT16 WINAPI SysReAllocString16(LPBSTR16 old,LPCOLESTR16 in)
+{
+	BSTR16 new=SysAllocString16(in);
+	BSTR_Free(*old);
+	*old=new;
+	return 1;
+}
+#endif
+
+/******************************************************************************
+ *		SysReAllocString	[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;
+}
+
+#ifndef __WIN32OS2__
+/******************************************************************************
+ *		SysAllocStringLen16	[OLE2DISP.4]
+ */
+BSTR16 WINAPI SysAllocStringLen16(const char *in, int len)
+{
+	BSTR16 out=BSTR_AllocBytes(len+1);
+
+	if (!out)
+		return 0;
+
+    /*
+     * 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)
+	strcpy(BSTR_GetAddr(out),in);
+    else
+      memset(BSTR_GetAddr(out), 0, len+1);
+
+	return out;
+}
+#endif
+
+/******************************************************************************
+ *             SysAllocStringLen     [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 length 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 beginning 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;
+}
+
+#ifndef __WIN32OS2__
+/******************************************************************************
+ *		SysReAllocStringLen16	[OLE2DISP.5]
+ */
+int WINAPI SysReAllocStringLen16(BSTR16 *old,const char *in,int len)
+{
+	BSTR16 new=SysAllocStringLen16(in,len);
+	BSTR_Free(*old);
+	*old=new;
+	return 1;
+}
+#endif
+
+ 
+/******************************************************************************
+ *             SysReAllocStringLen   [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;
+}
+
+#ifndef __WIN32OS2__
+/******************************************************************************
+ *		SysFreeString16	[OLE2DISP.6]
+ */
+void WINAPI SysFreeString16(BSTR16 in)
+{
+	BSTR_Free(in);
+}
+#endif
+
+/******************************************************************************
+ *		SysFreeString	[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);
+}
+
+#ifndef __WIN32OS2__
+/******************************************************************************
+ *		SysStringLen16	[OLE2DISP.7]
+ */
+int WINAPI SysStringLen16(BSTR16 str)
+{
+	return strlen(BSTR_GetAddr(str));
+}
+#endif
+
+/******************************************************************************
+ *             SysStringLen  [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;
+
+     if (!str) return 0;
+    /*
+     * 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)
+{
+    DWORD* bufferPointer;
+
+     if (!str) return 0;
+    /*
+     * 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);
+}
+
+#ifndef __WIN32OS2__
+/******************************************************************************
+ * CreateDispTypeInfo16 [OLE2DISP.31]
+ */
+HRESULT WINAPI CreateDispTypeInfo16(
+	INTERFACEDATA *pidata,
+	LCID lcid,
+	ITypeInfo **pptinfo)
+{
+	FIXME("(%p,%ld,%p),stub\n",pidata,lcid,pptinfo);
+	return 0;
+}
+#endif
+
+/******************************************************************************
+ * CreateDispTypeInfo [OLE2DISP.31]
+ */
+HRESULT WINAPI CreateDispTypeInfo(
+	INTERFACEDATA *pidata,
+	LCID lcid,
+	ITypeInfo **pptinfo)
+{
+	FIXME("(%p,%ld,%p),stub\n",pidata,lcid,pptinfo);
+	return 0;
+}
+
+#ifndef __WIN32OS2__
+/******************************************************************************
+ * CreateStdDispatch16 [OLE2DISP.32]
+ */
+HRESULT WINAPI CreateStdDispatch16(
+        IUnknown* punkOuter,
+        void* pvThis,
+	ITypeInfo* ptinfo,
+	IUnknown** ppunkStdDisp)
+{
+	FIXME("(%p,%p,%p,%p),stub\n",punkOuter, pvThis, ptinfo,
+               ppunkStdDisp);
+	return 0;
+}
+#endif
+
+/******************************************************************************
+ * CreateStdDispatch [OLE2DISP.32]
+ */
+HRESULT WINAPI CreateStdDispatch(
+        IUnknown* punkOuter,
+        void* pvThis,
+	ITypeInfo* ptinfo,
+	IUnknown** ppunkStdDisp)
+{
+	FIXME("(%p,%p,%p,%p),stub\n",punkOuter, pvThis, ptinfo,
+               ppunkStdDisp);
+	return 0;
+}
+
+#ifndef __WIN32OS2__
+/******************************************************************************
+ * RegisterActiveObject [OLE2DISP.35]
+ */
+HRESULT WINAPI RegisterActiveObject16(
+	IUnknown *punk, REFCLSID rclsid, DWORD dwFlags, unsigned long *pdwRegister
+) {
+	FIXME("(%p,%s,0x%08lx,%p):stub\n",punk,debugstr_guid(rclsid),dwFlags,pdwRegister);
+	return 0;
+}
+#endif
+
+/******************************************************************************
+ *		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.
+ */
+HRESULT WINAPI OleTranslateColor(
+  OLE_COLOR 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(LPCSTR in, UINT 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/ole2disp.cpp
===================================================================
--- trunk/src/oleaut32/ole2disp.cpp	(revision 4830)
+++ 	(revision )
@@ -1,349 +1,0 @@
-/* $Id: ole2disp.cpp,v 1.4 2000-09-17 22:31:41 davidr Exp $ */
-/*
- *	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("OLEAUT32: OleTranslateColor(%08lx, %d, %p)\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 4830)
+++ trunk/src/oleaut32/oleaut32.cpp	(revision 4837)
@@ -1,3 +1,3 @@
-/* $Id: oleaut32.cpp,v 1.5 2000-01-02 21:29:58 davidr Exp $ */
+/* $Id: oleaut32.cpp,v 1.6 2000-12-24 14:39:54 sandervl Exp $ */
 /* 
  * OLEAUT32 
@@ -29,5 +29,5 @@
 void OpenPrivateLogFiles()
 {
-    OpenPrivateLogFileTypelib();
+//    OpenPrivateLogFileTypelib();
 }
 //******************************************************************************
@@ -36,6 +36,7 @@
 void ClosePrivateLogFiles()
 {
-    ClosePrivateLogFileTypelib();
+//    ClosePrivateLogFileTypelib();
 }
+
 
 /***********************************************************************
Index: trunk/src/oleaut32/oleaut32.h
===================================================================
--- trunk/src/oleaut32/oleaut32.h	(revision 4830)
+++ trunk/src/oleaut32/oleaut32.h	(revision 4837)
@@ -1,3 +1,3 @@
-/* $Id: oleaut32.h,v 1.8 2000-01-26 11:26:05 sandervl Exp $ */
+/* $Id: oleaut32.h,v 1.9 2000-12-24 14:39:54 sandervl Exp $ */
 /*
  * Win32 OLE stubs for OS/2
@@ -32,5 +32,4 @@
 #undef CALLCONV
 
-#include <os2win.h>
 #include <ole2ver.h>
 #include <ole.h>
@@ -51,4 +50,5 @@
 
 #include <heapstring.h>
+#include <misc.h>
 
 extern int 	loadNr;
Index: trunk/src/oleaut32/olefont.c
===================================================================
--- trunk/src/oleaut32/olefont.c	(revision 4837)
+++ trunk/src/oleaut32/olefont.c	(revision 4837)
@@ -0,0 +1,1594 @@
+/*
+ * OLE Font encapsulation implementation
+ *
+ * This file contains an implementation of the IFont
+ * interface and the OleCreateFontIndirect API call.
+ *
+ * Copyright 1999 Francis Beaudet
+ */
+#ifdef __WIN32OS2__
+#define WINE_LARGE_INTEGER
+#include "oleaut32.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include "winerror.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "wine/unicode.h"
+#include "oleauto.h"    /* for SysAllocString(....) */
+#include "wine/obj_olefont.h"
+#include "wine/obj_storage.h"
+#include "ole2.h"
+#include "olectl.h"
+#include "debugtools.h"
+#include "heap.h"
+#include "connpt.h" /* for CreateConnectionPoint */
+
+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 IPersistStream and IConnectionPointContainer.
+   * The first two are supported by the first vtable, the next two are
+   * supported by the second table and the last two have their own.
+   */
+  ICOM_VTABLE(IFont)*     lpvtbl1;
+  ICOM_VTABLE(IDispatch)* lpvtbl2;
+  ICOM_VTABLE(IPersistStream)*            lpvtbl3;
+  ICOM_VTABLE(IConnectionPointContainer)* lpvtbl4;
+  /*
+   * 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;
+
+  IConnectionPoint *pCP;
+};
+
+/*
+ * Here, I define utility macros to help with the casting of the 
+ * "this" parameter.
+ * There is a version to accomodate all of the VTables implemented
+ * by this object.
+ */
+#define _ICOM_THIS(class,name) class* this = (class*)name;
+#define _ICOM_THIS_From_IDispatch(class, name) class* this = (class*)(((char*)name)-sizeof(void*)); 
+#define _ICOM_THIS_From_IPersistStream(class, name) class* this = (class*)(((char*)name)-2*sizeof(void*)); 
+#define _ICOM_THIS_From_IConnectionPointContainer(class, name) class* this = (class*)(((char*)name)-3*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); 
+
+/***********************************************************************
+ * Prototypes for the implementation functions for the
+ * IConnectionPointContainer interface
+ */
+static HRESULT WINAPI OLEFontImpl_IConnectionPointContainer_QueryInterface(
+					    IConnectionPointContainer* iface, 
+					    REFIID     riid, 
+					    VOID**     ppvoid);
+static ULONG   WINAPI OLEFontImpl_IConnectionPointContainer_AddRef(
+					    IConnectionPointContainer* iface);
+static ULONG   WINAPI OLEFontImpl_IConnectionPointContainer_Release(
+					    IConnectionPointContainer* iface);
+static HRESULT WINAPI OLEFontImpl_EnumConnectionPoints(
+					    IConnectionPointContainer* iface,
+					    IEnumConnectionPoints **ppEnum);
+static HRESULT WINAPI OLEFontImpl_FindConnectionPoint(
+					    IConnectionPointContainer* iface,
+					    REFIID riid,
+					    IConnectionPoint **ppCp);
+
+/*
+ * 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
+};
+
+static ICOM_VTABLE(IConnectionPointContainer)
+     OLEFontImpl_IConnectionPointContainer_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  OLEFontImpl_IConnectionPointContainer_QueryInterface,
+  OLEFontImpl_IConnectionPointContainer_AddRef,
+  OLEFontImpl_IConnectionPointContainer_Release,
+  OLEFontImpl_EnumConnectionPoints,
+  OLEFontImpl_FindConnectionPoint
+};
+
+/******************************************************************************
+ *		OleCreateFontIndirect	[OLEAUT32.420]
+ */
+HRESULT WINAPI OleCreateFontIndirect(
+  LPFONTDESC lpFontDesc,
+  REFIID     riid,
+  LPVOID*     ppvObj)
+{
+  OLEFontImpl* newFont = 0;
+  HRESULT      hr      = S_OK;
+
+  TRACE("(%p, %s, %p)\n", lpFontDesc, debugstr_guid(riid), ppvObj);
+  /*
+   * 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.
+ */
+
+/***********************************************************************
+ *    OLEFont_SendNotify (internal)
+ *
+ * Sends notification messages of changed properties to any interested
+ * connections.
+ */
+static void OLEFont_SendNotify(OLEFontImpl* this, DISPID dispID)
+{
+  IEnumConnections *pEnum;
+  CONNECTDATA CD;
+
+  IConnectionPoint_EnumConnections(this->pCP, &pEnum);
+  
+  while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
+    IPropertyNotifySink *sink;
+
+    IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
+    IPropertyNotifySink_OnChanged(sink, dispID);
+    IPropertyNotifySink_Release(sink);
+    IUnknown_Release(CD.pUnk);
+  }
+  IEnumConnections_Release(pEnum);
+  return;
+}
+  
+/************************************************************************
+ * 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 = 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;
+  newObject->lpvtbl4 = &OLEFontImpl_IConnectionPointContainer_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 = HeapAlloc(GetProcessHeap(),
+					       0, 
+					       (lstrlenW(fontDesc->lpstrName)+1) * sizeof(WCHAR));
+  strcpyW(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;
+
+  CreateConnectionPoint((IUnknown*)newObject, &IID_IPropertyNotifySink, &newObject->pCP);
+
+  TRACE("returning %p\n", newObject);
+  return newObject;
+}
+
+/************************************************************************
+ * OLEFontImpl_Destroy
+ *
+ * This method is called by the Release method when the reference
+ * count goes down to 0. It will free all resources used by
+ * this object.
+ */
+static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc)
+{
+  TRACE("(%p)\n", 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);
+  TRACE("(%p)->(%s, %p)\n", this, debugstr_guid(riid), ppvObject);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (this==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*)this;
+  }
+  else if (memcmp(&IID_IFont, riid, sizeof(IID_IFont)) == 0) 
+  {
+    *ppvObject = (IFont*)this;
+  }
+  else if (memcmp(&IID_IDispatch, riid, sizeof(IID_IDispatch)) == 0) 
+  {
+    *ppvObject = (IDispatch*)&(this->lpvtbl2);
+  }
+  else if (memcmp(&IID_IFontDisp, riid, sizeof(IID_IFontDisp)) == 0) 
+  {
+    *ppvObject = (IDispatch*)&(this->lpvtbl2);
+  }
+  else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0) 
+  {
+    *ppvObject = (IPersistStream*)&(this->lpvtbl3);
+  }
+  else if (memcmp(&IID_IConnectionPointContainer, riid,
+		  sizeof(IID_IConnectionPointContainer)) == 0) 
+  {
+    *ppvObject = (IPersistStream*)&(this->lpvtbl4);
+  }
+  
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+  {
+    FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
+    return E_NOINTERFACE;
+  }
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  OLEFontImpl_AddRef((IFont*)this);
+
+  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);
+  TRACE("(%p)->(ref=%ld)\n", this, this->ref);
+  this->ref++;
+
+  return this->ref;
+}
+        
+/************************************************************************
+ * OLEFontImpl_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+ULONG WINAPI OLEFontImpl_Release( 
+      IFont* iface)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+  TRACE("(%p)->(ref=%ld)\n", this, this->ref);
+
+  /*
+   * Decrease the reference count on this object.
+   */
+  this->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (this->ref==0)
+  {
+    OLEFontImpl_Destroy(this);
+
+    return 0;
+  }
+  
+  return this->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);
+  TRACE("(%p)->(%p)\n", this, pname);
+  /*
+   * Sanity check.
+   */
+  if (pname==0)
+    return E_POINTER;
+
+  if (this->description.lpstrName!=0)
+    *pname = SysAllocString(this->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);
+  TRACE("(%p)->(%p)\n", this, name);
+
+  if (this->description.lpstrName==0)
+  {
+    this->description.lpstrName = HeapAlloc(GetProcessHeap(),
+					    0, 
+					    (lstrlenW(name)+1) * sizeof(WCHAR));
+  }
+  else
+  {
+    this->description.lpstrName = HeapReAlloc(GetProcessHeap(),
+					      0, 
+					      this->description.lpstrName,
+					      (lstrlenW(name)+1) * sizeof(WCHAR));
+  }
+
+  if (this->description.lpstrName==0)
+    return E_OUTOFMEMORY;
+
+  strcpyW(this->description.lpstrName, name);
+  TRACE("new name %s\n", debugstr_w(this->description.lpstrName));
+  OLEFont_SendNotify(this, DISPID_FONT_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);
+  TRACE("(%p)->(%p)\n", this, psize);
+
+  /*
+   * Sanity check
+   */
+  if (psize==0)
+    return E_POINTER;
+
+  psize->s.Hi = 0;
+  psize->s.Lo = this->description.cySize.s.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);
+  TRACE("(%p)->(%ld)\n", this, size.s.Lo);
+  this->description.cySize.s.Hi = 0;
+  this->description.cySize.s.Lo = size.s.Lo;
+  OLEFont_SendNotify(this, DISPID_FONT_SIZE);
+
+  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)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+  TRACE("(%p)->(%p)\n", this, pbold);
+  /*
+   * Sanity check
+   */
+  if (pbold==0)
+    return E_POINTER;
+
+  *pbold = this->description.sWeight > 550;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_put_Bold (IFont)
+ *
+ * See Windows documentation for more details on IFont methods.
+ */
+static HRESULT WINAPI OLEFontImpl_put_Bold(
+  IFont* iface,
+  BOOL bold)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+  TRACE("(%p)->(%d)\n", this, bold);
+  this->description.sWeight = bold ? FW_BOLD : FW_NORMAL;
+  OLEFont_SendNotify(this, DISPID_FONT_BOLD);
+
+  return S_OK;
+}
+
+/************************************************************************
+ * 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);
+  TRACE("(%p)->(%p)\n", this, pitalic);
+  /*
+   * Sanity check
+   */
+  if (pitalic==0)
+    return E_POINTER;
+
+  *pitalic = this->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);
+  TRACE("(%p)->(%d)\n", this, italic);
+
+  this->description.fItalic = italic;
+
+  OLEFont_SendNotify(this, DISPID_FONT_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);
+  TRACE("(%p)->(%p)\n", this, punderline);
+
+  /*
+   * Sanity check
+   */
+  if (punderline==0)
+    return E_POINTER;
+
+  *punderline = this->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);
+  TRACE("(%p)->(%d)\n", this, underline);
+
+  this->description.fUnderline = underline;
+
+  OLEFont_SendNotify(this, DISPID_FONT_UNDER);
+  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);
+  TRACE("(%p)->(%p)\n", this, pstrikethrough);
+
+  /*
+   * Sanity check
+   */
+  if (pstrikethrough==0)
+    return E_POINTER;
+
+  *pstrikethrough = this->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);
+  TRACE("(%p)->(%d)\n", this, strikethrough);
+
+  this->description.fStrikethrough = strikethrough;
+  OLEFont_SendNotify(this, DISPID_FONT_STRIKE);
+
+  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);
+  TRACE("(%p)->(%p)\n", this, pweight);
+
+  /*
+   * Sanity check
+   */
+  if (pweight==0)
+    return E_POINTER;
+
+  *pweight = this->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);
+  TRACE("(%p)->(%d)\n", this, weight);
+
+  this->description.sWeight = weight;
+
+  OLEFont_SendNotify(this, DISPID_FONT_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);
+  TRACE("(%p)->(%p)\n", this, pcharset);
+
+  /*
+   * Sanity check
+   */
+  if (pcharset==0)
+    return E_POINTER;
+
+  *pcharset = this->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);
+  TRACE("(%p)->(%d)\n", this, charset);
+
+  this->description.sCharset = charset;
+  OLEFont_SendNotify(this, DISPID_FONT_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);
+  TRACE("(%p)->(%p)\n", this, phfont);
+  if (phfont==NULL)
+    return E_POINTER;
+
+  /*
+   * Realize the font if necessary
+ */
+  if (this->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.s.Lo, 2540L, 72L);
+    fontHeight = MulDiv(fontHeight, this->cyLogical,this->cyHimetric);
+
+    memset(&logFont, 0, sizeof(LOGFONTW));
+
+    logFont.lfHeight          = ((fontHeight%10000L)>5000L) ? (-fontHeight/10000L)-1 :
+                                                              (-fontHeight/10000L);
+    logFont.lfItalic          = this->description.fItalic;
+    logFont.lfUnderline       = this->description.fUnderline;
+    logFont.lfStrikeOut       = this->description.fStrikethrough;
+    logFont.lfWeight          = this->description.sWeight;
+    logFont.lfCharSet         = this->description.sCharset;
+    logFont.lfOutPrecision    = OUT_CHARACTER_PRECIS;
+    logFont.lfClipPrecision   = CLIP_DEFAULT_PRECIS;
+    logFont.lfQuality         = DEFAULT_QUALITY;
+    logFont.lfPitchAndFamily  = DEFAULT_PITCH;
+    strcpyW(logFont.lfFaceName,this->description.lpstrName);
+
+    this->gdiFont = CreateFontIndirectW(&logFont);
+  }
+
+  *phfont = this->gdiFont;
+  TRACE("Returning %08x\n", *phfont);
+  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);
+  TRACE("(%p)->(%p)\n", this, ppfont);
+
+  if (ppfont == NULL)
+    return E_POINTER;
+
+  *ppfont = NULL;
+
+  /*
+   * Allocate space for the object.
+   */
+  newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl));
+
+  if (newObject==NULL)
+    return E_OUTOFMEMORY;
+
+  *newObject = *this;
+
+  /*
+   * 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);
+  TRACE("(%p)->(%ld, %ld)\n", this, cyLogical, cyHimetric);
+
+  this->cyLogical  = cyLogical;
+  this->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);
+  TRACE("(%p)->(%08x) (lock=%ld)\n", this, hfont, this->fontLock);
+
+  if ( (hfont == 0) ||
+       (hfont != this->gdiFont) )
+    return E_INVALIDARG;
+
+  this->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);
+  TRACE("(%p)->(%08x) (lock=%ld)\n", this, hfont, this->fontLock);
+
+  if ( (hfont == 0) ||
+       (hfont != this->gdiFont) )
+    return E_INVALIDARG;
+
+  this->fontLock--;
+
+  /*
+   * If we just released our last font reference, destroy it.
+   */
+  if (this->fontLock==0)
+  {
+    DeleteObject(this->gdiFont);
+    this->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)
+{
+  _ICOM_THIS(OLEFontImpl, iface);
+  FIXME("(%p)->(%08x): Stub\n", this, hdc);
+  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(this, 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(this);
+}
+
+/************************************************************************
+ * 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(this);
+}
+
+/************************************************************************
+ * OLEFontImpl_GetTypeInfoCount (IDispatch)
+ *
+ * See Windows documentation for more details on IDispatch methods.
+ */
+static HRESULT WINAPI OLEFontImpl_GetTypeInfoCount(
+  IDispatch*    iface, 
+  unsigned int* pctinfo)
+{
+  _ICOM_THIS_From_IDispatch(IFont, iface);
+  FIXME("(%p)->(%p): Stub\n", this, pctinfo);
+
+  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)
+{
+  _ICOM_THIS_From_IDispatch(IFont, iface);
+  FIXME("(%p):Stub\n", this);
+
+  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)
+{
+  _ICOM_THIS_From_IDispatch(IFont, iface);
+  FIXME("(%p):Stub\n", this);
+
+  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)
+{
+  _ICOM_THIS_From_IDispatch(IFont, iface);
+  FIXME("(%p):Stub\n", this);
+
+  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(this, 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(this);
+}
+
+/************************************************************************
+ * 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(this);
+}
+
+/************************************************************************
+ * 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, &this->description.sCharset, 2, &cbRead);
+
+  if (cbRead!=2)
+    return E_FAIL;
+
+  /*
+   * Attributes
+   */
+  IStream_Read(pLoadStream, &bAttributes, 1, &cbRead);
+
+  if (cbRead!=1)
+    return E_FAIL;
+
+  this->description.fItalic        = (bAttributes & FONTPERSIST_ITALIC) != 0;
+  this->description.fStrikethrough = (bAttributes & FONTPERSIST_STRIKETHROUGH) != 0;
+  this->description.fUnderline     = (bAttributes & FONTPERSIST_UNDERLINE) != 0;
+    
+  /*
+   * Weight
+   */
+  IStream_Read(pLoadStream, &this->description.sWeight, 2, &cbRead);
+
+  if (cbRead!=2)
+    return E_FAIL;
+
+  /*
+   * Size
+   */
+  IStream_Read(pLoadStream, &this->description.cySize.s.Lo, 4, &cbRead);
+
+  if (cbRead!=4)
+    return E_FAIL;
+
+  this->description.cySize.s.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 (this->description.lpstrName!=0)
+    HeapFree(GetProcessHeap(), 0, this->description.lpstrName);
+
+  this->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, &this->description.sCharset, 2, &cbWritten);
+
+  if (cbWritten!=2)
+    return E_FAIL;
+
+  /*
+   * Attributes
+   */
+  bAttributes = 0;
+
+  if (this->description.fItalic)
+    bAttributes |= FONTPERSIST_ITALIC;
+
+  if (this->description.fStrikethrough)
+    bAttributes |= FONTPERSIST_STRIKETHROUGH;
+  
+  if (this->description.fUnderline)
+    bAttributes |= FONTPERSIST_UNDERLINE;
+
+  IStream_Write(pOutStream, &bAttributes, 1, &cbWritten);
+
+  if (cbWritten!=1)
+    return E_FAIL;
+  
+  /*
+   * Weight
+   */
+  IStream_Write(pOutStream, &this->description.sWeight, 2, &cbWritten);
+
+  if (cbWritten!=2)
+    return E_FAIL;
+
+  /*
+   * Size
+   */
+  IStream_Write(pOutStream, &this->description.cySize.s.Lo, 4, &cbWritten);
+
+  if (cbWritten!=4)
+    return E_FAIL;
+
+  /*
+   * FontName
+   */
+  if (this->description.lpstrName!=0)
+    bStringSize = lstrlenW(this->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,
+				  this->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->s.HighPart = 0;
+  pcbSize->s.LowPart = 0;
+
+  pcbSize->s.LowPart += sizeof(BYTE);  /* Version */
+  pcbSize->s.LowPart += sizeof(WORD);  /* Lang code */
+  pcbSize->s.LowPart += sizeof(BYTE);  /* Flags */
+  pcbSize->s.LowPart += sizeof(WORD);  /* Weight */
+  pcbSize->s.LowPart += sizeof(DWORD); /* Size */
+  pcbSize->s.LowPart += sizeof(BYTE);  /* StrLength */
+
+  if (this->description.lpstrName!=0)
+    pcbSize->s.LowPart += lstrlenW(this->description.lpstrName);
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEFontImpl_IConnectionPointContainer_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI OLEFontImpl_IConnectionPointContainer_QueryInterface(
+  IConnectionPointContainer* iface,
+  REFIID     riid,
+  VOID**     ppvoid)
+{
+  _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface);
+
+  return IFont_QueryInterface((IFont*)this, riid, ppvoid);
+}
+
+/************************************************************************
+ * OLEFontImpl_IConnectionPointContainer_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_Release(
+  IConnectionPointContainer* iface)
+{
+  _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface);
+
+  return IFont_Release((IFont*)this);
+}
+
+/************************************************************************
+ * OLEFontImpl_IConnectionPointContainer_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_AddRef(
+  IConnectionPointContainer* iface)
+{
+  _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface);
+
+  return IFont_AddRef((IFont*)this);
+}
+
+/************************************************************************
+ * OLEFontImpl_EnumConnectionPoints (IConnectionPointContainer)
+ *
+ * See Windows documentation for more details on IConnectionPointContainer
+ * methods.
+ */
+static HRESULT WINAPI OLEFontImpl_EnumConnectionPoints(
+  IConnectionPointContainer* iface,
+  IEnumConnectionPoints **ppEnum)
+{
+  _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface);
+
+  FIXME("(%p)->(%p): stub\n", this, ppEnum);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEFontImpl_FindConnectionPoint (IConnectionPointContainer)
+ *
+ * See Windows documentation for more details on IConnectionPointContainer
+ * methods.
+ */
+static HRESULT WINAPI OLEFontImpl_FindConnectionPoint(
+   IConnectionPointContainer* iface,
+   REFIID riid,
+   IConnectionPoint **ppCp)
+{
+  _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface);
+  TRACE("(%p)->(%s, %p): stub\n", this, debugstr_guid(riid), ppCp);
+
+  if(memcmp(riid, &IID_IPropertyNotifySink, sizeof(IID_IPropertyNotifySink)) == 0) {
+    return IConnectionPoint_QueryInterface(this->pCP, &IID_IConnectionPoint,
+					   (LPVOID)ppCp);
+  } else {
+    FIXME("Tried to find connection point on %s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+  }
+}
+
Index: trunk/src/oleaut32/olefont.cpp
===================================================================
--- trunk/src/oleaut32/olefont.cpp	(revision 4830)
+++ 	(revision )
@@ -1,1401 +1,0 @@
-/* $Id: olefont.cpp,v 1.3 1999-11-18 00:27:36 davidr Exp $ */
-/*
- * 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(
-	 "OLEAUT32: IFont->QueryInterface(%s) : unsupported interface requested!",
-	 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/olepicture.c
===================================================================
--- trunk/src/oleaut32/olepicture.c	(revision 4837)
+++ trunk/src/oleaut32/olepicture.c	(revision 4837)
@@ -0,0 +1,788 @@
+/*
+ * OLE Picture object
+ *
+ * Implementation of OLE IPicture and related interfaces
+ *
+ * Copyright 2000 Huw D M Davies for CodeWeavers.
+ *
+ *
+ * BUGS
+ *
+ * Only implements PICTYPE_BITMAP.
+ * Most methods are just stubs.
+ * Doesn't even expose IPersistStream, IConnectionPointContainer.
+ *
+ *
+ * NOTES (or things that msdn doesn't tell you)
+ *
+ * The width and height properties are returned in HIMETRIC units (0.01mm)
+ * IPicture::Render also uses these to select a region of the src picture.
+ * A bitmap's size is converted into these units by using the screen resolution
+ * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
+ *
+ */
+#ifdef __WIN32OS2__
+#define HAVE_FLOAT_H
+#define WINE_LARGE_INTEGER
+#include "oleaut32.h"
+#endif
+
+#include "winerror.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "ole2.h"
+#include "olectl.h"
+#include "wine/obj_picture.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole);
+
+/*************************************************************************
+ *  Declaration of implementation class
+ */
+
+typedef struct OLEPictureImpl {
+
+  /*
+   * IPicture handles IUnknown
+   */
+
+    ICOM_VTABLE(IPicture)       *lpvtbl1;
+    ICOM_VTABLE(IDispatch)      *lpvtbl2;
+    ICOM_VTABLE(IPersistStream) *lpvtbl3;
+
+  /* Object referenece count */
+    DWORD ref;
+
+  /* We own the object and must destroy it ourselves */
+    BOOL fOwn;
+  
+  /* Picture description */
+    PICTDESC desc;
+
+  /* These are the pixel size of a bitmap */
+    DWORD origWidth;
+    DWORD origHeight;
+
+  /* And these are the size of the picture converted into HIMETRIC units */
+    OLE_XSIZE_HIMETRIC himetricWidth;
+    OLE_YSIZE_HIMETRIC himetricHeight;
+
+} OLEPictureImpl;
+
+/*
+ * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
+ */
+#define ICOM_THIS_From_IDispatch(impl, name) \
+    impl *This = (impl*)(((char*)name)-sizeof(void*));
+
+#define ICOM_THIS_From_IPersistStream(impl, name) \
+    impl *This = (impl*)(((char*)name)-2*sizeof(void*));
+
+/*
+ * Predeclare VTables.  They get initialized at the end.
+ */
+static ICOM_VTABLE(IPicture) OLEPictureImpl_VTable;
+static ICOM_VTABLE(IDispatch) OLEPictureImpl_IDispatch_VTable;
+static ICOM_VTABLE(IPersistStream) OLEPictureImpl_IPersistStream_VTable;
+
+/***********************************************************************
+ * Implementation of the OLEPictureImpl class.
+ */
+
+/************************************************************************
+ * OLEPictureImpl_Construct
+ *
+ * This method will construct a new instance of the OLEPictureImpl
+ * class.
+ *
+ * The caller of this method must release the object when it's
+ * done with it.
+ */
+static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
+{
+  OLEPictureImpl* newObject = 0;
+  TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
+
+  /*
+   * Allocate space for the object.
+   */
+  newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEPictureImpl));
+
+  if (newObject==0)
+    return newObject;
+  
+  /*
+   * Initialize the virtual function table.
+   */
+  newObject->lpvtbl1 = &OLEPictureImpl_VTable;
+  newObject->lpvtbl2 = &OLEPictureImpl_IDispatch_VTable;
+  newObject->lpvtbl3 = &OLEPictureImpl_IPersistStream_VTable;
+  
+  /*
+   * Start with one reference count. The caller of this function 
+   * must release the interface pointer when it is done.
+   */
+  newObject->ref = 1;
+
+  newObject->fOwn = fOwn;
+
+  if(pictDesc->cbSizeofstruct != sizeof(PICTDESC)) {
+      FIXME("struct size = %d\n", pictDesc->cbSizeofstruct);
+  }
+  memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC));
+
+  switch(pictDesc->picType) {
+  case PICTYPE_BITMAP:
+    {
+      BITMAP bm;
+      HDC hdcRef;
+
+      TRACE("bitmap handle %08x\n", pictDesc->u.bmp.hbitmap);
+      if(GetObjectA(pictDesc->u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
+	ERR("GetObject fails\n");
+	break;
+      }
+
+      newObject->origWidth = bm.bmWidth;
+      newObject->origHeight = bm.bmHeight;
+
+      /* The width and height are stored in HIMETRIC units (0.01 mm),
+	 so we take our pixel width divide by pixels per inch and
+	 multiply by 25.4 * 100 */
+
+      /* Should we use GetBitmapDimension if available? */
+
+      hdcRef = CreateCompatibleDC(0);
+
+      newObject->himetricWidth = (bm.bmWidth * 2540) /
+	GetDeviceCaps(hdcRef, LOGPIXELSX);
+      newObject->himetricHeight = (bm.bmHeight * 2540) / 
+	GetDeviceCaps(hdcRef, LOGPIXELSY);
+      DeleteDC(hdcRef);
+    }
+    break;
+
+  case PICTYPE_METAFILE:
+    TRACE("metafile handle %08x\n", pictDesc->u.wmf.hmeta);
+    newObject->himetricWidth = pictDesc->u.wmf.xExt;
+    newObject->himetricHeight = pictDesc->u.wmf.yExt;
+    break;
+
+  case PICTYPE_ICON:
+  case PICTYPE_ENHMETAFILE:
+  default:
+    FIXME("Unsupported type %d\n", pictDesc->picType);
+    newObject->himetricWidth = newObject->himetricHeight = 0;
+    break;
+  }
+    
+  TRACE("returning %p\n", newObject);
+  return newObject;
+}
+
+/************************************************************************
+ * OLEPictureImpl_Destroy
+ *
+ * This method is called by the Release method when the reference
+ * count goes down to 0. It will free all resources used by
+ * this object.  */
+static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
+{ 
+  TRACE("(%p)\n", Obj);
+
+  if(Obj->fOwn) { /* We need to destroy the picture */
+    switch(Obj->desc.picType) {
+    case PICTYPE_BITMAP:
+      DeleteObject(Obj->desc.u.bmp.hbitmap);
+      break;
+    case PICTYPE_METAFILE:
+      DeleteMetaFile(Obj->desc.u.wmf.hmeta);
+      break;
+    case PICTYPE_ICON:
+      DestroyIcon(Obj->desc.u.icon.hicon);
+      break;
+    case PICTYPE_ENHMETAFILE:
+      DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
+      break;
+    default:
+      FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
+      break;
+    }
+  }
+  HeapFree(GetProcessHeap(), 0, Obj);
+}
+
+static ULONG WINAPI OLEPictureImpl_AddRef(IPicture* iface);
+
+/************************************************************************
+ * OLEPictureImpl_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI OLEPictureImpl_QueryInterface(
+  IPicture*  iface,
+  REFIID  riid,
+  void**  ppvObject)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==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 = (IPicture*)This;
+  }
+  else if (memcmp(&IID_IPicture, riid, sizeof(IID_IPicture)) == 0) 
+  {
+    *ppvObject = (IPicture*)This;
+  }
+  else if (memcmp(&IID_IDispatch, riid, sizeof(IID_IDispatch)) == 0) 
+  {
+    *ppvObject = (IDispatch*)&(This->lpvtbl2);
+  }
+  else if (memcmp(&IID_IPictureDisp, riid, sizeof(IID_IPictureDisp)) == 0) 
+  {
+    *ppvObject = (IDispatch*)&(This->lpvtbl2);
+  }
+  /*  else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0) 
+  {
+  *ppvObject = (IPersistStream*)&(This->lpvtbl3);
+  }*/
+  
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+  {
+    FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
+    return E_NOINTERFACE;
+  }
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  OLEPictureImpl_AddRef((IPicture*)This);
+
+  return S_OK;;
+}
+        
+/************************************************************************
+ * OLEPictureImpl_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEPictureImpl_AddRef( 
+  IPicture* iface)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  TRACE("(%p)->(ref=%ld)\n", This, This->ref);
+  This->ref++;
+
+  return This->ref;
+}
+        
+/************************************************************************
+ * OLEPictureImpl_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEPictureImpl_Release( 
+      IPicture* iface)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  TRACE("(%p)->(ref=%ld)\n", This, This->ref);
+
+  /*
+   * Decrease the reference count on this object.
+   */
+  This->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (This->ref==0)
+  {
+    OLEPictureImpl_Destroy(This);
+
+    return 0;
+  }
+  
+  return This->ref;
+}
+
+
+/************************************************************************
+ * OLEPictureImpl_get_Handle
+ */ 
+static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
+						OLE_HANDLE *phandle)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  TRACE("(%p)->(%p)\n", This, phandle);
+  switch(This->desc.picType) {
+  case PICTYPE_BITMAP:
+    *phandle = This->desc.u.bmp.hbitmap;
+    break;
+  case PICTYPE_METAFILE:
+    *phandle = This->desc.u.wmf.hmeta;
+    break;
+  case PICTYPE_ICON:
+    *phandle = This->desc.u.icon.hicon;
+    break;
+  case PICTYPE_ENHMETAFILE:
+    *phandle = This->desc.u.emf.hemf;
+    break;
+  default:
+    FIXME("Unimplemented type %d\n", This->desc.picType);
+    return E_NOTIMPL;
+  }
+  TRACE("returning handle %08x\n", *phandle);
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEPictureImpl_get_hPal
+ */ 
+static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
+					      OLE_HANDLE *phandle)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  FIXME("(%p)->(%p): stub\n", This, phandle);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_get_Type
+ */ 
+static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
+					      short *ptype)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
+  *ptype = This->desc.picType;
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEPictureImpl_get_Width
+ */ 
+static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
+					       OLE_XSIZE_HIMETRIC *pwidth)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  TRACE("(%p)->(%p): width is %ld\n", This, pwidth, This->himetricWidth);
+  *pwidth = This->himetricWidth;
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEPictureImpl_get_Height
+ */ 
+static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
+						OLE_YSIZE_HIMETRIC *pheight)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  TRACE("(%p)->(%p): height is %ld\n", This, pheight, This->himetricHeight);
+  *pheight = This->himetricHeight;
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEPictureImpl_Render
+ */ 
+static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
+					    long x, long y, long cx, long cy,
+					    OLE_XPOS_HIMETRIC xSrc,
+					    OLE_YPOS_HIMETRIC ySrc,
+					    OLE_XSIZE_HIMETRIC cxSrc,
+					    OLE_YSIZE_HIMETRIC cySrc,
+					    LPCRECT prcWBounds)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  TRACE("(%p)->(%08x, (%ld,%ld), (%ld,%ld) <- (%ld,%ld), (%ld,%ld), %p)\n",
+	This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
+  if(prcWBounds)
+    TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
+	  prcWBounds->right, prcWBounds->bottom);
+
+  switch(This->desc.picType) {
+  case PICTYPE_BITMAP:
+    {
+      HBITMAP hbmpOld;
+      HDC hdcBmp;
+
+      /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
+         NB y-axis gets flipped */
+
+      hdcBmp = CreateCompatibleDC(0);
+      SetMapMode(hdcBmp, MM_ANISOTROPIC);
+      SetWindowOrgEx(hdcBmp, 0, 0, NULL);
+      SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
+      SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
+      SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
+
+      hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
+
+      StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
+
+      SelectObject(hdcBmp, hbmpOld);
+      DeleteDC(hdcBmp);
+    }
+    break;
+
+  case PICTYPE_METAFILE:
+  case PICTYPE_ICON:
+  case PICTYPE_ENHMETAFILE:
+  default:
+    FIXME("type %d not implemented\n", This->desc.picType);
+    return E_NOTIMPL;
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEPictureImpl_set_hPal
+ */ 
+static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
+					      OLE_HANDLE hpal)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  FIXME("(%p)->(%08x): stub\n", This, hpal);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_get_CurDC
+ */ 
+static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
+					       HDC *phdc)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  FIXME("(%p)->(%p): stub\n", This, phdc);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_SelectPicture
+ */ 
+static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
+						   HDC hdcIn,
+						   HDC *phdcOut,
+						   OLE_HANDLE *phbmpOut)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  FIXME("(%p)->(%08x, %p, %p): stub\n", This, hdcIn, phdcOut, phbmpOut);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_get_KeepOriginalFormat
+ */ 
+static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
+							    BOOL *pfKeep)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  FIXME("(%p)->(%p): stub\n", This, pfKeep);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_put_KeepOriginalFormat
+ */ 
+static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
+							    BOOL keep)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  FIXME("(%p)->(%d): stub\n", This, keep);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_PictureChanged
+ */ 
+static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  FIXME("(%p)->(): stub\n", This);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_SaveAsFile
+ */ 
+static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
+						IStream *pstream,
+						BOOL SaveMemCopy,
+						LONG *pcbSize)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  FIXME("(%p)->(%p, %d, %p): stub\n", This, pstream, SaveMemCopy, pcbSize);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_get_Attributes
+ */ 
+static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
+						    DWORD *pdwAttr)
+{
+  ICOM_THIS(OLEPictureImpl, iface);
+  FIXME("(%p)->(%p): stub\n", This, pdwAttr);
+  return E_NOTIMPL;
+}
+
+
+
+/************************************************************************
+ *    IDispatch
+ */
+/************************************************************************
+ * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
+  IDispatch* iface,
+  REFIID     riid,
+  VOID**     ppvoid)
+{
+  ICOM_THIS_From_IDispatch(IPicture, iface);
+
+  return IPicture_QueryInterface(This, riid, ppvoid);
+}
+
+/************************************************************************
+ * OLEPictureImpl_IDispatch_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
+  IDispatch* iface)
+{
+  ICOM_THIS_From_IDispatch(IPicture, iface);
+
+  return IPicture_AddRef(This);
+}
+
+/************************************************************************
+ * OLEPictureImpl_IDispatch_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
+  IDispatch* iface)
+{
+  ICOM_THIS_From_IDispatch(IPicture, iface);
+
+  return IPicture_Release(This);
+}
+
+/************************************************************************
+ * OLEPictureImpl_GetTypeInfoCount (IDispatch)
+ *
+ * See Windows documentation for more details on IDispatch methods.
+ */
+static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
+  IDispatch*    iface, 
+  unsigned int* pctinfo)
+{
+  FIXME("():Stub\n");
+
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_GetTypeInfo (IDispatch)
+ *
+ * See Windows documentation for more details on IDispatch methods.
+ */
+static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
+  IDispatch*  iface, 
+  UINT      iTInfo,
+  LCID        lcid, 
+  ITypeInfo** ppTInfo)
+{
+  FIXME("():Stub\n");
+
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_GetIDsOfNames (IDispatch)
+ *
+ * See Windows documentation for more details on IDispatch methods.
+ */
+static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
+  IDispatch*  iface,
+  REFIID      riid, 
+  LPOLESTR* rgszNames, 
+  UINT      cNames, 
+  LCID        lcid,
+  DISPID*     rgDispId)
+{
+  FIXME("():Stub\n");
+
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_Invoke (IDispatch)
+ *
+ * See Windows documentation for more details on IDispatch methods.
+ */
+static HRESULT WINAPI OLEPictureImpl_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;
+}
+
+
+static ICOM_VTABLE(IPicture) OLEPictureImpl_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  OLEPictureImpl_QueryInterface,
+  OLEPictureImpl_AddRef,
+  OLEPictureImpl_Release,
+  OLEPictureImpl_get_Handle,
+  OLEPictureImpl_get_hPal,
+  OLEPictureImpl_get_Type,
+  OLEPictureImpl_get_Width,
+  OLEPictureImpl_get_Height,
+  OLEPictureImpl_Render,
+  OLEPictureImpl_set_hPal,
+  OLEPictureImpl_get_CurDC,
+  OLEPictureImpl_SelectPicture,
+  OLEPictureImpl_get_KeepOriginalFormat,
+  OLEPictureImpl_put_KeepOriginalFormat,
+  OLEPictureImpl_PictureChanged,
+  OLEPictureImpl_SaveAsFile,
+  OLEPictureImpl_get_Attributes
+};
+
+static ICOM_VTABLE(IDispatch) OLEPictureImpl_IDispatch_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  OLEPictureImpl_IDispatch_QueryInterface,
+  OLEPictureImpl_IDispatch_AddRef,
+  OLEPictureImpl_IDispatch_Release,
+  OLEPictureImpl_GetTypeInfoCount,
+  OLEPictureImpl_GetTypeInfo,
+  OLEPictureImpl_GetIDsOfNames,
+  OLEPictureImpl_Invoke
+};
+
+/***********************************************************************
+ * OleCreatePictureIndirect
+ */
+HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
+		            BOOL fOwn, LPVOID *ppvObj )
+{
+  OLEPictureImpl* newPict = NULL;
+  HRESULT      hr         = S_OK;
+
+  TRACE("(%p,%p,%d,%p)\n", lpPictDesc, riid, fOwn, ppvObj);
+
+  /*
+   * Sanity check
+   */
+  if (ppvObj==0)
+    return E_POINTER;
+
+  *ppvObj = NULL;
+
+  /*
+   * Try to construct a new instance of the class.
+   */
+  newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
+
+  if (newPict == NULL)
+    return E_OUTOFMEMORY;
+
+  /*
+   * Make sure it supports the interface required by the caller.
+   */
+  hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
+
+  /*
+   * Release the reference obtained in the constructor. If
+   * the QueryInterface was unsuccessful, it will free the class.
+   */
+  IPicture_Release((IPicture*)newPict);
+
+  return hr;
+}
+
+
+/***********************************************************************
+ * OleLoadPicture
+ */
+HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
+		            REFIID reed, LPVOID *ppvObj )
+{
+  FIXME("(%p,%ld,%d,%p,%p), not implemented\n",
+	lpstream, lSize, fRunmode, reed, ppvObj);
+  return S_OK;
+}
+ 
+#ifdef __WIN32OS2__
+// ----------------------------------------------------------------------
+// OleLoadPictureFile
+// ----------------------------------------------------------------------
+HRESULT WIN32API OleLoadPictureFile(VARIANT varFileName, LPDISPATCH* lplpdispPicture)
+{
+    dprintf(("OLEAUT32: OleLoadPictureFile - stub"));
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// OleSavePictureFile
+// ----------------------------------------------------------------------
+HRESULT WIN32API OleSavePictureFile(LPDISPATCH lpdispPicture,
+    BSTR bstrFileName)
+{
+    dprintf(("OLEAUT32: OleSavePictureFile - stub"));
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// OleLoadPicturePath
+// ----------------------------------------------------------------------
+HRESULT WIN32API OleLoadPicturePath
+   (LPOLESTR  		szURLorPath,
+    LPUNKNOWN 		punkCaller,
+    DWORD     		dwReserved,
+    OLE_COLOR 		clrReserved,
+    REFIID    		riid,
+    LPVOID *  		ppvRet )
+{
+    dprintf(("OLEAUT32: OleLoadPicturePath - stub"));
+    return S_OK;
+}
+#endif
Index: trunk/src/oleaut32/parsedt.c
===================================================================
--- trunk/src/oleaut32/parsedt.c	(revision 4837)
+++ trunk/src/oleaut32/parsedt.c	(revision 4837)
@@ -0,0 +1,1334 @@
+/*
+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 <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
+
+static const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
+
+static const char * const months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
+
+static const char * const days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
+"Thursday", "Friday", "Saturday", NULL};
+
+/* those three vars are useless, and not even initialized, so 
+ * I'd rather remove them all (EPP)
+ */
+int	DateStyle; 
+bool	EuroDates;
+int	CTimeZone;
+
+#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))))))
+
+
+
+
+/*****************************************************************************
+ *	 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.cpp
===================================================================
--- trunk/src/oleaut32/parsedt.cpp	(revision 4830)
+++ 	(revision )
@@ -1,1333 +1,0 @@
-/* $Id: parsedt.cpp,v 1.2 1999-08-22 22:08:48 sandervl Exp $ */
-/*
-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 4830)
+++ trunk/src/oleaut32/parsedt.h	(revision 4837)
@@ -1,3 +1,2 @@
-/* $Id: parsedt.h,v 1.2 1999-08-22 22:08:48 sandervl Exp $ */
 /*
 PostgreSQL Data Base Management System (formerly known as Postgres, then
@@ -33,5 +32,5 @@
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsedt.h,v 1.2 1999-08-22 22:08:48 sandervl Exp $
+ * $Id: parsedt.h,v 1.3 2000-12-24 14:39:55 sandervl Exp $
  *
  *-------------------------------------------------------------------------
@@ -61,9 +60,9 @@
 #define false	((char) 0)
 #define true	((char) 1)
-//#ifndef __cplusplus
+#ifndef __cplusplus
 #ifndef bool
 typedef char bool;
 #endif   /* ndef bool */
-//#endif	 /* not C++ */
+#endif	 /* not C++ */
 typedef bool *BoolPtr;
 
@@ -147,7 +146,7 @@
 #define USE_GERMAN_DATES		3
 
-extern int	DateStyle;
-extern bool EuroDates;
-extern int	CTimeZone;
+extern	int	DateStyle;
+extern	bool	EuroDates;
+extern	int	CTimeZone;
 
 typedef double float8;
Index: trunk/src/oleaut32/safearray.c
===================================================================
--- trunk/src/oleaut32/safearray.c	(revision 4837)
+++ trunk/src/oleaut32/safearray.c	(revision 4837)
@@ -0,0 +1,1088 @@
+/*************************************************************************
+ * OLE Automation
+ * SafeArray Implementation
+ *
+ * This file contains the implementation of the SafeArray interface.
+ *
+ * Copyright 1999 Sylvain St-Germain
+ */
+
+#ifdef __WIN32OS2__
+#define HAVE_FLOAT_H
+#define WINE_LARGE_INTEGER
+#include "oleaut32.h"
+#endif
+#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
+static const 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	*/
+};
+
+static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(ULONG);
+
+
+/*************************************************************************
+ *		SafeArrayAllocDescriptor
+ * 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)=HeapAlloc( 
+        GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
+    return(E_UNEXPECTED);
+  }
+  TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
+
+  return(S_OK);
+}
+
+/*************************************************************************
+ *		SafeArrayAllocData
+ * 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);
+}
+
+/*************************************************************************
+ *		SafeArrayCreate
+ * 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); 
+}
+
+/*************************************************************************
+ *		SafeArrayDestroyDescriptor
+ * 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);
+}
+
+
+/*************************************************************************
+ *		SafeArrayLock
+ * 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);
+}
+
+/*************************************************************************
+ *		SafeArrayUnlock
+ * Decrement the lock counter
+ */
+HRESULT WINAPI SafeArrayUnlock(
+  SAFEARRAY *psa)
+{
+  if(! validArg(psa)) 
+    return E_INVALIDARG;
+
+  if (psa->cLocks > 0) 
+    psa->cLocks--;
+
+  return(S_OK);
+}
+
+
+/*************************************************************************
+ *		SafeArrayPutElement
+ * 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);  
+}
+
+
+/*************************************************************************
+ *		SafeArrayGetElement
+ * 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) );  
+}
+
+/*************************************************************************
+ *		SafeArrayGetUBound
+ * 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;
+}
+
+/*************************************************************************
+ *		SafeArrayGetLBound
+ * 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;
+}
+
+/*************************************************************************
+ *		SafeArrayGetDim
+ * 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;
+}
+
+/*************************************************************************
+ *		SafeArrayGetElemsize
+ * 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;
+}
+
+/*************************************************************************
+ *		SafeArrayAccessData
+ * 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;
+}
+
+
+/*************************************************************************
+ *		SafeArrayUnaccessData
+ * Decrement the access count
+ */
+HRESULT WINAPI SafeArrayUnaccessData(
+  SAFEARRAY * psa)
+{ 
+  if(! validArg(psa)) 
+    return E_INVALIDARG;
+
+  return(SafeArrayUnlock(psa));
+}
+
+/************************************************************************ 
+ *		SafeArrayPtrOfIndex
+ * 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;
+}
+
+/************************************************************************ 
+ *		SafeArrayDestroyData
+ * 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_CREATEVECTOR)) { /* 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;
+}
+
+/************************************************************************ 
+ *		SafeArrayCopyData
+ * 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);
+}
+
+/************************************************************************ 
+ *		SafeArrayDestroy
+ * 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 */
+}
+
+/************************************************************************ 
+ *		SafeArrayCopy
+ * Make a dupplicate of a SafeArray
+ */
+HRESULT WINAPI SafeArrayCopy(
+  SAFEARRAY *psa, 
+  SAFEARRAY **ppsaOut)
+{ 
+  HRESULT hRes;
+  DWORD   dAllocSize;
+  ULONG   ulWholeArraySize; /* size of the thing */
+
+  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 */
+
+    /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
+       because the data has not been allocated with the descriptor. */
+    (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;  
+ 
+    /* Get the allocated memory size for source and allocate it for target */ 
+    ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
+    dAllocSize = ulWholeArraySize*psa->cbElements;
+
+    (*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;
+}
+
+/************************************************************************ 
+ *		SafeArrayCreateVector
+ * 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 = 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_CREATEVECTOR;  /* undocumented flag used by Microsoft */
+  psa->cLocks     = 0;
+  psa->pvData     = (BYTE*)psa + sizeof(*psa);
+  psa->cbElements = VARTYPE_SIZE[vt];
+
+  psa->rgsabound[0].cElements = cElements;
+  psa->rgsabound[0].lLbound   = lLbound;
+
+  return(psa); 				  
+} 
+
+/************************************************************************ 
+ *		SafeArrayRedim
+ * 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 makes sense... That's the only thing
+     I can think of now... */
+
+  psaSize = HeapSize(GetProcessHeap(), 0, psa);
+  if (psaSize == -1)
+    /* uh, foreign heap. Better don't mess with it ! */
+    return TRUE;
+
+  /* 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 );
+      }
+  }
+
+  if (!(psa->fFeatures & FADF_CREATEVECTOR))
+  {
+    /* 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
+                      */
+  }
+  else
+  {
+    /* Allocate a new block, because the previous data has been allocated with 
+       the descriptor in SafeArrayCreateVector function. */
+
+    if((pvNewBlock = HeapAlloc(GetProcessHeap(), 0,
+       ulWholeArraySize * psa->cbElements)) == NULL) 
+        return FALSE;
+
+    psa->fFeatures &= ~FADF_CREATEVECTOR;
+  }
+  /* 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;
+}
+
+
+/************************************************************************ 
+ *		SafeArrayGetVarType
+ * Returns the VARTYPE stored in the given safearray
+ */
+HRESULT WINAPI SafeArrayGetVarType(
+  SAFEARRAY* psa,
+  VARTYPE*   pvt)
+{
+  HRESULT hr = E_INVALIDARG;
+  VARTYPE vt = VT_EMPTY;
+
+  /* const short VARTYPE_OFFSET = -4; */
+
+  if (psa->fFeatures & FADF_HAVEVARTYPE)
+  {
+    /* VT tag @ negative offset 4 in the array descriptor */
+    FIXME("Returning VT_BSTR instead of VT_...");
+    vt = VT_BSTR;
+  }
+  else if (psa->fFeatures & FADF_RECORD)
+  {
+    vt = VT_RECORD;
+  }
+  else if (psa->fFeatures & FADF_DISPATCH)
+  {
+    vt = VT_DISPATCH;
+  }
+  else if (psa->fFeatures & FADF_UNKNOWN)
+  {
+    vt = VT_UNKNOWN;
+  }
+
+  if (vt != VT_EMPTY)
+  {
+    *pvt = vt;
+    hr = S_OK;
+  }
+  
+  TRACE("HRESULT = %08lx", hr);
+  return hr;
+}
Index: trunk/src/oleaut32/safearray.cpp
===================================================================
--- trunk/src/oleaut32/safearray.cpp	(revision 4830)
+++ 	(revision )
@@ -1,1004 +1,0 @@
-/* $Id: safearray.cpp,v 1.2 1999-08-22 22:08:49 sandervl Exp $ */
-/*************************************************************************
- * 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/stubs.cpp
===================================================================
--- trunk/src/oleaut32/stubs.cpp	(revision 4830)
+++ trunk/src/oleaut32/stubs.cpp	(revision 4837)
@@ -1,3 +1,3 @@
-/* $Id: stubs.cpp,v 1.7 2000-11-21 12:16:22 sandervl Exp $ */
+/* $Id: stubs.cpp,v 1.8 2000-12-24 14:39:56 sandervl Exp $ */
 /* 
  * Win32 COM/OLE stubs for OS/2
@@ -55,68 +55,4 @@
 //*****************************************************************************
 //*****************************************************************************
-HRESULT WIN32API DispGetParam
-   (DISPPARAMS *	pdispparams,
-    UINT		position,
-    VARTYPE		vtTarg,
-    VARIANT *		pvarResult,
-    UINT *		puArgErr)
-{
-    dprintf(("OLEAUT32: DispGetParam - stub"));
-    return S_OK;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT WIN32API DispGetIDsOfNames
-   (ITypeInfo *		ptinfo,
-    OLECHAR **		rgszNames,
-    UINT		cNames,
-    DISPID *		rgdispid)
-{
-    dprintf(("OLEAUT32: DispGetIDsOfNames - stub"));
-    return S_OK;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT WIN32API DispInvoke
-   (void *		_this,
-    ITypeInfo *		ptinfo,
-    DISPID		dispidMember,
-    WORD		wFlags,
-    DISPPARAMS *	pparams,
-    VARIANT *		pvarResult,
-    EXCEPINFO *		pexcepinfo,
-    UINT *		puArgErr)
-{
-    dprintf(("OLEAUT32: DispInvoke - stub"));
-    return S_OK;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT WIN32API CreateDispTypeInfo
-   (INTERFACEDATA *	pidata,
-    LCID		lcid,
-    ITypeInfo **	pptinfo)
-{
-    dprintf(("OLEAUT32: CreateDispTypeInfo - stub"));
-    return E_OUTOFMEMORY;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT WIN32API CreateStdDispatch
-   (IUnknown *		punkOuter,
-    void *		pvThis,
-    ITypeInfo *		ptinfo,
-    IUnknown **		ppunkStdDisp)
-{
-    dprintf(("OLEAUT32: CreateStdDispatch - stub"));
-    return S_OK;
-}
-
-//*****************************************************************************
-//*****************************************************************************
 HRESULT WIN32API RegisterActiveObject
    (IUnknown *		punk,
@@ -266,26 +202,9 @@
 //*****************************************************************************
 //*****************************************************************************
-HRESULT WIN32API DispCallFunc
-   (void *		pvInstance,
-   ULONG		oVft,
-   UINT			cc,
-   VARTYPE		vtReturn,
-   UINT 		cActuals,
-   VARTYPE *		prgvt,
-   VARIANTARG **	prgpvarg,
-   VARIANT *		pvargResult)
+HRESULT WINAPI DispCallFunc(void* pvInstance, ULONG oVft, CALLCONV_OLE2 cc,
+            VARTYPE vtReturn, UINT  cActuals, VARTYPE* prgvt,
+            VARIANTARG** prgpvarg, VARIANT* pvargResult)
 {
     dprintf(("OLEAUT32: DispCallFunc - stub"));
-    return S_OK;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT WIN32API CreateTypeLib
-   (SYSKIND		syskind,
-    const OLECHAR *	szFile,
-    ICreateTypeLib **	ppctlib)
-{
-    dprintf(("OLEAUT32: CreateTypeLib - stub"));
     return S_OK;
 }
Index: trunk/src/oleaut32/typelib.c
===================================================================
--- trunk/src/oleaut32/typelib.c	(revision 4837)
+++ trunk/src/oleaut32/typelib.c	(revision 4837)
@@ -0,0 +1,3332 @@
+/*
+ *	TYPELIB
+ *
+ *	Copyright 1997	Marcus Meissner
+ *		      1999  Rein Klazes
+ *		      2000  Francois Jacques
+ * --------------------------------------------------------------------------------------
+ * Known problems (2000, Francois Jacques)
+ *
+ * - Tested using OLEVIEW (Platform SDK tool) only.
+ *   
+ * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are 
+ *   creating by doing a straight copy of the dispinterface instance and just changing 
+ *   its typekind. Pointed structures aren't copied - only the address of the pointers.
+ *   So when you release the dispinterface, you delete the vtable-interface structures
+ *   as well... fortunately, clean up of structures is not implemented.
+ * 
+ * - locale stuff is partially implemented but hasn't been tested.
+ *
+ * - imported typelib should be stored together in a linked list instead of having
+ *   independant TLBImpLib strucutures in each ITypeInfo. This way, imported libraries
+ *   are just imported once (major optimization)
+ *
+ * - typelib file is still read it's in entirety, but it is released now.
+ * - some garbage is read from function names on some very rare occasion
+ *
+ * --------------------------------------------------------------------------------------
+ *  Known problems left from previous implementation (1999, Rein Klazes) :
+ *
+ * -. Only one format of typelibs is supported
+ * -. Data structures are straightforward, but slow for look-ups.
+ * -. (related) nothing is hashed
+ * -. 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.
+ * -. 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.
+ * 
+ */
+#ifdef __WIN32OS2__
+#define HAVE_FLOAT_H
+#define WINE_LARGE_INTEGER
+#include "oleaut32.h"
+#include <win\pe_image.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "winerror.h"
+#include "winreg.h"         /* for HKEY_LOCAL_MACHINE */
+#include "winnls.h"         /* for PRIMARYLANGID */
+#include "ole.h"
+#include "heap.h"
+#include "wine/obj_base.h"
+#include "debugtools.h"
+#include "typelib.h"
+
+DEFAULT_DEBUG_CHANNEL(ole);
+DECLARE_DEBUG_CHANNEL(typelib);
+
+#ifndef __WIN32OS2__
+/****************************************************************************
+ *		QueryPathOfRegTypeLib16	[TYPELIB.14]
+ *
+ * the path is "Classes\Typelib\<guid>\<major>.<minor>\<lcid>\win16\"
+ * RETURNS
+ *	path of typelib
+ */
+HRESULT WINAPI
+QueryPathOfRegTypeLib16(	
+	REFGUID guid,	/* [in] referenced guid */
+	WORD wMaj,	/* [in] major version */
+	WORD wMin,	/* [in] minor version */
+	LCID lcid,	/* [in] locale id */
+	LPBSTR16 path	/* [out] path of typelib */
+) {
+	char	xguid[80];
+	char	typelibkey[100],pathname[260];
+	DWORD	plen;
+
+       	TRACE("\n");
+
+	if (HIWORD(guid)) {
+            sprintf( typelibkey, "SOFTWARE\\Classes\\Typelib\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\%d.%d\\%lx\\win16",
+                     guid->Data1, guid->Data2, guid->Data3,
+                     guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+                     guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7],
+                     wMaj,wMin,lcid);
+	} else {
+		sprintf(xguid,"<guid 0x%08lx>",(DWORD)guid);
+		FIXME("(%s,%d,%d,0x%04lx,%p),can't handle non-string guids.\n",xguid,wMaj,wMin,(DWORD)lcid,path);
+		return E_FAIL;
+	}
+	plen = sizeof(pathname);
+	if (RegQueryValueA(HKEY_LOCAL_MACHINE,typelibkey,pathname,&plen)) {
+		/* try again without lang specific id */
+		if (SUBLANGID(lcid))
+			return QueryPathOfRegTypeLib16(guid,wMaj,wMin,PRIMARYLANGID(lcid),path);
+		FIXME("key %s not found\n",typelibkey);
+		return E_FAIL;
+	}
+	*path = SysAllocString16(pathname);
+	return S_OK;
+}
+#endif
+ 
+/****************************************************************************
+ *		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 */
+{
+    /* don't need to ZeroMemory those arrays since sprintf and RegQueryValue add
+       string termination character on output strings */
+
+    HRESULT hr        = E_FAIL;
+
+    DWORD   dwPathLen = _MAX_PATH;
+    LCID    myLCID    = lcid;
+
+    char    szXGUID[80];
+    char    szTypeLibKey[100];
+#ifdef __WIN32OS2__
+    //since when is this valid C code??????
+    char    szPath[_MAX_PATH];
+#else
+    char    szPath[dwPathLen];
+#endif
+
+    if ( !HIWORD(guid) )
+    {
+        sprintf(szXGUID,
+            "<guid 0x%08lx>",
+            (DWORD) guid);
+
+        FIXME("(%s,%d,%d,0x%04lx,%p),stub!\n", szXGUID, wMaj, wMin, (DWORD)lcid, path);
+        return E_FAIL;
+    }
+
+    while (hr != S_OK)
+    {
+        sprintf(szTypeLibKey,
+            "SOFTWARE\\Classes\\Typelib\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\%d.%d\\%lx\\win32",
+            guid->Data1,    guid->Data2,    guid->Data3,
+            guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], 
+            guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7],
+            wMaj,
+            wMin,
+            myLCID);
+
+        if (RegQueryValueA(HKEY_LOCAL_MACHINE, szTypeLibKey, szPath, &dwPathLen))
+        {
+            if (!lcid)
+                break;
+            else if (myLCID == lcid)
+            {
+                /* try with sub-langid */
+                myLCID = SUBLANGID(lcid);
+            }
+            else if ((myLCID == SUBLANGID(lcid)) && myLCID)
+            {
+                /* try with system langid */
+                myLCID = 0;
+            }
+            else
+            {
+                break;
+            }
+        }
+        else
+        {
+            DWORD len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, dwPathLen, NULL, 0 );
+            BSTR bstrPath = SysAllocStringLen(NULL,len);
+
+            MultiByteToWideChar(CP_ACP,
+                                MB_PRECOMPOSED,
+                                szPath,
+                                dwPathLen,
+                                bstrPath,
+                                len);
+           *path = bstrPath;
+           hr = S_OK;
+        }
+    }
+	
+    if (hr != S_OK)
+		TRACE_(typelib)("%s not found\n", szTypeLibKey);
+	
+    return hr;
+}
+
+/******************************************************************************
+ * CreateTypeLib [OLEAUT32]  creates a typelib
+ *
+ * RETURNS
+ *    Success: S_OK
+ *    Failure: Status
+ */
+HRESULT WINAPI CreateTypeLib(
+	SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib
+) {
+    FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
+    return E_FAIL;
+}
+#ifndef __WIN32OS2__
+/******************************************************************************
+ * 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(
+    LPOLESTR szFile, /* [in] Name of file to load from */
+    ITypeLib** pptLib) /* [out] Pointer to pointer to loaded type library */
+{
+    FIXME("('%s',%p): stub\n",debugstr_w((LPWSTR)szFile),pptLib);
+
+    if (pptLib!=0)
+      *pptLib=0;
+
+    return E_FAIL;
+}
+#endif
+
+/******************************************************************************
+ *		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, ITypeLib2 **ppTypelib);
+
+HRESULT WINAPI LoadTypeLib(
+    const OLECHAR *szFile,/* [in] Name of file to load from */
+    ITypeLib * *pptLib)   /* [out] Pointer to pointer to loaded type library */
+{
+    TRACE("\n");
+    return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
+}
+
+/******************************************************************************
+ *		LoadTypeLibEx	[OLEAUT32.183]
+ * Loads and optionally registers a type library
+ *
+ * RETURNS
+ *    Success: S_OK
+ *    Failure: Status
+ */
+HRESULT WINAPI LoadTypeLibEx(
+    LPCOLESTR szFile,  /* [in] Name of file to load from */
+    REGKIND  regkind,  /* [in] Specify kind of registration */
+    ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
+{
+    LPSTR p;
+    HRESULT res;
+    TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
+    
+    p=HEAP_strdupWtoA(GetProcessHeap(),0,szFile);
+    
+    if(regkind != REGKIND_NONE)
+        FIXME ("registration of typelibs not supported yet!\n");
+
+    res= TLB_ReadTypeLib(p, (ITypeLib2**)pptLib);
+    HeapFree(GetProcessHeap(),0,p);
+    TRACE(" returns %08lx\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);
+    }
+
+    TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), 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("(%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)
+{   
+    TRACE("(IID: %s): stub\n",debugstr_guid(libid));
+    return S_OK;	/* FIXME: pretend everything is OK */
+}
+
+#ifndef __WIN32OS2__
+/****************************************************************************
+ *	OaBuildVersion				(TYPELIB.15)
+ *
+ * known TYPELIB.DLL versions:
+ *
+ * OLE 2.01 no OaBuildVersion() avail	1993	--	---
+ * OLE 2.02				1993-94	02     3002
+ * OLE 2.03					23	730
+ * OLE 2.03					03     3025
+ * OLE 2.03 W98 SE orig. file !!	1993-95	10     3024
+ * OLE 2.1   NT				1993-95	??	???
+ * OLE 2.3.1 W95				23	700
+ * OLE2 4.0  NT4SP6			1993-98	40     4277
+ */
+DWORD WINAPI OaBuildVersion16(void)
+{
+    /* FIXME: I'd like to return the highest currently known version value
+     * in case the user didn't force a --winver, but I don't know how
+     * to retrieve the "versionForced" info from misc/version.c :(
+     * (this would be useful in other places, too) */
+    FIXME("Please report to a.mohr@mailto.de if you get version error messages !\n");
+    switch(GetVersion() & 0x8000ffff)  /* mask off build number */
+    {
+    case 0x80000a03:  /* WIN31 */
+		return MAKELONG(3027, 3); /* WfW 3.11 */
+    case 0x80000004:  /* WIN95 */
+		return MAKELONG(700, 23); /* Win95A */
+    case 0x80000a04:  /* WIN98 */
+		return MAKELONG(3024, 10); /* W98 SE */
+    case 0x00000004:  /* NT4 */
+		return MAKELONG(4277, 40); /* NT4 SP6 */
+    default:
+	FIXME("Version value not known yet. Please investigate it !");
+		return 0;
+    }
+}
+
+/* for better debugging info leave the static out for the time being */
+#define static
+#endif
+
+/*======================= ITypeLib implementation =======================*/
+
+typedef struct tagTLBCustData 
+{
+    GUID guid;
+    VARIANT data;
+    struct tagTLBCustData* next;
+} TLBCustData;
+
+/* data structure for import typelibs */
+typedef struct tagTLBImpLib
+{
+    int offset;                 /* offset in the file */
+    GUID guid;                  /* libid */
+    BSTR name;                  /* name; */
+
+	LCID lcid;					/* lcid of imported typelib */
+
+	WORD wVersionMajor;         /* major version number */
+    WORD wVersionMinor;         /* minor version number */
+
+    struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib */
+    struct tagTLBImpLib * next;
+} TLBImpLib;
+
+/* internal ITypeLib data */
+typedef struct tagITypeLibImpl
+{
+    ICOM_VFIELD(ITypeLib2);
+    UINT ref;
+    TLIBATTR LibAttr;            /* guid,lcid,syskind,version,flags */
+    
+    /* strings can be stored in tlb as multibyte strings BUT they are *always*
+	 * exported to the application as a UNICODE string.
+	 */
+	BSTR Name;
+    BSTR DocString;
+    BSTR HelpFile;
+    BSTR HelpStringDll;
+    unsigned long  dwHelpContext;
+    int TypeInfoCount;          /* nr of typeinfo's in librarry */
+    struct tagITypeInfoImpl *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 */
+} ITypeLibImpl;
+
+static struct ICOM_VTABLE(ITypeLib2) tlbvt;
+
+/* ITypeLib methods */
+static ITypeLib2* ITypeLib2_Constructor(LPVOID pLib, DWORD dwTLBLength);
+
+/*======================= ITypeInfo implementation =======================*/
+
+/* 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; */
+    TLBImpLib *pImpTLInfo;
+    struct tagTLBRefType * next;
+} TLBRefType;
+
+/* internal Parameter data */
+typedef struct tagTLBParDesc
+{
+    BSTR Name;
+    int ctCustData;
+    TLBCustData * pCustData;        /* linked list to cust data; */
+	TLBRefType * pRefType;			/* linked list to referenced types */
+} TLBParDesc;
+
+/* internal Function data */
+typedef struct tagTLBFuncDesc
+{
+    FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
+    BSTR Name;             /* the name of this function */
+    TLBParDesc *pParamDesc; /* array with name and custom data */
+    int helpcontext;
+    int HelpStringContext;
+    BSTR HelpString;
+    BSTR 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. */
+    BSTR Name;             /* the name of this variable */
+    int HelpContext;
+    int HelpStringContext;  /* fixme: where? */
+    BSTR HelpString;
+    int ctCustData;
+    TLBCustData * pCustData;/* linked list to cust data; */
+    struct tagTLBVarDesc * next; 
+} TLBVarDesc;
+
+/* internal TypeInfo data */
+typedef struct tagITypeInfoImpl
+{
+    ICOM_VFIELD(ITypeInfo2);
+    UINT ref;
+    TYPEATTR TypeAttr ;         /* _lots_ of type information. */
+    ITypeLibImpl * 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?
+     */
+    BSTR Name;
+    BSTR 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 tagITypeInfoImpl * next;
+} ITypeInfoImpl;
+
+static struct ICOM_VTABLE(ITypeInfo2) tinfvt;
+
+static ITypeInfo2 * WINAPI ITypeInfo_Constructor();
+
+typedef struct tagTLBContext
+{
+	unsigned int oStart;  /* start of TLB in file */
+	unsigned int pos;     /* current pos */
+	unsigned int length;  /* total length */
+	void *mapping;        /* memory mapping */
+	TLBSegDir * pTblDir;
+	ITypeLibImpl* pLibInfo;
+} TLBContext;
+
+
+static void TLB_DoRefType(TLBContext *pcx, int offset, TLBRefType ** pprtd);
+
+/*
+ debug
+*/
+static void dump_TLBFuncDesc(TLBFuncDesc * pfd)
+{
+	while (pfd)
+	{
+	  TRACE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
+	  pfd = pfd->next;
+	};
+}
+static void dump_TLBVarDesc(TLBVarDesc * pvd)
+{
+	while (pvd)
+	{
+	  TRACE("%s\n", debugstr_w(pvd->Name));
+	  pvd = pvd->next;
+	};
+}
+static void dump_TLBRefType(TLBRefType * prt)
+{
+	while (prt)
+	{
+	  TRACE("%s\n", debugstr_guid(&(prt->guid)));
+	  TRACE("  href:0x%08lx\n", prt->reference);
+	  prt = prt->next;
+	};
+}
+
+static void dump_Variant(VARIANT * pvar)
+{
+	TRACE("%p %x\n", pvar, pvar?pvar->vt:0 );
+	if(!pvar) return;
+
+	if (pvar->vt & VT_BYREF)
+	  return dump_Variant(pvar->u.pvarVal);
+}
+
+static void dump_DispParms(DISPPARAMS * pdp)
+{
+	dump_Variant( pdp->rgvarg);
+	TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
+}
+
+static char * typekind_desc[] =
+{
+	"TKIND_ENUM",
+	"TKIND_RECORD",
+	"TKIND_MODULE",
+	"TKIND_INTERFACE",
+	"TKIND_DISPATCH",
+	"TKIND_COCLASS",
+	"TKIND_ALIAS",
+	"TKIND_UNION",
+	"TKIND_MAX"
+};
+
+static void dump_TypeInfo(ITypeInfoImpl * pty)
+{
+    TRACE("%p ref=%u\n", pty, pty->ref);
+    TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
+    TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
+    TRACE("fct:%u var:%u impl:%u\n",
+      pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
+    TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
+    TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
+    dump_TLBFuncDesc(pty->funclist);
+    dump_TLBVarDesc(pty->varlist);
+    dump_TLBRefType(pty->impltypelist);
+}
+
+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()
+{
+    DebugBreak();
+}
+static void * TLB_Alloc(unsigned size)
+{
+    void * ret;
+    if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){
+        /* FIXME */
+        ERR("cannot allocate memory\n");
+    }
+    return ret;
+}
+
+static void TLB_Free(void * ptr)
+{
+    HeapFree(GetProcessHeap(), 0, ptr);
+}
+/* read function */
+DWORD TLB_Read(void *buffer,  DWORD count, TLBContext *pcx, long where )
+{
+    TRACE("pos=0x%08x len=0x%08lx 0x%08x 0x%08x 0x%08lx\n",
+       pcx->pos, count, pcx->oStart, pcx->length, where);
+
+    if (where != DO_NOT_SEEK)
+    {
+        where += pcx->oStart;
+        if (where > pcx->length)
+        {
+            /* FIXME */
+            ERR("seek beyond end (%ld/%d)\n", where, pcx->length );
+            TLB_abort();
+        }
+        pcx->pos = where;
+    }
+    if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
+    memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
+    pcx->pos += count;
+    return count;
+}
+
+static void TLB_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
+{
+    TRACE("%s\n", debugstr_guid(pGuid));
+
+    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 );
+}
+
+BSTR TLB_ReadName( TLBContext *pcx, int offset)
+{
+    char * name;
+    TLBNameIntro niName;
+    int lengthInChars;
+    WCHAR* pwstring = NULL;
+    BSTR bstrName = NULL;
+
+    TLB_Read(&niName, sizeof(niName), pcx,
+				pcx->pTblDir->pNametab.offset+offset);
+    niName.namelen &= 0xFF; /* FIXME: correct ? */
+    name=TLB_Alloc((niName.namelen & 0xff) +1);
+    TLB_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
+    name[niName.namelen & 0xff]='\0';
+
+    lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
+                                        name, -1, NULL, 0);
+
+    /* no invalid characters in string */
+    if (lengthInChars)
+    {
+        pwstring = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lengthInChars);
+
+        /* don't check for invalid character since this has been done previously */
+        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, pwstring, lengthInChars);
+
+        bstrName = SysAllocStringLen(pwstring, lengthInChars);
+        lengthInChars = SysStringLen(bstrName);
+        HeapFree(GetProcessHeap(), 0, pwstring);
+    }
+
+    TRACE("%s %d\n", debugstr_w(bstrName), lengthInChars);
+    return bstrName;
+}
+
+BSTR TLB_ReadString( TLBContext *pcx, int offset)
+{
+    char * string;
+    INT16 length;
+    int lengthInChars;
+    BSTR bstr = NULL;
+
+    if(offset<0) return NULL;
+    TLB_Read(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
+    if(length <= 0) return 0;
+    string=TLB_Alloc(length +1);
+    TLB_Read(string, length, pcx, DO_NOT_SEEK);
+    string[length]='\0';
+
+    lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
+                                        string, -1, NULL, 0);
+
+    /* no invalid characters in string */
+    if (lengthInChars)
+    {
+        WCHAR* pwstring = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lengthInChars);
+
+        /* don't check for invalid character since this has been done previously */
+        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, pwstring, lengthInChars);
+
+        bstr = SysAllocStringLen(pwstring, lengthInChars);
+        lengthInChars = SysStringLen(bstr);
+        HeapFree(GetProcessHeap(), 0, pwstring);
+    }
+
+    TRACE("%s %d\n", debugstr_w(bstr), lengthInChars);
+    return bstr;
+}
+/*
+ * read a value and fill a VARIANT structure 
+ */
+static void TLB_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
+{
+    int size;
+
+    TRACE("\n");
+
+    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 );
+    TRACE("Vartype = %x\n", pVar->vt);
+    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 );
+	    if(size <= 0) {
+	        FIXME("BSTR length = %d?\n", size);
+	    } else {
+                ptr=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("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;
+
+    TRACE("\n");
+
+    while(offset >=0){
+        count++;
+        pNew=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))];
+
+    TRACE("vt type = %X\n", pTd->vt);
+}
+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);
+
+    TRACE("\n");
+
+    TLB_Read(&infolen,sizeof(INT), pcx, offset);
+    for(i=0;i<cFuncs;i++){
+        *pptfd=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 = (WCHAR*) 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 = (pFuncRec->FKCCIC) & 0x7;
+        (*pptfd)->funcdesc.invkind = ((pFuncRec->FKCCIC) >>3) & 0xF;
+        (*pptfd)->funcdesc.callconv = (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=
+                TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC));
+            (*pptfd)->pParamDesc=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++){
+				TYPEDESC* lpArgTypeDesc = 0;
+				
+                TLB_GetTdesc(pcx, paraminfo.DataType,   
+                    &(*pptfd)->funcdesc.lprgelemdescParam[j].tdesc) ;
+                V_UNION(&((*pptfd)->funcdesc.lprgelemdescParam[j]),
+                    paramdesc.wParamFlags) = paraminfo.Flags;
+                (*pptfd)->pParamDesc[j].Name=(void *)paraminfo.oName;
+
+				/* SEEK value = jump to offset, from there jump to the end of record,
+				 * go back by (j-1) arguments
+				 */
+				TLB_Read(&paraminfo,sizeof(TLBParameterInfo), pcx,
+                        recoffset+reclength - 
+						((pFuncRec->nrargs - j - 1) * sizeof(TLBParameterInfo)));
+
+                lpArgTypeDesc = & ((*pptfd)->funcdesc.lprgelemdescParam[j].tdesc) ;
+
+                while (lpArgTypeDesc != NULL)
+                {
+                   switch (lpArgTypeDesc->vt)
+                   {
+                     case VT_PTR:
+                       lpArgTypeDesc = lpArgTypeDesc->u.lptdesc;
+                       break;
+                     
+                     case VT_CARRAY:
+                       lpArgTypeDesc = & (lpArgTypeDesc->u.lpadesc->tdescElem);
+                       break;
+               
+                     case VT_USERDEFINED:
+                       (*pptfd)->pParamDesc[j].pRefType = TLB_Alloc(sizeof(TLBRefType));
+                       TLB_DoRefType(pcx, lpArgTypeDesc->u.hreftype, &((*pptfd)->pParamDesc[j].pRefType));
+                       lpArgTypeDesc = NULL;
+                       break;
+                     
+                     default:
+                       lpArgTypeDesc = NULL;
+                   }
+                }
+            }
+            /* 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 = 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;
+
+    TRACE("\n");
+
+    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=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 = 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)=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 from import, its an offset+1 in the ImpInfo table
+ * */
+static void TLB_DoRefType(TLBContext *pcx, 
+                          int offset, TLBRefType ** pprtd)
+{
+    int j;
+
+	TRACE("TLB context %p, TLB offset %x\n", pcx, offset);
+
+    if(!HREFTYPE_INTHISFILE( offset)) {
+        /* external typelib */
+        TLBImpInfo impinfo;
+        TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs);
+
+        TRACE("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));
+		
+        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("Cannot find a reference\n");
+            (*pprtd)->reference=-1;
+            (*pprtd)->pImpTLInfo=(void *)-1;
+        }
+    }else{
+        /* in this typelib */
+        (*pprtd)->reference=offset;
+        (*pprtd)->pImpTLInfo=(void *)-2;
+    }
+}
+
+/* process Implemented Interfaces of a com class */
+static void TLB_DoImplTypes(TLBContext *pcx, int count,
+                          int offset, TLBRefType ** pprtd)
+{
+    int i;
+    TLBRefRecord refrec;
+
+    TRACE("\n");
+
+    for(i=0;i<count;i++){
+        if(offset<0) break; /* paranoia */
+        *pprtd=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
+ */
+ITypeInfoImpl * TLB_DoTypeInfo(
+	TLBContext *pcx,
+	int count,
+	ITypeLibImpl * pLibInfo)
+{
+    TLBTypeInfoBase tiBase;
+    ITypeInfoImpl *ptiRet;
+
+    TRACE("count=%u\n", count);
+
+    ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
+    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=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("reading %s\n", debugstr_w(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 ){
+        switch(ptiRet->TypeAttr.typekind)
+		{
+		case TKIND_COCLASS:
+            TLB_DoImplTypes(pcx, ptiRet->TypeAttr.cImplTypes , 
+                tiBase.datatype1, & ptiRet->impltypelist);
+			break;
+		case TKIND_DISPATCH:
+            ptiRet->impltypelist=TLB_Alloc(sizeof(TLBRefType));
+            
+            if (tiBase.datatype1 != -1)
+            {
+              TLB_DoRefType(pcx, tiBase.datatype1, & ptiRet->impltypelist);
+            }
+            else
+            {
+              char* szStdOle     = "stdole2.tlb\0";
+              int   nStdOleLen = strlen(szStdOle);
+                            
+              ptiRet->impltypelist->guid             = IID_IDispatch;
+              ptiRet->impltypelist->reference        = -1;
+              ptiRet->impltypelist->pImpTLInfo       = TLB_Alloc(sizeof(TLBImpLib));
+              ptiRet->impltypelist->pImpTLInfo->guid = IID_StdOle;             
+              ptiRet->impltypelist->pImpTLInfo->name = SysAllocStringLen(NULL, nStdOleLen  + 1);
+              
+              MultiByteToWideChar(CP_ACP,
+                                  MB_PRECOMPOSED,
+                                  szStdOle,
+                                  -1,
+                                  ptiRet->impltypelist->pImpTLInfo->name,
+                                  SysStringLen(ptiRet->impltypelist->pImpTLInfo->name));
+                                  
+              ptiRet->impltypelist->pImpTLInfo->lcid          = 0;
+              ptiRet->impltypelist->pImpTLInfo->wVersionMajor = 2;
+              ptiRet->impltypelist->pImpTLInfo->wVersionMinor = 0;
+            }
+			break;
+		default:
+			ptiRet->impltypelist=TLB_Alloc(sizeof(TLBRefType));
+            TLB_DoRefType(pcx, tiBase.datatype1, & ptiRet->impltypelist);
+			break;
+		}
+    }
+    ptiRet->ctCustData=
+        TLB_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData);
+
+    TRACE("%s guid: %s kind:%s\n",
+       debugstr_w(ptiRet->Name),
+       debugstr_guid(&ptiRet->TypeAttr.guid),
+       typekind_desc[ptiRet->TypeAttr.typekind]);
+
+    return ptiRet;
+}
+
+/****************************************************************************
+ *	TLB_ReadTypeLib
+ *
+ * find the type of the typelib file and map the typelib resource into
+ * the memory
+ */
+#define MSFT_SIGNATURE 0x5446534D /* "MSFT" */
+int TLB_ReadTypeLib(LPSTR pszFileName, ITypeLib2 **ppTypeLib)
+{
+    int ret = E_FAIL;
+    DWORD dwSignature = 0;
+    HFILE hFile;
+	int nStrLen = strlen(pszFileName);
+	int i;
+
+	PCHAR pszTypeLibIndex = NULL;
+    PCHAR pszDllName      = NULL;
+
+    TRACE("%s\n", pszFileName);
+
+    *ppTypeLib = NULL;
+
+    /* is it a DLL? */
+	for (i=0 ; i < nStrLen ; ++i)
+	{
+	    pszFileName[i] = tolower(pszFileName[i]);
+	}
+    pszTypeLibIndex = strstr(pszFileName, ".dll");
+
+    /* find if there's a back-slash after .DLL (good sign of the presence of a typelib index) */
+    if (pszTypeLibIndex)
+    {
+      pszTypeLibIndex = strstr(pszTypeLibIndex, "\\");
+    }
+
+    /* is there any thing after trailing back-slash  ? */
+    if (pszTypeLibIndex && pszTypeLibIndex < pszFileName + nStrLen)
+    {
+      /* yes -> it's a index! store DLL name, without the trailing back-slash */
+      size_t nMemToAlloc = pszTypeLibIndex - pszFileName;
+      
+      pszDllName = HeapAlloc(GetProcessHeap(),
+                          HEAP_ZERO_MEMORY, 
+                          nMemToAlloc + 1);
+                          
+      strncpy(pszDllName, pszFileName, nMemToAlloc);
+      
+      /* move index string pointer pass the backslash */
+      while (*pszTypeLibIndex == '\\')
+        ++pszTypeLibIndex;
+    }
+    else
+    {
+      /* No index, reset variable to 1 */
+      pszDllName = HeapAlloc(GetProcessHeap(),
+                          HEAP_ZERO_MEMORY, 
+                          nStrLen + 1);
+                          
+      strncpy(pszDllName, pszFileName, nStrLen);
+      
+      pszTypeLibIndex = "1\0";
+    }
+
+    TRACE("File name without index %s\n", pszDllName);
+    TRACE("Index of typelib %s\n",        pszTypeLibIndex);
+
+
+    /* check the signature of the file */
+    hFile = CreateFileA( pszDllName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, -1 );
+    if (INVALID_HANDLE_VALUE != hFile)
+    {
+      HANDLE hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL );
+      if (hMapping)
+      {
+        LPVOID pBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
+	if(pBase)
+	{
+	  /* first try to load as *.tlb */
+	  dwSignature = *((DWORD*) pBase);
+	  if ( dwSignature == MSFT_SIGNATURE)
+	  {
+            /* retrieve file size */
+            DWORD dwTLBLength = GetFileSize(hFile, NULL);
+
+	    *ppTypeLib = ITypeLib2_Constructor(pBase, dwTLBLength);
+	  }
+	  UnmapViewOfFile(pBase);
+	}
+	CloseHandle(hMapping);
+      }
+      CloseHandle(hFile);
+    }
+
+    if( (WORD)dwSignature == IMAGE_DOS_SIGNATURE )
+    {
+      /* find the typelibrary resource*/
+      HINSTANCE hinstDLL = LoadLibraryExA(pszDllName, 0, DONT_RESOLVE_DLL_REFERENCES|
+                                          LOAD_LIBRARY_AS_DATAFILE|LOAD_WITH_ALTERED_SEARCH_PATH);
+      if (hinstDLL)
+      {
+        HRSRC hrsrc = FindResourceA(hinstDLL, MAKEINTRESOURCEA(atoi(pszTypeLibIndex)), "TYPELIB");
+        if (hrsrc)
+        {
+          HGLOBAL hGlobal = LoadResource(hinstDLL, hrsrc);
+          if (hGlobal)
+          {
+            LPVOID pBase = LockResource(hGlobal);
+            DWORD  dwTLBLength = SizeofResource(hinstDLL, hrsrc);
+            
+            if (pBase)
+            {
+	      /* try to load as incore resource */
+	      dwSignature = *((DWORD*) pBase);
+	      if ( dwSignature == MSFT_SIGNATURE)
+		  *ppTypeLib = ITypeLib2_Constructor(pBase, dwTLBLength);
+	      else
+	        FIXME("Header type magic 0x%08lx not supported.\n",dwSignature);
+            }
+            FreeResource( hGlobal );
+          }
+        }
+        FreeLibrary(hinstDLL);
+      }
+    }
+
+	HeapFree(GetProcessHeap(), 0, pszDllName);
+
+    if(*ppTypeLib)
+      ret = S_OK;
+    else
+      ERR("Loading of typelib %s failed with error 0x%08lx\n", pszFileName, GetLastError());
+
+    return ret;
+}
+
+/*================== ITypeLib(2) Methods ===================================*/
+
+/****************************************************************************
+ *	ITypeLib2_Constructor
+ *
+ * loading a typelib from a in-memory image
+ */
+static ITypeLib2* ITypeLib2_Constructor(LPVOID pLib, DWORD dwTLBLength)
+{
+    TLBContext cx;
+    long lPSegDir;
+    TLB2Header tlbHeader;
+    TLBSegDir tlbSegDir;
+    ITypeLibImpl * pTypeLibImpl;
+
+    TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength);
+
+    pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl));
+    if (!pTypeLibImpl) return NULL;
+
+    ICOM_VTBL(pTypeLibImpl) = &tlbvt;
+    pTypeLibImpl->ref = 1;
+
+    /* get pointer to beginning of typelib data */
+    cx.pos = 0;
+    cx.oStart=0;
+    cx.mapping = pLib;
+    cx.pLibInfo = pTypeLibImpl;
+    cx.length = dwTLBLength;
+    
+    /* read header */
+    TLB_Read((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
+    TRACE("header:\n");
+    TRACE("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
+    if (memcmp(&tlbHeader.magic1,TLBMAGIC2,4)) {
+	FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
+	return NULL;
+    }
+    /* 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 */
+    TRACE("read segment directory (at %ld)\n",lPSegDir);
+    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("cannot find the table directory, ptr=0x%lx\n",lPSegDir);
+	HeapFree(GetProcessHeap(),0,pTypeLibImpl);
+	return NULL;
+    }
+
+    /* now fill our internal data */
+    /* TLIBATTR fields */
+    TLB_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
+    pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid;
+    pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
+    pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
+    pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
+    pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
+
+    /* name, eventually add to a hash table */
+    pTypeLibImpl->Name = TLB_ReadName(&cx, tlbHeader.NameOffset);
+
+    /* help info */
+    pTypeLibImpl->DocString = TLB_ReadString(&cx, tlbHeader.helpstring);
+    pTypeLibImpl->HelpFile = TLB_ReadString(&cx, tlbHeader.helpfile);
+
+    if( tlbHeader.varflags & HELPDLLFLAG)
+    {
+            int offset;
+            TLB_Read(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
+            pTypeLibImpl->HelpStringDll = TLB_ReadString(&cx, offset);
+    }
+
+    pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
+
+    /* custom data */
+    if(tlbHeader.CustomDataOffset >= 0)
+    {
+        pTypeLibImpl->ctCustData = TLB_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData);
+    }
+
+    /* fill in typedescriptions */
+    if(tlbSegDir.pTypdescTab.length > 0)
+    {
+        int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
+        INT16 td[4];
+        pTypeLibImpl->pTypeDesc = 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 */
+            pTypeLibImpl->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(&(pTypeLibImpl->pTypeDesc[i]),lptdesc)= & stndTypeDesc[td[2]];
+                else
+                    V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lptdesc)= & pTypeLibImpl->pTypeDesc[td[2]/8];
+            }
+	    else if(td[0] == VT_CARRAY)
+            {
+	        /* array descr table here */
+	        V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc) = (void *)((int) td[2]);  /* temp store offset in*/
+            }                             
+            else if(td[0] == VT_USERDEFINED)
+	    {
+                V_UNION(&(pTypeLibImpl->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(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
+            if(tlbSegDir.pArrayDescriptions.offset>0)
+	    {
+                TLB_Read(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc));
+                V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc) = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
+
+                if(td[1]<0)
+                    V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc)->tdescElem.vt = td[0] & VT_TYPEMASK;
+                else
+                    V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc)->tdescElem = stndTypeDesc[td[0]/8];
+
+                V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc)->cDims = td[2];
+
+                for(j = 0; j<td[2]; j++)
+		{
+                    TLB_Read(& V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc)->rgbounds[j].cElements, 
+                        sizeof(INT), &cx, DO_NOT_SEEK);
+                    TLB_Read(& V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc)->rgbounds[j].lLbound, 
+                        sizeof(INT), &cx, DO_NOT_SEEK);
+                }
+            }
+	    else
+	    {
+                V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc) = NULL;
+                ERR("didn't find array description data\n");
+            }
+        }
+    }
+
+    /* imported type libs */
+    if(tlbSegDir.pImpFiles.offset>0)
+    {
+        TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs);
+        int oGuid, offset = tlbSegDir.pImpFiles.offset;
+        UINT16 size;
+
+        while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
+	{
+            *ppImpLib = TLB_Alloc(sizeof(TLBImpLib));
+            (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset;
+            TLB_Read(&oGuid, sizeof(INT), &cx, offset);
+
+			TLB_Read(&(*ppImpLib)->lcid,          sizeof(LCID),   &cx, DO_NOT_SEEK);
+            TLB_Read(&(*ppImpLib)->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
+            TLB_Read(&(*ppImpLib)->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
+            TLB_Read(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
+
+            size >>= 2;
+            (*ppImpLib)->name = TLB_Alloc(size+1);
+            TLB_Read((*ppImpLib)->name, size, &cx, DO_NOT_SEEK);
+            TLB_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx);
+            offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & 0xfffffffc;
+
+            ppImpLib = &(*ppImpLib)->next;
+        }
+    }
+
+    /* type info's */
+    if(tlbHeader.nrtypeinfos >= 0 )
+    {
+        /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */
+        ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo);
+        int i;
+
+        for(i = 0; i<(int)tlbHeader.nrtypeinfos; i++)
+		{
+            *ppTI = TLB_DoTypeInfo(&cx, i, pTypeLibImpl);
+
+            ppTI = &((*ppTI)->next);
+            (pTypeLibImpl->TypeInfoCount)++;
+        }
+    }
+
+    TRACE("(%p)\n", pTypeLibImpl);
+    return (ITypeLib2*) pTypeLibImpl;
+}
+
+/* ITypeLib::QueryInterface
+ */
+static HRESULT WINAPI ITypeLib2_fnQueryInterface(
+	ITypeLib2 * iface,
+	REFIID riid,
+	VOID **ppvObject)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+
+    TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
+
+    *ppvObject=NULL;
+    if(IsEqualIID(riid, &IID_IUnknown) || 
+       IsEqualIID(riid,&IID_ITypeLib)||
+       IsEqualIID(riid,&IID_ITypeLib2))
+    {
+        *ppvObject = This;
+    }
+	
+    if(*ppvObject)
+    {
+        ITypeLib2_AddRef(iface);
+        TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
+        return S_OK;
+    }
+    TRACE("-- Interface: E_NOINTERFACE\n");
+    return E_NOINTERFACE;
+}
+
+/* ITypeLib::AddRef
+ */
+static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+
+    TRACE("(%p)->ref is %u\n",This, This->ref);
+
+    return ++(This->ref);
+}
+
+/* ITypeLib::Release
+ */
+static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+
+    TRACE("(%p)->(%u)\n",This, This->ref);
+
+    if (!--(This->ref))
+    {
+      /* fixme destroy child objects */
+
+      TRACE(" destroying ITypeLib(%p)\n",This);
+
+	  if (This->Name)
+	  {
+	 	  SysFreeString(This->Name);
+		  This->Name = NULL;
+	  }
+
+	  if (This->DocString)
+	  {
+		  SysFreeString(This->DocString);
+		  This->DocString = NULL;
+	  }
+
+	  if (This->HelpFile)
+	  {
+		  SysFreeString(This->HelpFile);
+		  This->HelpFile = NULL;
+	  }
+
+	  if (This->HelpStringDll)
+	  {
+		  SysFreeString(This->HelpStringDll);
+		  This->HelpStringDll = NULL;
+	  }
+	
+  	  ITypeInfo_Release((ITypeInfo*) This->pTypeInfo);
+      HeapFree(GetProcessHeap(),0,This);
+      return 0;
+    }
+    return This->ref;
+}
+
+/* ITypeLib::GetTypeInfoCount
+ * 
+ * Returns the number of type descriptions in the type library
+ */
+static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
+    return This->TypeInfoCount;
+}
+
+/* ITypeLib::GetTypeInfo
+ *
+ * retrieves the specified type description in the library.
+ */
+static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
+	ITypeLib2 *iface,
+	UINT index, 
+	ITypeInfo **ppTInfo)
+{
+    int i;
+    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeInfoImpl *pTLBTInfo = This->pTypeInfo;
+
+    TRACE("(%p)->(index=%d) \n",This, index);
+
+    if (!ppTInfo) return E_INVALIDARG;
+    
+    /* search element n in list */
+    for(i=0; i < index; i++)
+    {
+      pTLBTInfo = pTLBTInfo->next;
+      if (!pTLBTInfo)
+      {
+        TRACE("-- element not found\n");
+        return TYPE_E_ELEMENTNOTFOUND;
+      }
+    }	
+
+    *ppTInfo = (ITypeInfo *) pTLBTInfo;
+    ITypeInfo_AddRef(*ppTInfo);
+    TRACE("-- found (%p)\n",*ppTInfo);
+    return S_OK;
+}
+
+/* ITypeLibs::GetTypeInfoType
+ *
+ * Retrieves the type of a type description.
+ */
+static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
+	ITypeLib2 *iface,
+	UINT index,
+	TYPEKIND *pTKind)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    int i;
+    ITypeInfoImpl *pTInfo = This->pTypeInfo;
+
+    TRACE("(%p) index %d \n",This, index);
+
+    if(!pTKind) return E_INVALIDARG;
+    
+    /* search element n in list */
+    for(i=0; i < index; i++)
+    {
+      if(!pTInfo)
+      {
+        TRACE("-- element not found\n");
+        return TYPE_E_ELEMENTNOTFOUND;
+      }
+      pTInfo = pTInfo->next;
+    }
+
+    *pTKind = pTInfo->TypeAttr.typekind;
+    TRACE("-- found Type (%d)\n", *pTKind);
+    return S_OK;
+}
+
+/* ITypeLib::GetTypeInfoOfGuid
+ *
+ * Retrieves the type description that corresponds to the specified GUID.
+ *
+ */
+static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
+	ITypeLib2 *iface,
+	REFGUID guid,
+	ITypeInfo **ppTInfo)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeInfoImpl *ppTLBTInfo = This->pTypeInfo; /* head of list */
+
+    TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid));
+
+    /* serach linked list for guid */
+    while( !IsEqualIID(guid,&ppTLBTInfo->TypeAttr.guid) )
+    {
+      ppTLBTInfo = ppTLBTInfo->next;
+      if (!ppTLBTInfo)
+      {
+        /* end of list reached */
+	TRACE("-- element not found\n");
+	return TYPE_E_ELEMENTNOTFOUND;
+      }
+    }
+
+    TRACE("-- found (%p, %s)\n", ppTLBTInfo, debugstr_w(ppTLBTInfo->Name));
+
+    *ppTInfo = (ITypeInfo*)ppTLBTInfo;
+    ITypeInfo_AddRef(*ppTInfo);
+    return S_OK;
+}
+
+/* ITypeLib::GetLibAttr
+ *
+ * Retrieves the structure that contains the library's attributes.
+ *
+ */
+static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
+	ITypeLib2 *iface, 
+	LPTLIBATTR *ppTLibAttr)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    TRACE("(%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 ITypeLib2_fnGetTypeComp(
+	ITypeLib2 *iface,
+	ITypeComp **ppTComp)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    FIXME("(%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 ITypeLib2_fnGetDocumentation(
+	ITypeLib2 *iface,
+	INT index,
+	BSTR *pBstrName,
+	BSTR *pBstrDocString,
+	DWORD *pdwHelpContext, 
+	BSTR *pBstrHelpFile)
+{
+	ICOM_THIS( ITypeLibImpl, iface);
+    HRESULT result;
+    ITypeInfo *pTInfo;
+    TRACE("(%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=SysAllocString(This->Name);
+        if(pBstrDocString)
+            *pBstrDocString=SysAllocString(This->DocString);
+        if(pdwHelpContext)
+            *pdwHelpContext=This->dwHelpContext;
+        if(pBstrHelpFile)
+            *pBstrHelpFile=SysAllocString(This->HelpFile);
+    }else {/* for a typeinfo */
+        result=ITypeLib2_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 ITypeLib2_fnIsName(
+	ITypeLib2 *iface,
+	LPOLESTR szNameBuf,
+	ULONG lHashVal,
+	BOOL *pfName)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeInfoImpl *pTInfo;
+    TLBFuncDesc *pFInfo;
+    TLBVarDesc *pVInfo;
+    int i;
+    UINT nNameBufLen = SysStringLen(szNameBuf);
+
+    TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
+	  pfName);
+
+    *pfName=TRUE;
+    for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){
+        if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
+        for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
+            if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
+            for(i=0;i<pFInfo->funcdesc.cParams;i++)
+                if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen))
+                    goto ITypeLib2_fnIsName_exit;
+        }
+        for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next)
+            if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
+       
+    }
+    *pfName=FALSE;
+
+ITypeLib2_fnIsName_exit:
+    TRACE("(%p)slow! search for %s: %s found!\n", This,
+          debugstr_w(szNameBuf), *pfName?"NOT":"");
+    
+    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 ITypeLib2_fnFindName(
+	ITypeLib2 *iface,
+	LPOLESTR szNameBuf,
+	ULONG lHashVal,
+	ITypeInfo **ppTInfo,
+	MEMBERID *rgMemId,
+	UINT16 *pcFound)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    ITypeInfoImpl *pTInfo;
+    TLBFuncDesc *pFInfo;
+    TLBVarDesc *pVInfo;
+    int i,j = 0;
+   
+    UINT nNameBufLen = SysStringLen(szNameBuf);
+
+    for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){
+        if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
+        for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) {
+            if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit;
+            for(i=0;i<pFInfo->funcdesc.cParams;i++)
+                if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen))
+                    goto ITypeLib2_fnFindName_exit;
+        }
+        for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) ;
+            if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit;
+        continue;
+ITypeLib2_fnFindName_exit:
+        ITypeInfo_AddRef((ITypeInfo*)pTInfo);
+        ppTInfo[j]=(LPTYPEINFO)pTInfo;
+        j++;
+    }
+    TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n",
+          This, *pcFound, debugstr_w(szNameBuf), j);
+
+    *pcFound=j;
+    
+    return S_OK;
+}
+
+/* ITypeLib::ReleaseTLibAttr
+ *
+ * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
+ *
+ */
+static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
+	ITypeLib2 *iface,
+	TLIBATTR *pTLibAttr)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    TRACE("freeing (%p)\n",This);
+    /* nothing to do */
+}
+
+/* ITypeLib2::GetCustData
+ *
+ * gets the custom data
+ */
+static HRESULT WINAPI ITypeLib2_fnGetCustData(
+	ITypeLib2 * iface,
+	REFGUID guid, 
+        VARIANT *pVarVal)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    TLBCustData *pCData;
+
+    for(pCData=This->pCustData; pCData; pCData = pCData->next)
+    {
+      if( IsEqualIID(guid, &pCData->guid)) break;
+    }
+    
+    TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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(
+	ITypeLib2 * iface, 
+        ULONG *pcUniqueNames,
+	ULONG *pcchUniqueNames)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+
+    FIXME("(%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(
+	ITypeLib2 * iface, 
+        INT index,
+	LCID lcid,
+	BSTR *pbstrHelpString,
+        DWORD *pdwHelpStringContext,
+	BSTR *pbstrHelpStringDll)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    HRESULT result;
+    ITypeInfo *pTInfo;
+
+    FIXME("(%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=SysAllocString(This->DocString);
+      if(pdwHelpStringContext)
+        *pdwHelpStringContext=This->dwHelpContext;
+      if(pbstrHelpStringDll)
+        *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
+    }
+    else
+    {
+      /* for a typeinfo */
+      result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
+      if(SUCCEEDED(result))
+      {	
+	ITypeInfo2 * pTInfo2;
+	result = ITypeInfo_QueryInterface(pTInfo, &IID_ITypeInfo2, (LPVOID*) &pTInfo2);
+	if(SUCCEEDED(result))
+	{
+          result = ITypeInfo2_GetDocumentation2(pTInfo2, MEMBERID_NIL, lcid,
+                pbstrHelpString, pdwHelpStringContext, pbstrHelpStringDll);
+          ITypeInfo2_Release(pTInfo2);
+	}
+        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(
+	ITypeLib2 * iface,
+        CUSTDATA *pCustData)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+    TLBCustData *pCData;
+    int i;
+    TRACE("(%p) returning %d items\n", This, This->ctCustData); 
+    pCustData->prgCustData = 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(" OUT OF MEMORY! \n");
+        return E_OUTOFMEMORY;
+    }
+    return S_OK;
+}
+
+static ICOM_VTABLE(ITypeLib2) tlbvt = {
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    ITypeLib2_fnQueryInterface,
+    ITypeLib2_fnAddRef,
+    ITypeLib2_fnRelease,
+    ITypeLib2_fnGetTypeInfoCount,
+    ITypeLib2_fnGetTypeInfo,
+    ITypeLib2_fnGetTypeInfoType,
+    ITypeLib2_fnGetTypeInfoOfGuid,
+    ITypeLib2_fnGetLibAttr,
+    ITypeLib2_fnGetTypeComp,
+    ITypeLib2_fnGetDocumentation,
+    ITypeLib2_fnIsName,
+    ITypeLib2_fnFindName,
+    ITypeLib2_fnReleaseTLibAttr,
+
+    ITypeLib2_fnGetCustData,
+    ITypeLib2_fnGetLibStatistics,
+    ITypeLib2_fnGetDocumentation2,
+    ITypeLib2_fnGetAllCustData
+ };
+
+/*================== ITypeInfo(2) Methods ===================================*/
+static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void)
+{
+    ITypeInfoImpl * pTypeInfoImpl;
+
+    pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl));
+    if (pTypeInfoImpl)
+    {
+      ICOM_VTBL(pTypeInfoImpl) = &tinfvt;
+      pTypeInfoImpl->ref=1;
+    }
+    TRACE("(%p)\n", pTypeInfoImpl);
+    return (ITypeInfo2*) pTypeInfoImpl;
+}
+
+/* ITypeInfo::QueryInterface
+ */
+static HRESULT WINAPI ITypeInfo_fnQueryInterface(
+	ITypeInfo2 *iface,
+	REFIID riid,
+	VOID **ppvObject)
+{
+    ICOM_THIS( ITypeLibImpl, iface);
+
+    TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
+
+    *ppvObject=NULL;
+    if(IsEqualIID(riid, &IID_IUnknown) || 
+            IsEqualIID(riid,&IID_ITypeInfo)||
+            IsEqualIID(riid,&IID_ITypeInfo2))
+        *ppvObject = This;
+
+    if(*ppvObject){
+        ITypeInfo_AddRef(iface);
+        TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
+        return S_OK;
+    }
+    TRACE("-- Interface: E_NOINTERFACE\n");
+    return E_NOINTERFACE;
+}
+
+/* ITypeInfo::AddRef
+ */
+static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TRACE("(%p)->ref is %u\n",This, This->ref);
+    return ++(This->ref);
+}
+
+/* ITypeInfo::Release
+ */
+static ULONG WINAPI ITypeInfo_fnRelease( ITypeInfo2 *iface)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TRACE("(%p)->(%u)\n",This, This->ref);
+
+	
+    if (!--(This->ref))
+    {
+      FIXME("destroy child objects\n");
+
+      TRACE(" destroying ITypeInfo(%p)\n",This); 
+	  if (This->Name)
+	  {
+		  SysFreeString(This->Name);
+		  This->Name = 0;
+	  }
+	  
+	  if (This->DocString)
+	  {
+	      SysFreeString(This->DocString);
+		  This->DocString = 0;
+	  }
+
+	  if (This->next)
+	  {
+		ITypeInfo_Release((ITypeInfo*)This->next);
+	  }
+
+      HeapFree(GetProcessHeap(),0,This);
+      return 0;
+    }
+    return This->ref;
+}
+
+/* ITypeInfo::GetTypeAttr
+ *
+ * Retrieves a TYPEATTR structure that contains the attributes of the type
+ * description.
+ *
+ */
+static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
+        LPTYPEATTR  *ppTypeAttr)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TRACE("(%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( ITypeInfo2 *iface,
+        ITypeComp  * *ppTComp)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    FIXME("(%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( ITypeInfo2 *iface, UINT index,
+        LPFUNCDESC  *ppFuncDesc)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    int i;
+    TLBFuncDesc * pFDesc; 
+    TRACE("(%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( ITypeInfo2 *iface, UINT index,
+        LPVARDESC  *ppVarDesc)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    int i;
+    TLBVarDesc * pVDesc; 
+    TRACE("(%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( ITypeInfo2 *iface, MEMBERID memid,
+        BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TLBFuncDesc * pFDesc; 
+    TLBVarDesc * pVDesc; 
+    int i;
+    TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames);
+    for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; 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=SysAllocString(pFDesc->Name);
+        else
+          rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
+      }
+      *pcNames=i;
+    }
+    else
+    {
+      for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next);
+      if(pVDesc)
+      {
+        *rgBstrNames=SysAllocString(pVDesc->Name);
+        *pcNames=1;
+      }
+      else
+      {
+        if(This->TypeAttr.typekind==TKIND_INTERFACE && This->TypeAttr.cImplTypes )
+        {
+          /* recursive search */
+          ITypeInfo *pTInfo;
+          HRESULT result;
+          result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->reference, &pTInfo);
+          if(SUCCEEDED(result))
+	  {
+            result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
+            ITypeInfo_Release(pTInfo);
+            return result;
+          }
+          WARN("Could not search inherited interface!\n");
+        }
+        else
+	{
+          WARN("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(
+	ITypeInfo2 *iface,
+        UINT index,
+	HREFTYPE  *pRefType)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    int(i);
+    TLBRefType *pIref = This->impltypelist;
+
+    TRACE("(%p) index %d\n", This, index);
+    dump_TypeInfo(This);
+
+
+    if(index==(UINT)-1)
+    {
+      /* only valid on dual interfaces;
+         retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
+      */
+      if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
+      
+      if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE &&
+          This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL )
+      {
+        *pRefType = -1;
+      }
+      else
+      {
+        *pRefType = pIref->reference;
+      }
+    }
+    else
+    {
+      /* get element n from linked list */
+      for(i=0; i<index; i++)
+      {
+        if (!pIref) return TYPE_E_ELEMENTNOTFOUND;
+        pIref = pIref->next;
+      }
+      
+      *pRefType = pIref->reference;
+    }
+    
+    TRACE("-- 0x%08lx %s\n",pIref->reference, debugstr_guid(&pIref->guid) );
+    return S_OK;
+   
+}
+
+/* ITypeInfo::GetImplTypeFlags
+ * 
+ * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface 
+ * or base interface in a type description.
+ */
+static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
+        UINT index, INT  *pImplTypeFlags)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    int(i);
+    TLBRefType *pIref;
+    TRACE("(%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( ITypeInfo2 *iface,
+        LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TLBFuncDesc * pFDesc; 
+    TLBVarDesc * pVDesc; 
+    HRESULT ret=S_OK;
+	UINT nNameLen = SysStringLen(*rgszNames);
+	
+    TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
+            cNames);
+    for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) {
+        int i, j;
+        if( !memcmp(*rgszNames, pFDesc->Name, nNameLen)) {
+            if(cNames) *pMemId=pFDesc->funcdesc.memid;
+            for(i=1; i < cNames; i++){
+				UINT nParamLen = SysStringLen(rgszNames[i]);
+                for(j=0; j<pFDesc->funcdesc.cParams; j++)
+                    if(memcmp(rgszNames[i],pFDesc->pParamDesc[j].Name, nParamLen))
+                            break;
+                if( j<pFDesc->funcdesc.cParams)
+                    pMemId[i]=j;
+                else
+                   ret=DISP_E_UNKNOWNNAME;
+            };
+            return ret;
+        }
+    }   
+    for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) {
+        if( !memcmp(*rgszNames, pVDesc->Name, nNameLen)) {
+            if(cNames) *pMemId=pVDesc->vardesc.memid;
+            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=ITypeInfo_GetRefTypeInfo(iface, 
+                This->impltypelist->reference, &pTInfo);
+        if(SUCCEEDED(ret)){
+            ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
+            ITypeInfo_Release(pTInfo);
+            return ret;
+        }
+        WARN("Could not search inherited interface!\n");
+    } else
+        WARN("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(
+	ITypeInfo2 *iface,
+	VOID  *pIUnk,
+        MEMBERID memid,
+	UINT16 dwFlags,
+	DISPPARAMS  *pDispParams,
+        VARIANT  *pVarResult,
+	EXCEPINFO  *pExcepInfo,
+	UINT  *pArgErr)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    FIXME("(%p)(%p,id=0x%08lx,0x%08x,%p,%p,%p,%p) stub!\n",
+      This, pIUnk, memid, dwFlags, pDispParams, pVarResult, pExcepInfo, pArgErr );
+    dump_DispParms(pDispParams);
+    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( ITypeInfo2 *iface,
+        MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
+        DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TLBFuncDesc * pFDesc; 
+    TLBVarDesc * pVDesc; 
+    TRACE("(%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=SysAllocString(This->Name);
+        if(pBstrDocString)
+            *pBstrDocString=SysAllocString(This->DocString);
+        if(pdwHelpContext)
+            *pdwHelpContext=This->dwHelpContext;
+        if(pBstrHelpFile)
+            *pBstrHelpFile=SysAllocString(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( ITypeInfo2 *iface, MEMBERID memid,
+        INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
+        WORD  *pwOrdinal)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    FIXME("(%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(
+	ITypeInfo2 *iface,
+        HREFTYPE hRefType,
+	ITypeInfo  **ppTInfo)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    HRESULT result = E_FAIL;
+
+    if(HREFTYPE_INTHISFILE(hRefType))
+    {
+      ITypeLib *pTLib;
+      int Index;
+      result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
+      if(SUCCEEDED( result ))
+      {
+        result=ITypeLib2_GetTypeInfo(pTLib, HREFTYPE_INDEX(hRefType), ppTInfo);
+        ITypeLib2_Release(pTLib );
+      }
+    }
+	else if (hRefType == -1 && 
+             (((ITypeInfoImpl*) This)->TypeAttr.typekind   == TKIND_DISPATCH) &&
+             (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
+    {
+	  /* when we meet a DUAL dispinterface, we must create the interface 
+	  * version of it.
+	  */
+	  ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor();
+
+		
+	  /* the interface version contains the same information as the dispinterface
+	   * copy the contents of the structs.
+	   */
+	  *pTypeInfoImpl = *This;
+	  pTypeInfoImpl->ref = 1;
+		
+	  /* change the type to interface */
+	  pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
+		
+      *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
+
+	  ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl);
+
+      result = S_OK;
+	}
+    else
+    {
+      /* imported type lib */
+      TLBRefType   *pRefType     = NULL;
+      
+      /* search in implemented types */
+      for( pRefType = This->impltypelist; 
+           pRefType && (pRefType->reference != hRefType);
+           pRefType = pRefType->next);
+      
+      if(!pRefType)
+      {                       
+        TYPEATTR*       pMyTypeAttr  = &This->TypeAttr;
+        unsigned short  cFuncs       = pMyTypeAttr->cFuncs;
+        unsigned short  cVars        = pMyTypeAttr->cVars;
+        
+        /* search in arguments */      
+        if (cFuncs > 0)
+        {
+          unsigned short  cFuncIndex   = 0;
+  
+          TLBFuncDesc*    pCurrFunc    = This->funclist;
+          
+          for (cFuncIndex = 0; !pRefType && cFuncIndex < cFuncs ; ++cFuncIndex)
+          {
+            FUNCDESC*  pCurrFuncDesc = &pCurrFunc->funcdesc;
+            
+            short      cParams       = pCurrFuncDesc->cParams;
+            short      cParamIndex   = 0;
+              
+            for (cParamIndex = 0 ; 
+                 !pRefType && cParamIndex < cParams ; 
+                 ++cParamIndex)
+            {
+              TLBParDesc* pCurrParamDesc = &(pCurrFunc->pParamDesc[cParamIndex]);
+             
+              if ( pCurrParamDesc->pRefType && pCurrParamDesc->pRefType->reference == hRefType)
+              {
+                pRefType = pCurrParamDesc->pRefType;
+                break; /* also break from outer loop since pRefType != 0 */
+              }
+            }
+            
+            pCurrFunc = pCurrFunc->next;
+          }
+        }
+        /* search in variables */
+        else if (cVars > 0)
+        {
+          FIXME("search hreftype in variables, if any\n");
+          result = E_INVALIDARG; // FIXME : correct?
+        }
+      }
+      
+      /* href-referenced typeinfo found! */
+      if (pRefType || hRefType == -1)
+      {
+        ITypeLibImpl *pTypeLib = pRefType->pImpTLInfo->pImpTypeLib;
+        
+        if(pTypeLib) 
+        {
+          TRACE("typeinfo in imported typelib that is already loaded\n");
+          
+          result = ITypeLib2_GetTypeInfoOfGuid((LPTYPELIB)pTypeLib, 
+                                           &pRefType->guid, 
+                                           ppTInfo);
+        }
+        else
+        {
+          result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid,
+                      pRefType->pImpTLInfo->wVersionMajor,
+                      pRefType->pImpTLInfo->wVersionMinor,
+                      pRefType->pImpTLInfo->lcid,
+                      (LPTYPELIB *)&pTypeLib);
+          
+          if(!SUCCEEDED(result))
+	  	  {
+            BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name);
+            TRACE("typeinfo in imported typelib that isn't already loaded\n");
+            result=LoadTypeLib(libnam, (LPTYPELIB *)&pTypeLib);
+            SysFreeString(libnam);
+          } 
+          if(SUCCEEDED(result))
+          {
+            result=ITypeLib2_GetTypeInfoOfGuid((LPTYPELIB)pTypeLib, &pRefType->guid, ppTInfo);
+            pRefType->pImpTLInfo->pImpTypeLib = pTypeLib;
+			ITypeLib2_AddRef((ITypeLib*) pTypeLib);
+          }        
+        }
+      }
+    }
+
+    TRACE("(%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( ITypeInfo2 *iface,
+        MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    FIXME("(%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( ITypeInfo2 *iface, 
+        IUnknown *pUnk, REFIID riid, VOID  **ppvObj) 
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    FIXME("(%p) stub!\n", This);
+    return S_OK;
+}
+
+/* ITypeInfo::GetMops
+ *
+ * Retrieves marshaling information.
+ */
+static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
+				BSTR  *pBstrMops)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    FIXME("(%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( ITypeInfo2 *iface,
+        ITypeLib  * *ppTLib, UINT  *pIndex)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    if (!pIndex)
+        return E_INVALIDARG;
+    *ppTLib=(LPTYPELIB )(This->pTypeLib);
+    *pIndex=This->index;
+    ITypeLib2_AddRef(*ppTLib);
+    TRACE("(%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( ITypeInfo2 *iface,
+        TYPEATTR* pTypeAttr)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TRACE("(%p)->(%p)\n", This, pTypeAttr);
+    return S_OK;
+}
+
+/* ITypeInfo::ReleaseFuncDesc
+ *
+ * Releases a FUNCDESC previously returned by GetFuncDesc. *
+ */
+static HRESULT WINAPI ITypeInfo_fnReleaseFuncDesc(
+	ITypeInfo2 *iface,
+        FUNCDESC *pFuncDesc)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TRACE("(%p)->(%p)\n", This, pFuncDesc);
+    return S_OK;
+}
+
+/* ITypeInfo::ReleaseVarDesc
+ *
+ * Releases a VARDESC previously returned by GetVarDesc.
+ */
+static HRESULT WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
+        VARDESC *pVarDesc)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TRACE("(%p)->(%p)\n", This, pVarDesc);
+    return S_OK;
+}
+
+/* ITypeInfo2::GetTypeKind
+ *
+ * Returns the TYPEKIND enumeration quickly, without doing any allocations.
+ *
+ */
+static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
+    TYPEKIND *pTypeKind)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    *pTypeKind=This->TypeAttr.typekind;
+    TRACE("(%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( ITypeInfo2 * iface,
+    UINT *pTypeFlags)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    *pTypeFlags=This->TypeAttr.wTypeFlags;
+    TRACE("(%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( ITypeInfo2 * iface,
+    MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
+{
+    ICOM_THIS( ITypeInfoImpl, 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("(%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( ITypeInfo2 * iface,
+    MEMBERID memid, UINT *pVarIndex)
+{
+    ICOM_THIS( ITypeInfoImpl, 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("(%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(
+	ITypeInfo2 * iface,
+	REFGUID guid,
+	VARIANT *pVarVal)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TLBCustData *pCData;
+
+    for(pCData=This->pCustData; pCData; pCData = pCData->next)
+        if( IsEqualIID(guid, &pCData->guid)) break;
+
+    TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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(
+	ITypeInfo2 * iface,
+	UINT index,
+	REFGUID guid,
+	VARIANT *pVarVal)
+{
+    ICOM_THIS( ITypeInfoImpl, 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;
+
+    TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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(
+	ITypeInfo2 * iface,
+	UINT indexFunc,
+	UINT indexParam,
+	REFGUID guid,
+	VARIANT *pVarVal)
+{   
+    ICOM_THIS( ITypeInfoImpl, 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;
+
+    TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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(
+	ITypeInfo2 * iface,
+	UINT index,
+	REFGUID guid,
+	VARIANT *pVarVal)
+{   
+    ICOM_THIS( ITypeInfoImpl, 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;
+      }
+    }
+
+    TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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(
+	ITypeInfo2 * iface,
+	UINT index,
+	REFGUID guid,
+	VARIANT *pVarVal)
+{   
+    ICOM_THIS( ITypeInfoImpl, 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;
+      }
+    }
+    
+    TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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(
+	ITypeInfo2 * iface,
+	MEMBERID memid,
+	LCID lcid,
+	BSTR *pbstrHelpString,
+	DWORD *pdwHelpStringContext,
+	BSTR *pbstrHelpStringDll)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TLBFuncDesc * pFDesc; 
+    TLBVarDesc * pVDesc; 
+    TRACE("(%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=SysAllocString(This->Name);
+        if(pdwHelpStringContext)
+            *pdwHelpStringContext=This->dwHelpStringContext;
+        if(pbstrHelpStringDll)
+            *pbstrHelpStringDll=
+                SysAllocString(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=SysAllocString(pFDesc->HelpString);
+            if(pdwHelpStringContext)
+                *pdwHelpStringContext=pFDesc->HelpStringContext;
+            if(pbstrHelpStringDll)
+                *pbstrHelpStringDll=
+                    SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
+        return S_OK;
+    }
+    for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next)
+        if(pVDesc->vardesc.memid==memid){
+             if(pbstrHelpString)
+                *pbstrHelpString=SysAllocString(pVDesc->HelpString);
+            if(pdwHelpStringContext)
+                *pdwHelpStringContext=pVDesc->HelpStringContext;
+            if(pbstrHelpStringDll)
+                *pbstrHelpStringDll=
+                    SysAllocString(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(
+	ITypeInfo2 * iface,
+	CUSTDATA *pCustData)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TLBCustData *pCData;
+    int i;
+
+    TRACE("(%p) returning %d items\n", This, This->ctCustData); 
+
+    pCustData->prgCustData = 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(" 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(
+	ITypeInfo2 * iface,
+	UINT index,
+	CUSTDATA *pCustData)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TLBCustData *pCData;
+    TLBFuncDesc * pFDesc; 
+    int i;
+    TRACE("(%p) index %d\n", This, index); 
+    for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++,
+            pFDesc=pFDesc->next)
+        ;
+    if(pFDesc){
+        pCustData->prgCustData =
+            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(" 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( ITypeInfo2 * iface,
+    UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TLBCustData *pCData=NULL;
+    TLBFuncDesc * pFDesc; 
+    int i;
+    TRACE("(%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 = 
+            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(" 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( ITypeInfo2 * iface,
+    UINT index, CUSTDATA *pCustData)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TLBCustData *pCData;
+    TLBVarDesc * pVDesc; 
+    int i;
+    TRACE("(%p) index %d\n", This, index); 
+    for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++,
+            pVDesc=pVDesc->next)
+        ;
+    if(pVDesc){
+        pCustData->prgCustData =
+            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(" 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(
+	ITypeInfo2 * iface,
+	UINT index,
+	CUSTDATA *pCustData)
+{
+    ICOM_THIS( ITypeInfoImpl, iface);
+    TLBCustData *pCData;
+    TLBRefType * pRDesc; 
+    int i;
+    TRACE("(%p) index %d\n", This, index); 
+    for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++,
+            pRDesc=pRDesc->next)
+        ;
+    if(pRDesc){
+        pCustData->prgCustData =
+            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(" OUT OF MEMORY! \n");
+            return E_OUTOFMEMORY;
+        }
+        return S_OK;
+    }
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+static ICOM_VTABLE(ITypeInfo2) tinfvt = 
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+
+    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,
+};
Index: trunk/src/oleaut32/typelib.cpp
===================================================================
--- trunk/src/oleaut32/typelib.cpp	(revision 4830)
+++ 	(revision )
@@ -1,1982 +1,0 @@
-/* $Id: typelib.cpp,v 1.15 2000-09-17 22:31:41 davidr Exp $ */
-/* 
- * ITypelib interface
- * 
- * 1/12/99
- * 
- * Copyright 1999 David J. Raison
- * Some portions based on original work on Wine
- *   Copyright 1997 Marcus Meissner
- 	       1999 Rein Klazes
- * 
- * Project Odin Software License can be found in LICENSE.TXT
- *
- * NB: Logging from this module is piped into TLIB_n.LOG via
- * the private logging interface.
- */
-
-typedef enum tagREGKIND
-{
-    REGKIND_DEFAULT,
-    REGKIND_REGISTER,
-    REGKIND_NONE
-} REGKIND;
-
-#define PRIVATE_LOGGING	// Private logfile
-#define DEBUG2
-
-#include "oleaut32.h"
-#include "olectl.h"
-#include "oList.h"	// linked list template
-#include "itypelib.h"
-
-static FILE *_privateLogFile = NULL;
-
-// ----------------------------------------------------------------------
-// OpenPrivateLogFileTypelib
-// ----------------------------------------------------------------------
-void OpenPrivateLogFileTypelib()
-{
-#ifdef DEBUG
-    char logname[1024];
-
-    sprintf(logname, "tlib_%d.log", loadNr);
-    _privateLogFile = fopen(logname, "w");
-    if(_privateLogFile == NULL)
-    {
-	sprintf(logname, "%stlib_%d.log", oleaut32Path, loadNr);
-	_privateLogFile = fopen(logname, "w");
-    }
-    dprintfGlobal(("TLIB LOGFILE : %s", logname));
-#endif
-}
-
-// ----------------------------------------------------------------------
-// ClosePrivateLogFileTypelib
-// ----------------------------------------------------------------------
-void ClosePrivateLogFileTypelib()
-{
-#ifdef DEBUG
-    if(_privateLogFile)
-    {
-	fclose(_privateLogFile);
-	_privateLogFile = NULL;
-    }
-#endif
-}
-
-// ======================================================================
-// Local Data
-// ======================================================================
-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}
-};
-
-// ======================================================================
-// Public API's
-// ======================================================================
-
-// ----------------------------------------------------------------------
-// QueryPathOfRegTypeLib()				[OLEAUT32.164]
-//
-// Retrieves the path of a registered type library.
-// ----------------------------------------------------------------------
-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];
-    char	pathname[260];
-    DWORD	plen;
-
-    dprintfGlobal(("OLEAUT32: QueryPathOfRegTypeLib()"));
-
-    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);
-	dprintfGlobal(("OLEAUT32: QueryPathOfRegTypeLib(%s,%d,%d,0x%04lx,%p) - stub!",
-	    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);
-
-	dprintfGlobal(("OLEAUT32: QueryPathOfRegTypeLib() - key \"%s\" not found", typelibkey));
-	return E_FAIL;
-    }
-    *path = HEAP_strdupAtoW(GetProcessHeap(), 0, pathname);
-    return S_OK;
-}
-
-// ----------------------------------------------------------------------
-// LoadTypeLibEx()					[OLEAUT32.183]
-//
-// Loads a type library & optionally registers it in the system registry.
-// * If file is a standalone type library - load it directly.
-// * If the file is a DLL or EXE then load the module, and extract the TYPELIB
-//   resource from it. The default is the first TYPELIB resource - subsequent
-//   TYPELIBs may be accessed by appending an integer index to szFile
-// * If neither of the above, the library is parsed into a filebased Moniker. 
-//   No idea of what/when/where/how to do this yet ;-)
-//
-// If the library (guid, etc) is already loaded return the loaded ITypeLib
-// and incr. its ref count.
-// ----------------------------------------------------------------------
-HRESULT WINAPI LoadTypeLibEx(
-    LPCOLESTR		szFile,
-    REGKIND		regkind,
-    ITypeLib * *	ppTlib)
-{
-    HANDLE		hHeap = GetProcessHeap();
-    char *		szFileA;
-    HRESULT		rc;
-
-    szFileA = HEAP_strdupWtoA(hHeap, 0, szFile);
-    dprintfGlobal(("OLEAUT32: LoadTypeLibEx(%s)", szFileA));
-
-    // Sanity check...
-    if (ppTlib == 0)
-    {
-	HeapFree(hHeap, 0, szFileA);
-    	return E_POINTER;
-    }
-
-    *ppTlib = 0;
-
-    TypeLibExtract	extractor(szFileA);
-
-    if (!extractor.Valid())
-    {
-	HeapFree(hHeap, 0, szFileA);
-	dprintfGlobal(("  Invalid typelib file"));
-	return E_FAIL;
-    }
-
-    rc = extractor.MakeITypeLib((ITypeLibImpl * *)ppTlib);
-
-    HeapFree(hHeap, 0, szFileA); 
-
-    return rc;
-}
-
-// ----------------------------------------------------------------------
-// LoadTypeLib()					[OLEAUT32.161]
-//
-// Loads a type library & registers it in the system registry.
-// ----------------------------------------------------------------------
-HRESULT WINAPI LoadTypeLib(
-    LPCOLESTR		szFile,		/* [in] Name of file to load from */
-    ITypeLib * *	ppTLib)		/* [out] Pointer to pointer to loaded type library */
-{
-    HRESULT		res;
-
-    dprintfGlobal(("OLEAUT32: LoadTypeLib()"));
-
-    return LoadTypeLibEx(szFile, REGKIND_DEFAULT, ppTLib);
-}
-
-// ----------------------------------------------------------------------
-// LoadRegTypeLib()					[OLEAUT32.162]
-//
-// Use system registry information to locate and load a type library.
-// ----------------------------------------------------------------------
-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;
-
-    dprintfGlobal(("OLEAUT32: LoadRegTypeLib()"));
-
-    res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
-
-    if (SUCCEEDED(res))
-    {
-        res = LoadTypeLibEx(bstr, REGKIND_NONE, ppTLib);
-        SysFreeString(bstr);
-    }
-
-    return res;
-}
-
-// ----------------------------------------------------------------------
-// RegisterTypeLib()					[OLEAUT32.163]
-//
-// Adds information about a type library to the System Registry
-// ----------------------------------------------------------------------
-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*/
-{
-    dprintfGlobal(("OLEAUT32: RegisterTypeLib() - stub\n"));
-
-    return S_OK;	/* FIXME: pretend everything is OK */
-}
-
-// ----------------------------------------------------------------------
-// UnRegisterTypeLib()					[OLEAUT32.186]
-// 
-// Removes information about a type library from the System Registry
-// ----------------------------------------------------------------------
-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)
-{
-    dprintfGlobal(("OLEAUT32: UnRegisterTypeLib() - stub"));
-
-    return S_OK;	/* FIXME: pretend everything is OK */
-}
-
-// ======================================================================
-// Local functions.
-// ======================================================================
-
-#if defined(DEBUG2)
-
-// ----------------------------------------------------------------------
-// dprintfLine2
-// ----------------------------------------------------------------------
-static void dprintfLine2(void)
-{
-    dprintf((LOG, "========================================"));
-}
-
-// ----------------------------------------------------------------------
-// dprintfLine
-// ----------------------------------------------------------------------
-static void dprintfLine(void)
-{
-    dprintf((LOG, "----------------------------------------"));
-}
-
-// ----------------------------------------------------------------------
-// TypeKindAsString
-// ----------------------------------------------------------------------
-char * TypeKindAsString(int typekind)
-{
-    char *	p;
-    switch (typekind)
-    {
-	case TKIND_ENUM: p = "TKIND_ENUM"; break;
-	case TKIND_RECORD: p = "TKIND_RECORD"; break;
-	case TKIND_MODULE: p = "TKIND_MODULE"; break;
-	case TKIND_INTERFACE: p = "TKIND_INTERFACE"; break;
-	case TKIND_DISPATCH: p = "TKIND_DISPATCH"; break;
-	case TKIND_COCLASS: p = "TKIND_COCLASS"; break;
-	case TKIND_ALIAS: p = "TKIND_ALIAS"; break;
-	case TKIND_UNION: p = "TKIND_UNION"; break;
-	case TKIND_MAX: p = "TKIND_MAX"; break;
-	default: p = "*UNKNOWN*"; break;
-    }
-    return p;
-}
-
-// ----------------------------------------------------------------------
-// FuncKindAsString
-// ----------------------------------------------------------------------
-char * FuncKindAsString(int funckind)
-{
-    char *	p;
-    switch (funckind)
-    {
-	case FUNC_VIRTUAL: p = "FUNC_VIRTUAL"; break;
-	case FUNC_PUREVIRTUAL: p = "FUNC_PUREVIRTUAL"; break;
-	case FUNC_NONVIRTUAL: p = "FUNC_NONVIRTUAL"; break;
-	case FUNC_STATIC: p = "FUNC_STATIC"; break;
-	case FUNC_DISPATCH: p = "FUNC_DISPATCH"; break;
-	default: p = "*UNKNOWN*"; break;
-    }
-    return p;
-}
-
-// ----------------------------------------------------------------------
-// InvKindAsString
-// ----------------------------------------------------------------------
-char * InvKindAsString(int invkind)
-{
-    char *	p;
-    switch (invkind)
-    {
-	case INVOKE_FUNC: p = "INVOKE_FUNC"; break;
-	case INVOKE_PROPERTYGET: p = "INVOKE_PROPERTYGET"; break;
-	case INVOKE_PROPERTYPUT: p = "INVOKE_PROPERTYPUT"; break;
-	case INVOKE_PROPERTYPUTREF: p = "INVOKE_PROPERTYPUTREF"; break;
-	default: p = "*UNKNOWN*"; break;
-    }
-    return p;
-}
-
-// ----------------------------------------------------------------------
-// VarKindAsString
-// ----------------------------------------------------------------------
-char * VarKindAsString(int varkind)
-{
-    char *	p;
-    switch (varkind)
-    {
-	case VAR_PERINSTANCE: p = "VAR_PERINSTANCE"; break;
-	case VAR_STATIC: p = "VAR_STATIC"; break;
-	case VAR_CONST: p = "VAR_CONST"; break;
-	case VAR_DISPATCH: p = "VAR_DISPATCH"; break;
-	default: p = "*UNKNOWN*"; break;
-    }
-    return p;
-}
-
-// ----------------------------------------------------------------------
-// CallConvAsString
-// ----------------------------------------------------------------------
-char * CallConvAsString(int callconv)
-{
-    char *	p;
-    switch (callconv)
-    {
-	case CC_CDECL: p = "CC_CDECL"; break; 
-//	case CC_MSCPASCAL: p = "CC_MSCPASCAL"; break; 
-	case CC_PASCAL: p = "CC_PASCAL"; break; 
-	case CC_MACPASCAL: p = "CC_MACPASCAL"; break; 
-	case CC_STDCALL: p = "CC_STDCALL"; break; 
-	case CC_RESERVED: p = "CC_RESERVED"; break; 
-	case CC_SYSCALL: p = "CC_SYSCALL"; break; 
-	case CC_MPWCDECL: p = "CC_MPWCDECL"; break; 
-	case CC_MPWPASCAL: p = "CC_MPWPASCAL"; break; 
-	case CC_MAX: p = "CC_MAX"; break; 
-
-	default: p = "*UNKNOWN*"; break;
-    }
-    return p;
-}
-
-// ----------------------------------------------------------------------
-// VariantAsString
-// ----------------------------------------------------------------------
-char * VariantTypeAsString(int vt)
-{
-    char *	p;
-
-    switch(vt & VT_TYPEMASK)
-    {
-	case VT_EMPTY: p = "VT_EMPTY"; break;
-	case VT_NULL: p = "VT_NULL"; break;
-	case VT_I2: p = "VT_I2"; break;
-	case VT_I4: p = "VT_I4"; break;
-	case VT_R4: p = "VT_R4"; break;
-	case VT_ERROR: p = "VT_ERROR"; break;
-	case VT_BOOL: p = "VT_BOOL"; break;
-	case VT_I1: p = "VT_I1"; break;
-	case VT_UI1: p = "VT_UI1"; break;
-	case VT_UI2: p = "VT_UI2"; break;
-	case VT_UI4: p = "VT_UI4"; break;
-	case VT_INT: p = "VT_INT"; break;
-	case VT_UINT: p = "VT_UINT"; break;
-	case VT_VOID: p = "VT_VOID"; break;
-	case VT_HRESULT: p = "VT_HRESULT"; break;
-	case VT_R8: p = "VT_R8"; break;
-	case VT_CY: p = "VT_CY"; break;
-	case VT_DATE: p = "VT_DATE"; break;
-	case VT_I8: p = "VT_I8"; break;
-	case VT_UI8: p = "VT_UI8"; break;
-	case VT_DECIMAL: p = "VT_DECIMAL"; break;
-	case VT_FILETIME: p = "VT_FILETIME"; break;
-	case VT_BSTR: p = "VT_BSTR"; break;
-	case VT_DISPATCH: p = "VT_DISPATCH"; break;
-	case VT_VARIANT: p = "VT_VARIANT"; break;
-	case VT_UNKNOWN: p = "VT_UNKNOWN"; break;
-	case VT_PTR: p = "VT_PTR"; break;
-	case VT_SAFEARRAY: p = "VT_SAFEARRAY"; break;
-	case VT_CARRAY: p = "VT_CARRAY"; break;
-	case VT_USERDEFINED: p = "VT_USERDEFINED"; break;
-	case VT_LPSTR: p = "VT_LPSTR"; break;
-	case VT_LPWSTR: p = "VT_LPWSTR"; break;
-	case VT_BLOB: p = "VT_BLOB"; break;
-	case VT_STREAM: p = "VT_STREAM"; break;
-	case VT_STORAGE: p = "VT_STORAGE"; break;
-	case VT_STREAMED_OBJECT: p = "VT_STREAMED_OBJECT"; break;
-	case VT_STORED_OBJECT: p = "VT_STORED_OBJECT"; break;
-	case VT_BLOB_OBJECT: p = "VT_BLOB_OBJECT"; break;
-	case VT_CF: p = "VT_CF"; break;
-	case VT_CLSID: p = "VT_CLSID"; break;
-	default: p = "*UNKNOWN*"; break;
-    }
-
-    return p;
-}
-
-// ----------------------------------------------------------------------
-// VariantTypeAsString2
-// ----------------------------------------------------------------------
-char * VariantTypeAsString2(int vt)
-{
-    char *	p;
-
-    switch(vt & VT_TYPEMASK)
-    {
-	case VT_EMPTY: p = "(empty)"; break;
-	case VT_NULL: p = "(null)"; break;
-	case VT_I2: p = "short"; break;
-	case VT_I4: p = "long"; break;
-	case VT_R4: p = "float"; break;
-	case VT_ERROR: p = "(error)"; break;
-	case VT_BOOL: p = "boolean"; break;
-	case VT_I1: p = "char"; break;
-	case VT_UI1: p = "unsigned char"; break;
-	case VT_UI2: p = "unsigned short"; break;
-	case VT_UI4: p = "unsigned long"; break;
-	case VT_INT: p = "int"; break;
-	case VT_UINT: p = "unsigned int"; break;
-	case VT_VOID: p = "void"; break;
-	case VT_HRESULT: p = "HRESULT"; break;
-	case VT_R8: p = "double"; break;
-	case VT_CY: p = "currency"; break;
-	case VT_DATE: p = "date"; break;
-	case VT_I8: p = "long long"; break;
-	case VT_UI8: p = "unsigned long long"; break;
-	case VT_DECIMAL: p = "decimal"; break;
-	case VT_FILETIME: p = "FILETIME"; break;
-	case VT_BSTR: p = "BSTR"; break;
-	case VT_DISPATCH: p = "IDISPATCH"; break;
-	case VT_VARIANT: p = "VARIANT"; break;
-	case VT_UNKNOWN: p = "IUNKNOWN"; break;
-	case VT_PTR: p = "*"; break;
-	case VT_SAFEARRAY: p = "SAFEARRAY"; break;
-	case VT_CARRAY: p = "CARRAY"; break;
-	case VT_USERDEFINED: p = "USERDEFINED"; break;
-	case VT_LPSTR: p = "LPSTR"; break;
-	case VT_LPWSTR: p = "LPWSTR"; break;
-	case VT_BLOB: p = "BLOB"; break;
-	case VT_STREAM: p = "STREAM"; break;
-	case VT_STORAGE: p = "STORAGE"; break;
-	case VT_STREAMED_OBJECT: p = "STREAMED_OBJECT"; break;
-	case VT_STORED_OBJECT: p = "STORED_OBJECT"; break;
-	case VT_BLOB_OBJECT: p = "BLOB_OBJECT"; break;
-	case VT_CF: p = "CF"; break;
-	case VT_CLSID: p = "CLSID"; break;
-	default: p = "*UNKNOWN*"; break;
-    }
-
-    return p;
-}
-// ----------------------------------------------------------------------
-// dprintTypeDesc
-// ----------------------------------------------------------------------
-size_t sprintfTypeDesc(char * buf, TYPEDESC * pDesc)
-{
-    LONG	ii;
-    size_t	len = 0;
-
-    if (pDesc->vt & VT_ARRAY)
-    {
-	ARRAYDESC *	pArray = V_UNION(pDesc, lpadesc);
-	
-	len += sprintfTypeDesc(buf + len, &pArray->tdescElem);
-	for (ii = 0; ii < pArray->cDims; ii++)
-	{
-	    if (ii)
-		len += sprintf(buf + len, ", ");
-
-	    len += sprintf(buf + len, "[%ld..%ld]", pArray->rgbounds[ii].lLbound,
-				pArray->rgbounds[ii].lLbound + pArray->rgbounds[ii].cElements);
-	}
-
-    }
-    else if (pDesc->vt == VT_PTR)
-    {
-	len += sprintfTypeDesc(buf + len, V_UNION(pDesc, lptdesc)) ;	// 'ware recursion...!
-	len += sprintf(buf + len,  "%s ", VariantTypeAsString2(pDesc->vt));
-    }
-    else if (pDesc->vt == VT_USERDEFINED)
-    {
-	len += sprintf(buf + len, "(%ld) ", V_UNION(pDesc, hreftype)  );
-    }
-    else
-    {
-	len += sprintf(buf + len, "%s ",  VariantTypeAsString2(pDesc->vt));
-    }
-    return len;
-}
-
-typedef struct FlagSt
-{
-    char *		name;
-    ULONG		value;
-} FLAGST;
-
-static FLAGST FKCCICFlagData[] =
-{
-    {"custom data",	    0x80},
-    {"default values",	    0x1000},
-    {"numeric entry",	    0x2000},
-    {"has retval",	    0x4000},	// Set for methods with a retval parameter
-    {"0x8000",		    0x8000},
-    {0, 0}
-};
-
-static FLAGST VarFlagData[] =
-{
-    {"readonly",	    0x1},
-    {"source",		    0x2},
-    {"bindable",	    0x4},
-    {"requestedit ",	    0x8},
-    {"displaybind ",	    0x10},
-    {"defaultbinD ",	    0x20},
-    {"hidden",		    0x40},
-    {"restricted",	    0x80},
-    {"defaultcollElem",	    0x100},
-    {"uidefault ",	    0x200},
-    {"nonbrowsable",	    0x400},
-    {"replaceable ",	    0x800},
-    {"immediatebind ",	    0x1000},
-    {0, 0}
-};
-
-static FLAGST ParamFlagData[] =
-{
-    {"in",		    0x01},
-    {"out",		    0x02},
-    {"lcid",		    0x04},
-    {"retval",		    0x08},
-    {"opt",		    0x10},
-    {"hasdefault",	    0x20},
-    {0, 0}
-};
-
-static FLAGST FuncFlagData[] =
-{
-    {"restricted",    	    0x1},
-    {"source",        	    0x2},
-    {"bindable",      	    0x4},
-    {"requestedit",   	    0x8},
-    {"displaybind",   	    0x10},
-    {"defaultbind",   	    0x20},
-    {"hidden",        	    0x40},
-    {"usesgetlasterror",    0x80},
-    {"defaultcollelem",     0x100},
-    {"uidefault",     	    0x200},
-    {"nonbrowsable",  	    0x400},
-    {"replaceable",   	    0x800},
-    {"immediatebind", 	    0x1000},
-    {0, 0}
-};
-
-// ----------------------------------------------------------------------
-// sprintfFlags
-// ----------------------------------------------------------------------
-size_t sprintfFlags(char * buf, FLAGST const * pData, ULONG flags)
-{
-    size_t	len = 0;
-
-    len += sprintf(buf + len, "[");
-
-    while (pData->name != 0)
-    {
-	if (flags & pData->value)
-	{
-	    if (len > 1)
-		len += sprintf(buf + len, ", ");
-
-	    len += sprintf(buf + len, pData->name);
-	}
-	pData++;
-    }
-    len += sprintf(buf + len, "]");
-
-    return len;
-}
-
-
-#endif
-
-// ======================================================================
-// Class functions.
-// ======================================================================
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::TypeLibExtract
-// ----------------------------------------------------------------------
-TypeLibExtract::TypeLibExtract(char * szName)
-    : m_fValid(0), m_hHeap(GetProcessHeap()), m_fFree(FALSE)
-{
-    if ((Load(szName) == S_OK)
-    && (EstablishPointers() == S_OK))
-    {
-	m_fValid = TRUE;
-    }
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::~TypeLibExtract
-// ----------------------------------------------------------------------
-TypeLibExtract::~TypeLibExtract()
-{
-    m_fValid = 0;
-
-    if (m_fFree)
-	HeapFree(m_hHeap, 0, m_pTypeLib);
-
-    m_hHeap = 0;
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::EstablishPointers()
-// ----------------------------------------------------------------------
-HRESULT TypeLibExtract::EstablishPointers()
-{
-    // Locate segment directory...
-    m_pHeader = (TLB2Header *)m_pTypeLib;
-
-    if (m_pHeader->varflags & HELPDLLFLAG)
-    {
-	m_pHelpStringOff = (ULONG *)(m_pHeader + 1);
-	m_pTypeInfoDir = m_pHelpStringOff + 1;
-    }
-    else
-    {
-	m_pHelpStringOff = 0;
-	m_pTypeInfoDir = (ULONG *)(m_pHeader + 1);
-    }
-    m_pSegDir = (TLBSegDir *)(m_pTypeInfoDir + m_pHeader->nrtypeinfos);
-
-    // Segment directory sanity check...
-    if (m_pSegDir->pTypeInfoTab.res0c != 0x0F || m_pSegDir->pImpInfo.res0c != 0x0F)
-    {
-	dprintf((LOG, "  Segment directory sanity check failed!"));
-	return E_FAIL;
-    }
-
-    // Decode the segment offsets...
-    dprintf((LOG, "Segment Offsets:"));
-
-    if (m_pSegDir->pImpInfo.offset != 0xffffffff)
-    {
-	m_pImpInfo = (TLBImpInfo *)((char *)m_pTypeLib + m_pSegDir->pImpInfo.offset);
-	dprintf((LOG, "  ImpInfo       0x%08lx", m_pSegDir->pImpInfo.offset));
-    }
-    else
-    {
-	m_pImpInfo = 0;
-    }
-
-    if (m_pSegDir->pRefTab.offset != 0xffffffff)
-    {
-	m_pRef = (TLBRefRecord *)((char *)m_pTypeLib + m_pSegDir->pRefTab.offset);
-	dprintf((LOG, "  RefTab        0x%08lx", m_pSegDir->pRefTab.offset));
-    }
-    else
-    {
-	m_pRef = 0;
-    }
-
-    if (m_pSegDir->pGuidTab.offset != 0xffffffff)
-    {
-	m_pGUID = (GUID *)((char *)m_pTypeLib + m_pSegDir->pGuidTab.offset);
-	dprintf((LOG, "  GuidTab       0x%08lx", m_pSegDir->pGuidTab.offset));
-    }
-    else
-    {
-	m_pGUID = 0;
-    }
-
-    if (m_pSegDir->pNameTab.offset != 0xffffffff)
-    {
-	m_pName = (TLBName *)((char *)m_pTypeLib + m_pSegDir->pNameTab.offset);
-	dprintf((LOG, "  NameTab       0x%08lx", m_pSegDir->pNameTab.offset));
-    }
-    else
-    {
-	m_pName = 0;
-    }
-
-    if (m_pSegDir->pStringTab.offset != 0xffffffff)
-    {
-	m_pString = (TLBString *)((char *)m_pTypeLib + m_pSegDir->pStringTab.offset);
-	dprintf((LOG, "  StringTab     0x%08lx", m_pSegDir->pStringTab.offset));
-    }
-    else
-    {
-	m_pString = 0;
-    }
-
-    if (m_pSegDir->pTypedescTab.offset != 0xffffffff)
-    {
-	m_pTypedesc = (TLBTypedesc *)((char *)m_pTypeLib + m_pSegDir->pTypedescTab.offset);
-	dprintf((LOG, "  TypedescTab   0x%08lx", m_pSegDir->pTypedescTab.offset));
-    }
-    else
-    {
-	m_pTypedesc = 0;
-    }
-
-    if (m_pSegDir->pCustData.offset != 0xffffffff)
-    {
-	m_pCustData = (void *)((char *)m_pTypeLib + m_pSegDir->pCustData.offset);
-	dprintf((LOG, "  CustData      0x%08lx", m_pSegDir->pCustData.offset));
-    }
-    else
-    {
-	m_pCustData = 0;
-    }
-
-    if (m_pSegDir->pCDGuids.offset != 0xffffffff)
-    {
-        m_pCDGuid = (TLBCDGuid *)((char *)m_pTypeLib + m_pSegDir->pCDGuids.offset);
-	dprintf((LOG, "  CDGuids       0x%08lx", m_pSegDir->pCDGuids.offset));
-    }
-    else
-    {
-	m_pCDGuid = 0;
-    }
-
-    if (m_pSegDir->pImpFiles.offset != 0xffffffff)
-    {
-        m_pImpFile = (TLBImpFile *)((char *)m_pTypeLib + m_pSegDir->pImpFiles.offset);
-	dprintf((LOG, "  ImpFiles      0x%08lx", m_pSegDir->pImpFiles.offset));
-    }
-    else
-    {
-	m_pImpFile = 0;
-    }
-
-    if (m_pSegDir->pTypeInfoTab.offset != 0xffffffff)
-    {
-        m_pTypeInfo = (TLBTypeInfoBase *)((char *)m_pTypeLib + m_pSegDir->pTypeInfoTab.offset);
-	dprintf((LOG, "  TypeInfoTab   0x%08lx", m_pSegDir->pTypeInfoTab.offset));
-    }
-    else
-    {
-	m_pTypeInfo = 0;
-    }
-
-    if (m_pSegDir->pArrayDescriptions.offset != 0xffffffff)
-    {
-        m_pArray = (TLBArray *)((char *)m_pTypeLib + m_pSegDir->pArrayDescriptions.offset);
-	dprintf((LOG, "  ArrayDesc     0x%08lx", m_pSegDir->pArrayDescriptions.offset));
-    }
-    else
-    {
-	m_pArray = 0;
-    }
-
-    if (m_pSegDir->pRes7.offset != 0xffffffff)
-    {
-        m_pRes7 = (void *)((char *)m_pTypeLib + m_pSegDir->pRes7.offset);
-	dprintf((LOG, "  Res7          0x%08lx", m_pSegDir->pRes7.offset));
-    }
-    else
-    {
-	m_pRes7 = 0;
-    }
-
-    if (m_pSegDir->pResE.offset != 0xffffffff)
-    {
-        m_pResE = (void *)((char *)m_pTypeLib + m_pSegDir->pResE.offset);
-	dprintf((LOG, "  ResE          0x%08lx", m_pSegDir->pResE.offset));
-    }
-    else
-    {
-	m_pResE = 0;
-    }
-
-    if (m_pSegDir->pResF.offset != 0xffffffff)
-    {
-        m_pResF = (void *)((char *)m_pTypeLib + m_pSegDir->pResF.offset);
-	dprintf((LOG, "  ResF          0x%08lx", m_pSegDir->pResF.offset));
-    }
-    else
-    {
-	m_pResF = 0;
-    }
-
-    return S_OK;
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::Read
-//
-// If 'where' is != DO_NOT_SEEK then seek to 'where'.
-// Read 'count' bytes from 'hfile' into 'buffer'
-// ----------------------------------------------------------------------
-BOOL TypeLibExtract::Read(HANDLE hFile, void * buffer, DWORD count, DWORD * pBytesRead, long where)
-{
-    if (where != DO_NOT_SEEK)
-    {
-	if (0xffffffff == SetFilePointer(hFile, where, 0, FILE_BEGIN))
-	    return FALSE;
-    }
-    return ReadFile(hFile, buffer, count, pBytesRead, NULL);
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::GetTypedesc
-// ----------------------------------------------------------------------
-void TypeLibExtract::GetTypedesc(int type, TYPEDESC * pTd)
-{
-    if (type < 0)
-        pTd->vt = type & VT_TYPEMASK;
-    else
-        *pTd = *m_pITypeLib->pTypedesc[type / (sizeof(TLBTypedesc))];
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::ParseGuid
-// ----------------------------------------------------------------------
-void TypeLibExtract::ParseGuid(int offset, GUID * pGuid)
-{
-    if (offset < 0)
-    {
-        memset(pGuid, 0, sizeof(GUID));
-    }
-    else
-    {
-	memcpy(pGuid, (char *)m_pGUID + offset, sizeof(GUID));
-    }
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::ParseArray
-// ----------------------------------------------------------------------
-void TypeLibExtract::ParseArray(int offset, TLBArray * pArray)
-{
-    if (offset < 0)
-    {
-        memset(pArray, 0, sizeof(TLBArray));
-    }
-    else
-    {
-	memcpy(pArray, (char *)m_pGUID + offset, sizeof(TLBArray));
-    }
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::ParseName
-// ----------------------------------------------------------------------
-void TypeLibExtract::ParseName(int offset, char * * ppName)
-{
-    char *	p;
-
-    if (offset < 0)
-    {
-	*ppName = 0;
-    }
-    else
-    {
-	TLBName *	pName = (TLBName *)((char *)m_pName + offset);
-	int		nameLen = pName->namelen & 0xff;
-
-	p = (char *)HeapAlloc(m_hHeap, 0, nameLen + 1);
-	memcpy(p, pName->name, nameLen);
-	p[nameLen] = 0;
-
-	*ppName = p;
-    }
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::ParseString
-// ----------------------------------------------------------------------
-void TypeLibExtract::ParseString(int offset, char * * ppString)
-{
-    char *	p;
-
-    if (offset < 0)
-    {
-	*ppString = 0;
-    }
-    else
-    {
-	TLBString *	pString = (TLBString *)((char *)m_pString + offset);
-	int		stringLen = pString->stringlen;
-
-	p = (char *)HeapAlloc(m_hHeap, 0, stringLen + 1);
-
-	memcpy(p, pString->string, stringLen);
-	p[stringLen] = 0;
-
-	*ppString = p;
-    }
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::ParseValue
-// ----------------------------------------------------------------------
-void TypeLibExtract::ParseValue(int offset, VARIANT * pVar)
-{
-    int		size;
-
-    if (offset < 0) /* data is packed in here */
-    {
-        pVar->vt = (offset & 0x7c000000) >> 26;
-        V_UNION(pVar, iVal) = offset & 0xffff;
-        return;
-    }
-
-    VARTYPE *	pVarType = (VARTYPE *)((char *)m_pCustData + offset);
-
-    pVar->vt = *pVarType;
-
-    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    :
-        {
-            INT *	pStringLen = (INT *)(pVarType + 1);
-            char *	pString = (char *)(pStringLen + 1);
-
-	    // Allocate BSTR container and then convert directly into it...
-	    // SvL: *pStringLen == -1 in MS Office 2k install
-	    // DjR: *pStringLen == -1 is used to denote VBA.vbNullString
-	    //      *pStringLen == 0 for a string that happens to be 0 length
-	    //      *pStringLen > 0 for a string with defined content.
-            if(*pStringLen == -1)
-		*pStringLen = 0;
-
-	    V_UNION(pVar, bstrVal) = SysAllocStringLen(NULL, *pStringLen);
-
-	    if (*pStringLen != 0)	// Save cluttering up logfile
-		AsciiToUnicodeN(pString, V_UNION(pVar, bstrVal), *pStringLen);
-
-	    return;
-	}
-
-    /* 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;
-            dprintf((LOG,
-            	     " VARTYPE %d (%s) is not supported yet, setting to NULL\n",
-            	     pVar->vt,
-            	     VariantTypeAsString(pVar->vt)));
-    }
-
-    if (size > 0) /* (big|small) endian correct? */
-	memcpy(&(V_UNION(pVar, iVal)), (pVarType + 1), size);
-
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::ParseCustomData
-// ----------------------------------------------------------------------
-void TypeLibExtract::ParseCustomData(int offset, oList<TLBCustData *> * pCustomData)
-{
-    TLBCDGuid *		pCDGuid;
-    TLBCustData *	pNew;
-
-    while (offset >= 0)		// Some offsets in VBA are 0x8c000000 - Special meaning??
-    {
-	pCDGuid = (TLBCDGuid *)((char *)m_pCDGuid + offset);
-	pNew = new TLBCustData;
-        memset(pNew, 0, sizeof(*pNew));	// Ensure that unset fields get nulled out.
-
-	ParseGuid(pCDGuid->GuidOffset, &(pNew->guid));
-	ParseValue(pCDGuid->DataOffset, &(pNew->data));
-
-	pCustomData->AddAtEnd(pNew);
-	offset  =  pCDGuid->next;
-    }
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::ParseTypeInfo
-// ----------------------------------------------------------------------
-void TypeLibExtract::ParseTypeInfo(ITypeInfoImpl * pTypeInfo, TLBTypeInfoBase * pBase)
-{
-    /* fill in the typeattr fields */
-    ParseGuid(pBase->posguid, &pTypeInfo->TypeAttr.guid);
-    pTypeInfo->TypeAttr.lcid = m_pITypeLib->LibAttr.lcid;   /* FIXME: correct? */
-    pTypeInfo->TypeAttr.memidConstructor = MEMBERID_NIL ;/* FIXME */
-    pTypeInfo->TypeAttr.memidDestructor = MEMBERID_NIL ; /* FIXME */
-    pTypeInfo->TypeAttr.lpstrSchema = NULL;              /* reserved */
-    pTypeInfo->TypeAttr.cbSizeInstance = pBase->size;
-    pTypeInfo->TypeAttr.typekind = (tagTYPEKIND)(pBase->typekind & 0xF);
-    pTypeInfo->TypeAttr.cFuncs = LOWORD(pBase->cElement);
-    pTypeInfo->TypeAttr.cVars = HIWORD(pBase->cElement);
-    pTypeInfo->TypeAttr.cbAlignment = (pBase->typekind >> 11 )& 0x1F; /* more flags here ? */
-    pTypeInfo->TypeAttr.wTypeFlags = pBase->flags;
-    pTypeInfo->TypeAttr.wMajorVerNum = LOWORD(pBase->version);
-    pTypeInfo->TypeAttr.wMinorVerNum = HIWORD(pBase->version);
-    pTypeInfo->TypeAttr.cImplTypes = pBase->cImplTypes;
-    pTypeInfo->TypeAttr.cbSizeVft = pBase->cbSizeVft; // FIXME: this is only the non inherited part
-
-    /*  FIXME: */
-    /*    IDLDESC  idldescType; *//* never saw this one ! =  zero  */
-
-    /* name, eventually add to a hash table */
-    ParseName(pBase->NameOffset, &pTypeInfo->szName);
-
-    /* help info */
-    ParseString(pBase->docstringoffs, &pTypeInfo->szDocString);
-    pTypeInfo->lHelpStringContext = pBase->helpstringcontext;
-    pTypeInfo->lHelpContext = pBase->helpcontext;
-    /* note: InfoType's Help file and HelpStringDll come from the containing
-     * library. Further HelpString and Docstring appear to be the same thing :(
-     */
-
-    // ImplTypes {DR: not sure this is OK yet}
-    switch(pTypeInfo->TypeAttr.typekind)
-    {
-	case TKIND_ALIAS:
-	    GetTypedesc(pBase->datatype1, &pTypeInfo->TypeAttr.tdescAlias) ;
-	    break;
-
-	case TKIND_COCLASS:
-	    ParseImplemented(pTypeInfo, pBase);
-	    break;
-
-	case TKIND_DISPATCH:
-	    break;
-
-	default:
-	    if (pBase->datatype1 != 0xffffffff)
-	    {
-		TLBRefType *	pNew = new TLBRefType;
-		memset(pNew, 0, sizeof(*pNew));	// Ensure that unset fields get nulled out.
-
-		ParseReference(pBase->datatype1, pNew);
-		pTypeInfo->pImplements.AddAtEnd(pNew);
-	    }
-	
-    }
-
-#if defined(DEBUG2)	    
-    dprintfLine2();
-    dprintf((LOG, "TypeInfo        %s", pTypeInfo->szName));
-    dprintf((LOG, "  .typeKind:    %08x (%s)", pTypeInfo->TypeAttr.typekind,
-						TypeKindAsString(pTypeInfo->TypeAttr.typekind)));
-    char	guid[128];
-    char	buf[1024];
-    WINE_StringFromCLSID(&pTypeInfo->TypeAttr.guid, guid);
-    dprintf((LOG, "  .GUID:        %s", guid));
-    dprintf((LOG, "  .lcid:        %08x", pTypeInfo->TypeAttr.lcid));
-    dprintf((LOG, "  .memidCon:    %08x", pTypeInfo->TypeAttr.memidConstructor));
-    dprintf((LOG, "  .memidDest:   %08x", pTypeInfo->TypeAttr.memidDestructor));
-    dprintf((LOG, "  .SizeInst:    %08x", pTypeInfo->TypeAttr.cbSizeInstance));
-    dprintf((LOG, "  .cFuncs:      %08x", pTypeInfo->TypeAttr.cFuncs));
-    dprintf((LOG, "  .cVars:       %08x", pTypeInfo->TypeAttr.cVars));
-    dprintf((LOG, "  .cbAlignment: %08x", pTypeInfo->TypeAttr.cbAlignment));
-    dprintf((LOG, "  .TypeFlags:   %08x", pTypeInfo->TypeAttr.wTypeFlags));
-    dprintf((LOG, "  .MajorVerNum: %08x", pTypeInfo->TypeAttr.wMajorVerNum));
-    dprintf((LOG, "  .MinorVerNum: %08x", pTypeInfo->TypeAttr.wMinorVerNum));
-    dprintf((LOG, "  .cImplTypes:  %08x", pTypeInfo->TypeAttr.cImplTypes));
-    dprintf((LOG, "  .cbSizeVft:   %08x", pTypeInfo->TypeAttr.cbSizeVft));
-    if (pTypeInfo->TypeAttr.typekind == TKIND_ALIAS)
-    {
-	sprintfTypeDesc(buf, &pTypeInfo->TypeAttr.tdescAlias);
-	dprintf((LOG, "  .tdesc        %s", buf));
-    }
-    dprintf((LOG, "  .DocString    %s", pTypeInfo->szDocString));
-    dprintf((LOG, "  .HelpStrCtx   %08x", pTypeInfo->lHelpStringContext));
-    dprintf((LOG, "  .HelpCtx      %08x", pTypeInfo->lHelpContext));
-
-    dprintf((LOG, "pBase"));
-    dprintf((LOG, "  .res2         %08x", pBase->res2));
-    dprintf((LOG, "  .res3         %08x", pBase->res3));
-    dprintf((LOG, "  .res4         %08x", pBase->res4));
-    dprintf((LOG, "  .res5         %08x", pBase->res5));
-    dprintf((LOG, "  .res7         %08x", pBase->res7));
-    dprintf((LOG, "  .res8         %08x", pBase->res8));
-    dprintf((LOG, "  .res9         %08x", pBase->res9));
-    dprintf((LOG, "  .resA         %08x", pBase->resA));
-    dprintf((LOG, "  .datatype1    %08x", pBase->datatype1));
-    dprintf((LOG, "  .datatype2    %08x", pBase->datatype2));
-    dprintf((LOG, "  .res18        %08x", pBase->res18));
-    dprintf((LOG, "  .res19        %08x", pBase->res19));
-
-#endif
-
-    // Functions/
-    ParseMembers(pTypeInfo, pBase);
-
-
-    // Load Custom data
-    ParseCustomData(pBase->oCustData, &pTypeInfo->pCustData);
-
-#if defined(DEBUG2)	    
-    dprintfLine();
-#endif
-
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::ParseReference
-// ----------------------------------------------------------------------
-void TypeLibExtract::ParseReference(int offset, TLBRefType * pNew)
-{
-    int j;
-
-    if(!HREFTYPE_INTHISFILE( offset))
-    {
-        /* external typelib */
-        TLBImpInfo *	pImpInfo = (TLBImpInfo *)((char *)m_pImpInfo + (offset & 0xfffffffc));
-        oListIter<TLBImpLib *>	itrImpLib(m_pITypeLib->pImpLibs);
-
-        // We have already loaded the external typelibs so
-        // loop thru them to find the one we want.
-        for (itrImpLib.MoveStart(); itrImpLib.IsValid(); itrImpLib.MoveNext())
-        {
-
-	    if (itrImpLib.Element()->offset == pImpInfo->oImpFile)
-	    {
-		pNew->reference = offset;
-		pNew->pImpTLInfo = itrImpLib.Element();
-		ParseGuid(pImpInfo->oGuid, &pNew->guid);
-		return;
-	    }
-        }
-	dprintf((LOG, " WARNING: Cannot find a reference\n"));
-	pNew->reference = -1;
-	pNew->pImpTLInfo = (TLBImpLib *)-1;
-    }
-    else
-    {
-        /* in this typelib */
-        pNew->reference = offset;
-        pNew->pImpTLInfo = (TLBImpLib *)-2;
-    }
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::ParseImplemented
-//
-// Process Implemented Interfaces of a com class
-// ----------------------------------------------------------------------
-void TypeLibExtract::ParseImplemented(ITypeInfoImpl * pTypeInfo, TLBTypeInfoBase * pBase)
-{
-    TLBRefRecord *	pRefRec;
-    TLBRefType *	pNew;
-    int			ii;
-    int			offset;
-
-    offset = pBase->datatype1;
-    for (ii = 0; ii < pTypeInfo->TypeAttr.cImplTypes; ii++)
-    {
-        if (offset < 0)
-	    break; /* paranoia */
-
-	pRefRec = (TLBRefRecord *)((char *)m_pRef + offset);
-	pNew = new TLBRefType;
-        memset(pNew, 0, sizeof(*pNew));	// Ensure that unset fields get nulled out.
-
-        ParseReference(pRefRec->reftype, pNew);
-        pNew->flags = pRefRec->flags;
-
-        // Custom data
-        ParseCustomData(pRefRec->oCustData, &pNew->pCustData);
-
-        pTypeInfo->pImplements.AddAtEnd(pNew);
-
-        offset = pRefRec->onext;
-    }
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::ParseMembers
-//
-// 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.
-//
-// ----------------------------------------------------------------------
-void	TypeLibExtract::ParseMembers(ITypeInfoImpl * pTypeInfo, TLBTypeInfoBase * pBase)
-{
-    char * 		pMemberRec;
-    TLBFuncRecord *	pFuncRec;
-    TLBVarRecord *	pVarRec;
-    int			ii;
-    int			jj;
-    int			iAttrCount;
-    INT *		pInfoLen;
-    INT *		pNameOff;
-    INT *		pMemberID;
-    INT *		pMemberOff;
-    INT *		pDefaultOff;
-    INT *		pCustomOff;
-    LONG		lMembers = pTypeInfo->TypeAttr.cFuncs + pTypeInfo->TypeAttr.cVars;
-
-    // Map ptrs to sections of the typeinfo record...
-    pInfoLen = (INT *)((char *)m_pTypeLib + pBase->memoffset);
-    pMemberRec = (char *)(pInfoLen + 1);
-    pMemberID = (INT *)(pMemberRec + *pInfoLen);
-    pNameOff = pMemberID + lMembers;
-    pMemberOff = pNameOff + lMembers;
-
-    // loop through each function...
-    for (ii = 0; ii < pTypeInfo->TypeAttr.cFuncs; ii++)
-    {
-        // Get record...
-        pFuncRec = (TLBFuncRecord *)(pMemberRec + pMemberOff[ii]);
-
-	TLBFuncDesc *	pNew;
-
-        pNew = new TLBFuncDesc;
-        memset(pNew, 0, sizeof(*pNew));	// Ensure that unset fields get nulled out.
-
-        ParseName(pNameOff[ii], &pNew->szName);
-	// fill the FuncDesc Structure
-	pNew->funcdesc.memid = pMemberID[ii];
-        pNew->funcdesc.funckind = (tagFUNCKIND)((pFuncRec->FKCCIC) & 0x7);
-        pNew->funcdesc.invkind = (tagINVOKEKIND)(((pFuncRec->FKCCIC) >>3) & 0xF);
-        pNew->funcdesc.callconv = (tagCALLCONV)((pFuncRec->FKCCIC) >>8 & 0xF);
-        pNew->funcdesc.cParams = pFuncRec->nrargs ;
-        pNew->funcdesc.cParamsOpt = pFuncRec->nroargs ;
-        pNew->funcdesc.oVft = pFuncRec->VtableOffset ;
-        pNew->funcdesc.wFuncFlags = LOWORD(pFuncRec->Flags)  ;
-        GetTypedesc(pFuncRec->DataType, &pNew->funcdesc.elemdescFunc.tdesc) ;
-
-	// Calc remaining attributes to be decoded.
-	iAttrCount = pFuncRec->recsize
-			- 24		// OFFSETOF(OptAttr[0])
-			- (pFuncRec->nrargs * sizeof(TLBParameterInfo));
-
-	iAttrCount /= sizeof(INT);
-
-	// If the 'default values' flag is set
-	// allow for a default value for each argument
-	// (include the return value)
-	if (pFuncRec->FKCCIC & 0x1000)
-	    iAttrCount -= pFuncRec->nrargs;
-
-	// If the 'custom data' flag is set
-	// allow for one dataoffset for the method
-	// plus one for each argument
-	// (include the return value)
-	if (pFuncRec->FKCCIC & 0x0080)
-	    iAttrCount -= pFuncRec->nrargs + 1;
-
-	// Loop through 'size specified' block to rip info...
-	for (jj = 0; jj < iAttrCount; jj++)
-	{
-	    switch(jj)
-	    {
-		case 0:
-		    pNew->helpcontext = pFuncRec->OptAttr[jj];
-		    break;
-
-		case 1:
-		    ParseString(pFuncRec->OptAttr[jj], &pNew->szHelpString);
-		    break;
-
-		case 2:
-		    if (pFuncRec->FKCCIC & 0x2000)
-			pNew->szEntry = (char *)(pFuncRec->OptAttr[jj]);
-		    else
-			ParseString(pFuncRec->OptAttr[jj], &pNew->szEntry);
-		    break;
-
-		case 5:
-		    pNew->lHelpStringContext = pFuncRec->OptAttr[jj];
-		    break;
-
-		default:
-		    if (pFuncRec->OptAttr[jj] != 0xffffffff)
-			dprintf((LOG, "- skipping pFuncRec->OptAttr[%lx] (%08x)...",
-				jj, pFuncRec->OptAttr[jj]));
-	    }
-	}
-
-	// Default & custom data come after size specified' block...
-	pCustomOff = pDefaultOff = pFuncRec->OptAttr + iAttrCount;
-
-	// Only advance custom data if there are defaults...
-	if (pFuncRec->FKCCIC & 0x1000)
-	    pCustomOff += pFuncRec->nrargs;
-
-	// Rip the method custom data...
-	if (pFuncRec->FKCCIC & 0x80)
-	    ParseCustomData(pCustomOff[0], &pNew->pCustData);
-
-#if defined(DEBUG2)
-	{
-	dprintfLine();
-        char	 buf[1024];
-	dprintf((LOG, "Method          \"%s\"\n", pNew->szName));
-	dprintf((LOG, "  .memid        %08x", pNew->funcdesc.memid));
-        dprintf((LOG, "  .funckind     %08x (%s)",
-				    pNew->funcdesc.funckind,
-				    FuncKindAsString(pNew->funcdesc.funckind)));
-        dprintf((LOG, "  .invkind      %08x (%s)",
-				    pNew->funcdesc.invkind,
-				    InvKindAsString(pNew->funcdesc.invkind)));
-        dprintf((LOG, "  .callconv     %08x (%s)",
-				    pNew->funcdesc.callconv,
-				    CallConvAsString(pNew->funcdesc.callconv)));
-        dprintf((LOG, "  .cParams      %08x", pNew->funcdesc.cParams));
-        dprintf((LOG, "  .cParamsOpt   %08x", pNew->funcdesc.cParamsOpt));
-        dprintf((LOG, "  .oVft         %08x", pNew->funcdesc.oVft));
-        sprintfFlags(buf, FuncFlagData, pNew->funcdesc.wFuncFlags);
-        dprintf((LOG, "  .wFuncFlags   %s", buf));
-        sprintfTypeDesc(buf, &pNew->funcdesc.elemdescFunc.tdesc);
-        dprintf((LOG, "  .tdesc        %s", buf));
-        dprintf((LOG, "  .helpcontext  %08x", pNew->helpcontext));
-        dprintf((LOG, "  .helpstring   %s", pNew->szHelpString));
-        if (pFuncRec->FKCCIC & 0x2000)
-	    dprintf((LOG, "  .entry        %08x", pNew->szHelpString));
-        else
-	    dprintf((LOG, "  .entry        %s", pNew->szHelpString));
-#if 0
-        dprintf((LOG, "pFuncRec"));
-        dprintf((LOG, "  .recsize      %08lx", pFuncRec->recsize));
-        dprintf((LOG, "  .index        %08lx", pFuncRec->index));
-        dprintf((LOG, "  .Datatype     %08lx", pFuncRec->DataType));
-        dprintf((LOG, "  .Flags        %08lx", pFuncRec->Flags));
-        dprintf((LOG, "  .res3         %08lx", pFuncRec->res3));
-
-        sprintfFlags(buf, FKCCICFlagData, pFuncRec->FKCCIC);
-        dprintf((LOG, "  .FKCCIC       %08lx (%s)", pFuncRec->FKCCIC, buf));
-        dprintf((LOG, "  .nrargs       %04lx", pFuncRec->nrargs));
-        dprintf((LOG, "  .nroargs      %04lx", pFuncRec->nroargs));
-	for (jj = 0;
-		(pFuncRec->recsize
-		    - (jj * sizeof(INT))
-		    - 24
-		    - (pFuncRec->nrargs * sizeof(TLBParameterInfo))) > 0 ;
-		jj++)
-	    dprintf((LOG, "  .optattr[%d]   %08lx", jj, pFuncRec->OptAttr[jj]));
-
-#endif // 0
-	}
-#endif // defined(DEBUG2)
-
-        // do the parameters/arguments 
-        if (pFuncRec->nrargs)
-        {
-            TLBParameterInfo *	pParam;
-
-            pNew->funcdesc.lprgelemdescParam = new ELEMDESC[pFuncRec->nrargs];
-            pNew->pParamDesc = new TLBParDesc[pFuncRec->nrargs];
-
-	    pParam = (TLBParameterInfo *)((char *)pFuncRec + pFuncRec->recsize -
-                pFuncRec->nrargs * sizeof(TLBParameterInfo));
-
-            for(jj = 0 ; jj < pFuncRec->nrargs; jj++)
-            {
-                GetTypedesc(pParam->DataType, &pNew->funcdesc.lprgelemdescParam[jj].tdesc);
-                    
-                V_UNION(&(pNew->funcdesc.lprgelemdescParam[jj]),
-		    paramdesc.wParamFlags)  =  pParam->Flags;
-		// Name
-                ParseName(pParam->oName, &pNew->pParamDesc[jj].szName);
-
-                // default value
-                if ((PARAMFLAG_FHASDEFAULT & V_UNION(&(pNew->funcdesc.
-			lprgelemdescParam[jj]),paramdesc.wParamFlags)) )
-		{
-		    if (pDefaultOff[jj] != 0xffffffff)	// jic
-		    {
-			PARAMDESC * pParamDesc =  &V_UNION(&(pNew->funcdesc.
-				lprgelemdescParam[jj]), paramdesc);
-			pParamDesc->pparamdescex  = new PARAMDESCEX;
-			pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
-			ParseValue(pDefaultOff[jj], &(pParamDesc->pparamdescex->varDefaultValue));
-		    }
-                }
-
-                // custom info
-                if (pFuncRec->FKCCIC & 0x80)
-                    ParseCustomData(pCustomOff[1 + jj], &pNew->pParamDesc[jj].pCustData);
-
-#if defined(DEBUG2)
-	dprintfLine();
-	dprintf((LOG, "Parameter       \"%s\"\n", pNew->pParamDesc[jj].szName));
-	char	buf[1024];
-	sprintfTypeDesc(buf, &pNew->funcdesc.lprgelemdescParam[jj].tdesc);
-	dprintf((LOG, "  .tdesc        %s", buf));
-	sprintfFlags(buf, ParamFlagData,
-		V_UNION(&pNew->funcdesc.lprgelemdescParam[jj], paramdesc.wParamFlags));
-	dprintf((LOG, "  .wParamFlags  %s", buf));
-#endif
-
-
-                pParam++;	// Next record.
-            }
-	}
-
-	/* scode is not used: archaic win16 stuff FIXME: right? */
-        pNew->funcdesc.cScodes = 0 ;
-        pNew->funcdesc.lprgscode = NULL ;
-
-	// Store
-	pTypeInfo->pFunctions.AddAtEnd(pNew);
-
-    }
-
-    for (ii = 0; ii < pTypeInfo->TypeAttr.cVars; ii++)
-    {
-        // Get record...
-        pVarRec = (TLBVarRecord *)(pMemberRec + pMemberOff[pTypeInfo->TypeAttr.cFuncs + ii]);
-
-	TLBVarDesc *	pNew;
-
-	pNew = new TLBVarDesc;
-        memset(pNew, 0, sizeof(*pNew));	// Ensure that unset fields get nulled out.
-
-	// name, eventually add to a hash table 
-	ParseName(pNameOff[ii], &pNew->szName);
-
-	// Calc remaining attributes to be decoded.
-	iAttrCount = pVarRec->recsize - 20;
-
-	iAttrCount /= sizeof(INT);
-
-	// Optional data
-	for (jj = 0; jj < iAttrCount; jj++)
-	{
-	    switch(jj)
-	    {
-		case 0:
-		    pNew->lHelpContext = pVarRec->OptAttr[jj];
-		    break;
-
-		case 1:
-		    ParseString(pVarRec->OptAttr[jj], &pNew->szHelpString);
-		    break;
-
-		case 4:
-		    pNew->lHelpStringContext = pVarRec->OptAttr[jj];
-		    break;
-
-		default:
-		    if (pVarRec->OptAttr[jj] != 0xffffffff)
-			dprintf((LOG, "- skipping pVarRec->OptAttr[%lx] (%08x)...",
-				jj, pVarRec->OptAttr[jj]));
-
-	    }
-	}
-
-	// fill the VarDesc Structure
-        pNew->vardesc.memid = pMemberID[ii];
-        pNew->vardesc.varkind = (tagVARKIND)pVarRec->VarKind;
-        pNew->vardesc.wVarFlags = pVarRec->Flags;
-        GetTypedesc(pVarRec->DataType, &pNew->vardesc.elemdescVar.tdesc) ;
-	/*   pNew->vardesc.lpstrSchema; is reserved (SDK) fixme?? */
-        if (pVarRec->VarKind == VAR_CONST )
-        {
-            V_UNION(&(pNew->vardesc), lpvarValue) = new VARIANT;
-            ParseValue(pVarRec->OffsValue, V_UNION(&(pNew->vardesc), lpvarValue));
-        }
-        else
-            V_UNION(&(pNew->vardesc), oInst) = pVarRec->OffsValue;
-
-#if defined(DEBUG2)
-	{
-	dprintfLine();
-        char	 buf[1024];
-	dprintf((LOG, "Variable        \"%s\"\n", pNew->szName));
-	dprintf((LOG, "  .MemberID     %08x", pNew->vardesc.memid));
-	dprintf((LOG, "  .VarKind      %08x (%s)",
-					pNew->vardesc.varkind,
-					VarKindAsString(pNew->vardesc.varkind)));
-        sprintfFlags(buf, FuncFlagData, pNew->vardesc.wVarFlags);
-	dprintf((LOG, "  .VarFlags     %08x %s", pNew->vardesc.wVarFlags, buf));
-	sprintfTypeDesc(buf, &pNew->vardesc.elemdescVar.tdesc);
-	dprintf((LOG, "  .TDesc        %s", buf));
-	dprintf((LOG, "  .HelpContext  %08x", pNew->lHelpContext));
-        dprintf((LOG, "  .HelpStrCtx   %08x", pNew->lHelpStringContext));
-        dprintf((LOG, "  .HelpStr      %s", pNew->szHelpString));
-
-#if 0
-        dprintf((LOG, "pVarRec"));
-	for (jj = 0; jj < iAttrCount; jj++)
-	    dprintf((LOG, "  .optattr[%d]   %08lx", jj, pVarRec->OptAttr[jj]));
-
-#endif
-
-        }
-
-#endif // defined(DEBUG2)
-
-	// Store
-	pTypeInfo->pVariables.AddAtEnd(pNew);
-    }
-}
-
-typedef struct LoadSt
-{
-    ULONG	cLibs;
-    VOID * *	ppLib;
-} LoadSt;
-
-// ----------------------------------------------------------------------
-// LoadSub
-//
-// Callback handler function for the EnumResourceNamesA function...
-// ----------------------------------------------------------------------
-static BOOL	WIN32API LoadSub(HANDLE hMod, LPCTSTR pResType, LPTSTR pResName, LONG lParm)
-{
-    LoadSt *	pLoad = (LoadSt *)lParm;
-
-    if (--pLoad->cLibs == 0)
-    {
-
-	HRSRC	hRsrc;
-	HGLOBAL	hData;
-
-	hRsrc = FindResourceA(hMod, pResName, pResType);
-	hData =  LoadResource(hMod, hRsrc);
-	*(pLoad->ppLib) = LockResource(hData);
-	return FALSE;
-    }
-    return TRUE;
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::Load
-//
-// Search for & load the TYPELIB into memory.
-// ----------------------------------------------------------------------
-HRESULT TypeLibExtract::Load(char * szFile)
-{
-    ULONG		lStart;			// Start of typelib in file
-    ULONG		lReadLen;		// Size of data read from file
-    ULONG		lFileSize;		// Size of file
-    char		buf[5];
-    OFSTRUCT		ofStruct;
-    HANDLE		hFile;
-    HRESULT		rc;
-    HINSTANCE		hInst;
-    LoadSt		loadData;
-
-    dprintf((LOG, "TypeLibExtract::Load(%s)", szFile));
-
-    // Open file
-    if ((hFile = OpenFile(szFile, &ofStruct, OF_READ)) != HFILE_ERROR)
-    {
-	lStart = 0;
-
-	// Read first four byts of file to identify it...
-	if (!Read(hFile, (void *)buf, 4, &lReadLen, lStart))
-	{
-	    CloseHandle(hFile);
-	    dprintf((LOG, "  Failed to read file start bytes"));
-	    return E_FAIL;
-	}
-
-	// Check to see if this is a type 1 typelib...
-	if ((buf[0] == 'S') && (buf[1] == 'L') && (buf[2] == 'T') && (buf[3] == 'G'))
-	{
-	    CloseHandle(hFile);
-	    dprintf((LOG, "  File identified as TYPE1 TYPELIB - not supported yet :-("));
-	    return E_FAIL;
-	}
-
-	// Check to see if this is a type 2 typelib...
-	if ((buf[0] == 'M') && (buf[1] == 'S') && (buf[2] == 'F') && (buf[3] == 'T'))
-	{
-	    // Get typelib file size...
-	    lFileSize = GetFileSize(hFile, NULL);
-	    dprintf((LOG, "  File identified as TYPE2 TYPELIB - Loading image (%lu bytes)", lFileSize));
-
-	    m_pTypeLib = HeapAlloc(m_hHeap, 0, lFileSize);
-	    if (!m_pTypeLib)
-	    {
-		CloseHandle(hFile);
-		dprintf((LOG, "  Failed to allocate a memory pool for typelib image"));
-		return E_OUTOFMEMORY;
-	    }
-
-	    // Read whole file into memory...
-	    if (!Read(hFile, m_pTypeLib, lFileSize, &lReadLen, lStart))
-	    {
-		CloseHandle(hFile);
-		dprintf((LOG, "  Failed to read typelib"));
-		HeapFree(m_hHeap, 0, m_pTypeLib);
-		return E_FAIL;
-	    }
-
-	    // Return buffer...
-	    CloseHandle(hFile);
-	    m_fFree = TRUE;
-	    return S_OK;
-	}
-
-	// Done with file handle...
-	CloseHandle(hFile);
-    }
-    else
-    {
-	// Failed to open file - Check to see if this is a request for a given resource
-	HRSRC			hRsrc;
-	HGLOBAL			hData;
-	char *			szLibName = HEAP_strdupA(m_hHeap, 0, szFile);
-	char *			p = strrchr(szLibName, '\\');
-	ULONG			lResId;
-
-	if (p)
-	{
-	    // Filename of form {drive:}{\\path\\}file\\resid
-	    *p = 0;
-	    lResId = atoi(p + 1);
-	    hInst = CoLoadLibrary(szLibName, TRUE);
-	    HeapFree(m_hHeap, 0, szLibName);
-	    if (hInst != 0)
-	    {
-		HRSRC	hRsrc;
-		HGLOBAL	hData;
-
-		if ((hRsrc = FindResourceA(hInst, (LPTSTR)lResId, "TYPELIB")) != 0)
-		{
-		    hData =  LoadResource(hInst, hRsrc);
-		    m_pTypeLib = LockResource(hData);
-		    return S_OK;
-		}
-		return E_FAIL;
-	    }
-	}
-	HeapFree(m_hHeap, 0, szLibName);
-    }
-
-    // Check to see if this is a module...
-    hInst = CoLoadLibrary(szFile, TRUE);
-    if (hInst)
-    {
-	loadData.cLibs = 1;
-	loadData.ppLib = &m_pTypeLib;
-	// Yup - use EnumResourceNames to locate & load 1st resource.
-	EnumResourceNamesA(hInst, "TYPELIB", LoadSub, (LONG)&loadData);
-	return m_pTypeLib ? S_OK : E_FAIL;
-    }
-
-    return E_FAIL;
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::MakeITypeLib
-// ----------------------------------------------------------------------
-HRESULT TypeLibExtract::MakeITypeLib(ITypeLibImpl * * ppObject)
-{
-    dprintf((LOG, "TypeLibExtract::MakeITypeLib"));
-
-    HRESULT		rc;
-
-    // Create new typelib object...
-    if ((m_pITypeLib = ITypeLibImpl_Constructor()) == 0)
-    {
-	dprintfGlobal(("OLEAUT32: TypeLibExtract::MakeITypeLib: E_OUTOFMEMORY"));
-    	return E_OUTOFMEMORY;
-    }
-
-    // Parse the typelib into storeage independent format.
-    rc = Parse();
-    if (rc != S_OK)
-    {
-	ITypeLibImpl_Destructor(m_pITypeLib);
-	return rc;
-    }
-
-    // Return new object
-    *ppObject = m_pITypeLib;
-    return S_OK;
-}
-
-// ----------------------------------------------------------------------
-// TypeLibExtract::Parse
-// ----------------------------------------------------------------------
-HRESULT TypeLibExtract::Parse()
-{
-
-    dprintf((LOG, "TypeLibExtract::Parse"));
-
-    // name, eventually add to a hash table
-    ParseName(m_pHeader->nameOffset, &m_pITypeLib->szName);
-
-    // Load header info...
-    ParseGuid(m_pHeader->posguid, &m_pITypeLib->LibAttr.guid);
-
-    m_pITypeLib->LibAttr.lcid = m_pHeader->lcid;
-    m_pITypeLib->LibAttr.syskind = (tagSYSKIND)(m_pHeader->varflags & 0x0f); /* check the mask */
-    m_pITypeLib->LibAttr.wMajorVerNum = LOWORD(m_pHeader->version);
-    m_pITypeLib->LibAttr.wMinorVerNum = HIWORD(m_pHeader->version);
-    m_pITypeLib->LibAttr.wLibFlags = (WORD) m_pHeader->flags & 0xffff;	/* check mask */
-
-    // help info
-    m_pITypeLib->lHelpContext = m_pHeader->helpstringcontext;
-    ParseString(m_pHeader->helpstring, &m_pITypeLib->szDocString);
-    ParseString(m_pHeader->helpfile, &m_pITypeLib->szHelpFile);
-    if (m_pHelpStringOff)
-	ParseString(*m_pHelpStringOff, &m_pITypeLib->szHelpStringDll);
-
-#if defined(DEBUG2)
-
-    dprintfLine2();
-    dprintf((LOG, "Library:        \"%s\"", m_pITypeLib->szName));
-    char	guid[128];
-    WINE_StringFromCLSID(&m_pITypeLib->LibAttr.guid, guid);
-    dprintf((LOG, "  .GUID:        %s", guid));
-    dprintf((LOG, "  .lcid:        %08x", m_pITypeLib->LibAttr.lcid));
-    dprintf((LOG, "  .syskind:     %08x", m_pITypeLib->LibAttr.syskind));
-    dprintf((LOG, "  .MajorVer:    %08x", m_pITypeLib->LibAttr.wMajorVerNum));
-    dprintf((LOG, "  .MinorVer:    %08x", m_pITypeLib->LibAttr.wMinorVerNum));
-    dprintf((LOG, "  .LibFlags:    %08x", m_pITypeLib->LibAttr.wLibFlags));
-
-#endif
-
-    // Load Custom data
-    ParseCustomData(m_pHeader->customDataOffset, &m_pITypeLib->pCustData);
-
-    // Load typedescriptions
-    if (m_pSegDir->pTypedescTab.length > 0)
-    {
-	TLBTypedesc *	pTd;
-	TYPEDESC *	pNew;
-	TLBArray *	pArray;
-	ULONG		clTd;
-	ULONG		ii;
-	ULONG		jj;
-	
-	clTd = m_pSegDir->pTypedescTab.length / sizeof(TLBTypedesc);
-
-	// Preload (in case of forward references)
-	for (ii = 0; ii < clTd; ii++)
-	{
-	    pNew = new TYPEDESC;
-	    memset(pNew, 0, sizeof(*pNew));	// Ensure that unset fields get nulled out.
-	    m_pITypeLib->pTypedesc.AddAtEnd(pNew);
-	}
-
-	// Populate
-	for (ii = 0, pTd = m_pTypedesc; ii < clTd; ii++, pTd++)
-	{
-	    pNew = m_pITypeLib->pTypedesc[ii];
-
-	    pNew->vt = pTd->rec0 & VT_TYPEMASK;
-	    if (pNew->vt == VT_PTR)
-	    {
-		// >< 99.12.18 DJR Changed test
-		if ((pTd->rec3 & 0x8000))
-		    V_UNION(pNew, lptdesc) = &stndTypeDesc[pTd->rec2];
-		else
-		    V_UNION(pNew, lptdesc) = m_pITypeLib->pTypedesc[pTd->rec2 / 8];
-	    }
-	    if (pNew->vt == VT_SAFEARRAY)
-	    {
-		dprintf((LOG, "VT_SAFEARRAY - NIY"));
-	    }
-	    else if (pNew->vt == VT_CARRAY) 
-	    {
-		pArray = (TLBArray *)((char *)m_pArray + pTd->rec2);
-
-		V_UNION(pNew, lpadesc) =
-		    (tagARRAYDESC*) HeapAlloc(m_hHeap, 0, (sizeof(ARRAYDESC)
-			+ sizeof(SAFEARRAYBOUND) * (pArray->rec3 - 1)));
-
-		if (pArray->rec1 < 0)
-		    V_UNION(pNew,lpadesc)->tdescElem.vt= pArray->rec0 & VT_TYPEMASK;
-		else
-		    V_UNION(pNew,lpadesc)->tdescElem = stndTypeDesc[pArray->rec0 / 8];
-
-		V_UNION(pNew,lpadesc)->cDims = pArray->rec2;
-
-		INT *	pInt = (INT *)(pArray + 1);
-
-		for (jj = 0; jj < pArray->rec2; jj++)
-		{
-		    V_UNION(pNew,lpadesc)->rgbounds[jj].cElements = *pInt++;
-		    V_UNION(pNew,lpadesc)->rgbounds[jj].lLbound = *pInt++;
-		}
-	    }
-	    else if (pNew->vt == VT_USERDEFINED)
-	    {
-		V_UNION(pNew, hreftype) = MAKELONG(pTd->rec2, pTd->rec3);
-	    }
-
-#if defined(DEBUG2)	    
-	    dprintfLine2();
-	    dprintf((LOG, "TypeDesc:       %i", ii));
-	    char	buf[1024];
-	    sprintfTypeDesc(buf, pNew);
-	    dprintf((LOG, "  desc          %s", buf));
-	    dprintf((LOG, "  pTd->rec0:    %04x", pTd->rec0));
-	    dprintf((LOG, "  pTd->rec1:    %04x", pTd->rec1));
-	    dprintf((LOG, "  pTd->rec2:    %04x", pTd->rec2));
-	    dprintf((LOG, "  pTd->rec3:    %04x", pTd->rec3));
-	    if (pNew->vt == VT_CARRAY) 
-	    {
-		dprintf((LOG, "  pArray->rec0: %04x", pArray->rec0));
-		dprintf((LOG, "  pArray->rec1: %04x", pArray->rec1));
-		dprintf((LOG, "  pArray->rec2: %04x", pArray->rec2));
-		dprintf((LOG, "  pArray->rec3: %04x", pArray->rec3));
-	    }
-#endif
-	}
-    }
-
-    // Load Imported typelibs
-    if (m_pSegDir->pImpFiles.length > 0)
-    {
-	TLBImpFile *	pImpFile = m_pImpFile;
-	TLBImpLib *	pNew;
-        ULONG		recLen = 0;
-        ULONG		totLen = 0;
-        ULONG 		size;
-
-        while(totLen < m_pSegDir->pImpFiles.length)
-        {
-	    pNew = new TLBImpLib;
-	    memset(pNew, 0, sizeof(*pNew));	// Ensure that unset fields get nulled out.
-            pNew->offset = totLen;
-
-            ParseGuid(pImpFile->offGuid, &(pNew->guid));
-            
-            /* we are skipping some unknown info here */
-
-            size = pImpFile->size >> 2;
-
-            pNew->name = (char *)HeapAlloc(m_hHeap, 0, size + 1);
-	    memcpy(pNew->name, pImpFile->name, size);
-
-	    // Add to list
-	    m_pITypeLib->pImpLibs.AddAtEnd(pNew);
-
-            // Align to next 4 byte boundary...
-            recLen = (sizeof(TLBImpFile) + size + 3) & 0xfffffffc;
-            totLen += recLen;
-            pImpFile = (TLBImpFile *)((char *)pImpFile + recLen);
-#if defined(DEBUG2)	    
-	    dprintfLine2();
-	    dprintf((LOG, "ImpLib %i", pNew->offset));
-	    char	guid[128];
-	    WINE_StringFromCLSID(&(pNew->guid), guid);
-	    dprintf((LOG, "  .GUID:        %s", guid));
-	    dprintf((LOG, "  .Name:        %s", pNew->name));
-#endif
-        }
-    }
-
-    // Load Type info data
-    if (m_pHeader->nrtypeinfos >=0 )
-    {
-	ULONG			ii;
-	ITypeInfoImpl *		pNew;
-	TLBTypeInfoBase *	pBase = m_pTypeInfo;
-
-	for (ii = 0; ii < m_pHeader->nrtypeinfos; ii++)
-	{
-	    TLBTypeInfoBase *	pBase = (TLBTypeInfoBase *)
-					((char *)m_pTypeInfo + m_pTypeInfoDir[ii]);
-	    pNew = ITypeInfoImpl_Constructor();
-	    pNew->pTypeLib = (ITypeLib *)m_pITypeLib;
-	    pNew->index = ii;
-
-	    ParseTypeInfo(pNew, pBase);
-
-	    m_pITypeLib->pTypeInfo.AddAtEnd(pNew);
-	}
-    }
-
-    return S_OK;
-}
-
-// ----------------------------------------------------------------------
-// DupAtoBstr
-// ----------------------------------------------------------------------
-extern BSTR DupAtoBstr(char * pAscii)
-{
-    int		len;
-    BSTR	bstr;
-    DWORD *	pl;
-
-    if (!pAscii)
-        return NULL;
-
-    len = strlen(pAscii);
-    pl  =  (DWORD *)HeapAlloc(GetProcessHeap(), 0, (len+3)*sizeof(OLECHAR));
-    pl[0] = (len)*sizeof(OLECHAR);
-    bstr = (BSTR)&( pl[1]);
-    lstrcpyAtoW( bstr, pAscii);
-    return bstr;
-}
-
Index: trunk/src/oleaut32/typelib.h
===================================================================
--- trunk/src/oleaut32/typelib.h	(revision 4837)
+++ trunk/src/oleaut32/typelib.h	(revision 4837)
@@ -0,0 +1,237 @@
+/*
+ * typelib.h  internal wine data structures
+ * used to decode typelib's
+ *
+ * Copyright 1999 Rein KLazes
+ *  
+ */
+#ifndef _WINE_TYPELIB_H
+#define _WINE_TYPELIB_H
+
+#include "oleauto.h"
+#include "wine/windef16.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))
+
+/*-------------------------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--------------------------------------------*/
+#endif
Index: trunk/src/oleaut32/variant.c
===================================================================
--- trunk/src/oleaut32/variant.c	(revision 4837)
+++ trunk/src/oleaut32/variant.c	(revision 4837)
@@ -0,0 +1,4338 @@
+/*
+ * VARIANT
+ *
+ * Copyright 1998 Jean-Claude Cote
+ *
+ * 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 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 dates prior to 1900.
+ *   - The parsing does not accept as many formats as the Windows implementation.
+ */
+
+#ifdef __WIN32OS2__
+#define HAVE_FLOAT_H
+#define WINE_LARGE_INTEGER
+#include "oleaut32.h"
+#endif
+
+#include "config.h"
+ 
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <time.h>
+
+#ifdef HAVE_FLOAT_H
+# include <float.h>
+#endif
+
+#include "windef.h"
+#include "oleauto.h"
+#include "heap.h"
+#include "debugtools.h"
+#include "winerror.h"
+#include "parsedt.h"
+
+DEFAULT_DEBUG_CHANNEL(ole);
+
+#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.01
+ * One + every 400 years: 1/400 -> 365.0025
+ */
+/* static const double DAYS_IN_ONE_YEAR = 365.2515;
+ *
+ *  ^^  Might this be the key to an easy way to factor large prime numbers?
+ *  Let's try using arithmetic.  <lawson_whitney@juno.com> 7 Mar 2000
+ */
+static const double DAYS_IN_ONE_YEAR = 365.2425;
+
+/******************************************************************************
+ *	   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 successful.
+ *
+ * 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 successful.
+ */
+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 converts 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 successful.
+ */
+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) + 0.001 );
+			pTm->tm_year += yearsSince1900;
+			/* determine if this is a leap year.
+			 */
+			if( isleap( pTm->tm_year ) )
+			{
+				leapYear = 1;
+				wholePart++;
+			}
+
+			/* 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 their unsigned versions.
+	 */
+
+	/* Trivial Case: If the coercion is from two types that are 
+	 * identical then we can blindly copy from one argument to another.*/
+	if ((vt==vtFrom))
+	{
+	   return VariantCopy(pd,ps);
+	}
+
+	/* Cases requiring thought*/
+	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_EMPTY ):
+			if ((pd->u.bstrVal = SysAllocStringLen(NULL, 0)))
+				res = S_OK;
+			else
+				res = E_OUTOFMEMORY;
+			break;
+		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;
+}
+
+
+
+
+
+/******************************************************************************
+ *		VariantInit	[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;
+}
+
+/******************************************************************************
+ *		VariantClear	[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 ):
+	    if(pvarg->u.pdispVal!=NULL)
+	      ICOM_CALL(Release,pvarg->u.pdispVal);
+	    break;
+	  case( VT_VARIANT ):
+	    VariantClear(pvarg->u.pvarVal);
+	    break;
+	  case( VT_UNKNOWN ):
+	    if(pvarg->u.punkVal!=NULL)
+	      ICOM_CALL(Release,pvarg->u.punkVal);
+	    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;
+}
+
+/******************************************************************************
+ *		VariantCopy	[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 ):
+	      pvargDest->u.pdispVal = pvargSrc->u.pdispVal;
+	      if (pvargDest->u.pdispVal!=NULL)
+		ICOM_CALL(AddRef,pvargDest->u.pdispVal);
+	      break;
+	    case( VT_VARIANT ):
+	      VariantCopy(pvargDest->u.pvarVal,pvargSrc->u.pvarVal);
+	      break;
+	    case( VT_UNKNOWN ):
+	      pvargDest->u.punkVal = pvargSrc->u.punkVal;
+	      if (pvargDest->u.pdispVal!=NULL)
+		ICOM_CALL(AddRef,pvargDest->u.punkVal);
+	      break;
+	    case( VT_SAFEARRAY ):
+	      SafeArrayCopy(pvargSrc->u.parray, &pvargDest->u.parray);
+	      break;
+	    default:
+	      pvargDest->u = pvargSrc->u;
+	      break;
+	  }
+	}
+	
+	pvargDest->vt = pvargSrc->vt;
+      }      
+    }
+  }
+
+  return res;
+}
+
+
+/******************************************************************************
+ *		VariantCopyInd	[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 );
+		  /* We must also copy its type, I think.
+		   */
+		  pvargSrc->vt = pvargSrc->u.pvarVal->vt; 
+		}
+	      }
+	      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;
+}
+
+/******************************************************************************
+ *		VariantChangeType	[OLEAUT32.12]
+ */
+HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
+							USHORT wFlags, VARTYPE vt)
+{
+	return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
+}
+
+/******************************************************************************
+ *		VariantChangeTypeEx	[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;
+}
+
+
+
+
+/******************************************************************************
+ *		VarUI1FromI2		[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;
+}
+
+/******************************************************************************
+ *		VarUI1FromI4		[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;
+}
+
+
+/******************************************************************************
+ *		VarUI1FromR4		[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;
+}
+
+/******************************************************************************
+ *		VarUI1FromR8		[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;
+}
+
+/******************************************************************************
+ *		VarUI1FromDate		[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;
+}
+
+/******************************************************************************
+ *		VarUI1FromBool		[OLEAUT32.138]
+ */
+HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pbOut );
+
+	*pbOut = (BYTE) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI1FromI1		[OLEAUT32.237]
+ */
+HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pbOut );
+
+	*pbOut = cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI1FromUI2		[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;
+}
+
+/******************************************************************************
+ *		VarUI1FromUI4		[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;
+}
+
+
+/******************************************************************************
+ *		VarUI1FromStr		[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;
+}
+
+/**********************************************************************
+ *              VarUI1FromCy [OLEAUT32.134]
+ * Convert currency to unsigned char
+ */
+HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
+   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
+   
+   if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
+   
+   *pbOut = (BYTE)t;
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromUI1		[OLEAUT32.48]
+ */
+HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
+{
+	TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
+
+	*psOut = (short) bIn;
+	
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromI4		[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;
+}
+
+/******************************************************************************
+ *		VarI2FromR4		[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;
+}
+
+/******************************************************************************
+ *		VarI2FromR8		[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;
+}
+
+/******************************************************************************
+ *		VarI2FromDate		[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;
+}
+
+/******************************************************************************
+ *		VarI2FromBool		[OLEAUT32.56]
+ */
+HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, psOut );
+
+	*psOut = (short) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromI1		[OLEAUT32.48]
+ */
+HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, psOut );
+
+	*psOut = (short) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI2FromUI2		[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;
+}
+
+/******************************************************************************
+ *		VarI2FromUI4		[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;
+}
+
+/******************************************************************************
+ *		VarI2FromStr		[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;
+}
+
+/**********************************************************************
+ *              VarI2FromCy [OLEAUT32.52]
+ * Convert currency to signed short
+ */
+HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
+   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
+   
+   if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
+   
+   *psOut = (SHORT)t;
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromUI1		[OLEAUT32.58]
+ */
+HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
+{
+	TRACE("( %X, %p ), stub\n", bIn, plOut );
+
+	*plOut = (LONG) bIn;
+
+	return S_OK;
+}
+
+
+/******************************************************************************
+ *		VarI4FromR4		[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;
+}
+
+/******************************************************************************
+ *		VarI4FromR8		[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;
+}
+
+/******************************************************************************
+ *		VarI4FromDate		[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;
+}
+
+/******************************************************************************
+ *		VarI4FromBool		[OLEAUT32.66]
+ */
+HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, plOut );
+
+	*plOut = (LONG) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromI1		[OLEAUT32.209]
+ */
+HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, plOut );
+
+	*plOut = (LONG) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromUI2		[OLEAUT32.210]
+ */
+HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, plOut );
+
+	*plOut = (LONG) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromUI4		[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;
+}
+
+/******************************************************************************
+ *		VarI4FromI2		[OLEAUT32.59]
+ */
+HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
+{
+	TRACE("( %d, %p ), stub\n", sIn, plOut );
+
+	*plOut = (LONG) sIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI4FromStr		[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;
+}
+
+/**********************************************************************
+ *              VarI4FromCy [OLEAUT32.62]
+ * Convert currency to signed long
+ */
+HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
+   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
+   
+   if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
+   
+   *plOut = (LONG)t;
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromUI1		[OLEAUT32.68]
+ */
+HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
+{
+	TRACE("( %X, %p ), stub\n", bIn, pfltOut );
+
+	*pfltOut = (FLOAT) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromI2		[OLEAUT32.69]
+ */
+HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
+{
+	TRACE("( %d, %p ), stub\n", sIn, pfltOut );
+
+	*pfltOut = (FLOAT) sIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromI4		[OLEAUT32.70]
+ */
+HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
+{
+	TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
+
+	*pfltOut = (FLOAT) lIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromR8		[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;
+}
+
+/******************************************************************************
+ *		VarR4FromDate		[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;
+}
+
+/******************************************************************************
+ *		VarR4FromBool		[OLEAUT32.76]
+ */
+HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
+
+	*pfltOut = (FLOAT) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromI1		[OLEAUT32.213]
+ */
+HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pfltOut );
+
+	*pfltOut = (FLOAT) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromUI2		[OLEAUT32.214]
+ */
+HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
+
+	*pfltOut = (FLOAT) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromUI4		[OLEAUT32.215]
+ */
+HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
+{
+	TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
+
+	*pfltOut = (FLOAT) ulIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR4FromStr		[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;
+}
+
+/**********************************************************************
+ *              VarR4FromCy [OLEAUT32.72]
+ * Convert currency to float
+ */
+HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
+   *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
+   
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromUI1		[OLEAUT32.68]
+ */
+HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
+{
+	TRACE("( %d, %p ), stub\n", bIn, pdblOut );
+
+	*pdblOut = (double) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromI2		[OLEAUT32.69]
+ */
+HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
+{
+	TRACE("( %d, %p ), stub\n", sIn, pdblOut );
+
+	*pdblOut = (double) sIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromI4		[OLEAUT32.70]
+ */
+HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
+{
+	TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
+
+	*pdblOut = (double) lIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromR4		[OLEAUT32.81]
+ */
+HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
+{
+	TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
+
+	*pdblOut = (double) fltIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromDate		[OLEAUT32.83]
+ */
+HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
+{
+	TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
+
+	*pdblOut = (double) dateIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromBool		[OLEAUT32.86]
+ */
+HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
+
+	*pdblOut = (double) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromI1		[OLEAUT32.217]
+ */
+HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pdblOut );
+
+	*pdblOut = (double) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromUI2		[OLEAUT32.218]
+ */
+HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
+
+	*pdblOut = (double) uiIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromUI4		[OLEAUT32.219]
+ */
+HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
+{
+	TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
+
+	*pdblOut = (double) ulIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarR8FromStr		[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;
+}
+
+/**********************************************************************
+ *              VarR8FromCy [OLEAUT32.82]
+ * Convert currency to double
+ */
+HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
+   *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
+   
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromUI1		[OLEAUT32.]
+ */
+HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
+{
+	TRACE("( %d, %p ), stub\n", bIn, pdateOut );
+
+	*pdateOut = (DATE) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromI2		[OLEAUT32.222]
+ */
+HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
+{
+	TRACE("( %d, %p ), stub\n", sIn, pdateOut );
+
+	*pdateOut = (DATE) sIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromI4		[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;
+}
+
+/******************************************************************************
+ *		VarDateFromR4		[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;
+}
+
+/******************************************************************************
+ *		VarDateFromR8		[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;
+}
+
+/******************************************************************************
+ *		VarDateFromStr		[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;
+
+    memset( &TM, 0, sizeof(TM) );
+
+    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;
+}
+
+/******************************************************************************
+ *		VarDateFromI1		[OLEAUT32.221]
+ */
+HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pdateOut );
+
+	*pdateOut = (DATE) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarDateFromUI2		[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;
+}
+
+/******************************************************************************
+ *		VarDateFromUI4		[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;
+}
+
+/******************************************************************************
+ *		VarDateFromBool		[OLEAUT32.96]
+ */
+HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
+
+	*pdateOut = (DATE) boolIn;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarDateFromCy [OLEAUT32.93]
+ * Convert currency to date
+ */
+HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
+   *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
+
+   if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromUI1		[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;
+}
+
+/******************************************************************************
+ *		VarBstrFromI2		[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;
+}
+
+/******************************************************************************
+ *		VarBstrFromI4		[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;
+}
+
+/******************************************************************************
+ *		VarBstrFromR4		[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;
+}
+
+/******************************************************************************
+ *		VarBstrFromR8		[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;
+}
+
+ 
+/******************************************************************************
+ *		VarBstrFromDate		[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;
+    memset( &TM, 0, sizeof(TM) );
+
+    TRACE("( %f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
+
+    if( DateToTm( dateIn, lcid, &TM ) == FALSE )
+			{
+        return E_INVALIDARG;
+		}
+
+    if( dwFlags & VAR_DATEVALUEONLY )
+			strftime( pBuffer, BUFFER_MAX, "%x", &TM );
+    else if( dwFlags & VAR_TIMEVALUEONLY )
+			strftime( pBuffer, BUFFER_MAX, "%X", &TM );
+		else
+        strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
+
+		*pbstrOut = StringDupAtoBstr( pBuffer );
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarBstrFromBool		[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;
+}
+
+/******************************************************************************
+ *		VarBstrFromI1		[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;
+}
+
+/******************************************************************************
+ *		VarBstrFromUI2		[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;
+}
+
+/******************************************************************************
+ *		VarBstrFromUI4		[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;
+}
+
+/******************************************************************************
+ *		VarBoolFromUI1		[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;
+}
+
+/******************************************************************************
+ *		VarBoolFromI2		[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;
+}
+
+/******************************************************************************
+ *		VarBoolFromI4		[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;
+}
+
+/******************************************************************************
+ *		VarBoolFromR4		[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;
+}
+
+/******************************************************************************
+ *		VarBoolFromR8		[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;
+}
+
+/******************************************************************************
+ *		VarBoolFromDate		[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;
+}
+
+/******************************************************************************
+ *		VarBoolFromStr		[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 )
+		{
+			*pboolOut = VARIANT_TRUE;
+		}
+		else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 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;
+}
+
+/******************************************************************************
+ *		VarBoolFromI1		[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;
+}
+
+/******************************************************************************
+ *		VarBoolFromUI2		[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;
+}
+
+/******************************************************************************
+ *		VarBoolFromUI4		[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;
+}
+
+/**********************************************************************
+ *              VarBoolFromCy [OLEAUT32.124]
+ * Convert currency to boolean
+ */
+HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
+      if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
+      else *pboolOut = 0;
+      
+      return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromUI1		[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;
+}
+
+/******************************************************************************
+ *		VarI1FromI2		[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;
+}
+
+/******************************************************************************
+ *		VarI1FromI4		[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;
+}
+
+/******************************************************************************
+ *		VarI1FromR4		[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;
+}
+
+/******************************************************************************
+ *		VarI1FromR8		[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;
+}
+
+/******************************************************************************
+ *		VarI1FromDate		[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;
+}
+
+/******************************************************************************
+ *		VarI1FromStr		[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;
+}
+
+/******************************************************************************
+ *		VarI1FromBool		[OLEAUT32.253]
+ */
+HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pcOut );
+
+	*pcOut = (CHAR) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarI1FromUI2		[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;
+}
+
+/******************************************************************************
+ *		VarI1FromUI4		[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;
+}
+
+/**********************************************************************
+ *              VarI1FromCy [OLEAUT32.250]
+ * Convert currency to signed char
+ */
+HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
+   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
+   
+   if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
+   
+   *pcOut = (CHAR)t;
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromUI1		[OLEAUT32.257]
+ */
+HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
+{
+	TRACE("( %d, %p ), stub\n", bIn, puiOut );
+
+	*puiOut = (USHORT) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromI2		[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;
+}
+
+/******************************************************************************
+ *		VarUI2FromI4		[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;
+}
+
+/******************************************************************************
+ *		VarUI2FromR4		[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;
+}
+
+/******************************************************************************
+ *		VarUI2FromR8		[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;
+}
+
+/******************************************************************************
+ *		VarUI2FromDate		[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;
+}
+
+/******************************************************************************
+ *		VarUI2FromStr		[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;
+}
+
+/******************************************************************************
+ *		VarUI2FromBool		[OLEAUT32.266]
+ */
+HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, puiOut );
+
+	*puiOut = (USHORT) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromI1		[OLEAUT32.267]
+ */
+HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, puiOut );
+
+	*puiOut = (USHORT) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI2FromUI4		[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;
+}
+
+/******************************************************************************
+ *		VarUI4FromStr		[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;
+}
+
+/**********************************************************************
+ *              VarUI2FromCy [OLEAUT32.263]
+ * Convert currency to unsigned short
+ */
+HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
+   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
+   
+   if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
+      
+   *pusOut = (USHORT)t;
+   
+   return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromUI1		[OLEAUT32.270]
+ */
+HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
+{
+	TRACE("( %d, %p ), stub\n", bIn, pulOut );
+
+	*pulOut = (USHORT) bIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromI2		[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;
+}
+
+/******************************************************************************
+ *		VarUI4FromI4		[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;
+}
+
+/******************************************************************************
+ *		VarUI4FromR4		[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;
+}
+
+/******************************************************************************
+ *		VarUI4FromR8		[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;
+}
+
+/******************************************************************************
+ *		VarUI4FromDate		[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;
+}
+
+/******************************************************************************
+ *		VarUI4FromBool		[OLEAUT32.279]
+ */
+HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
+{
+	TRACE("( %d, %p ), stub\n", boolIn, pulOut );
+
+	*pulOut = (ULONG) boolIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromI1		[OLEAUT32.280]
+ */
+HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
+{
+	TRACE("( %c, %p ), stub\n", cIn, pulOut );
+
+	*pulOut = (ULONG) cIn;
+
+	return S_OK;
+}
+
+/******************************************************************************
+ *		VarUI4FromUI2		[OLEAUT32.281]
+ */
+HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
+{
+	TRACE("( %d, %p ), stub\n", uiIn, pulOut );
+
+	*pulOut = (ULONG) uiIn;
+
+	return S_OK;
+}
+
+/**********************************************************************
+ *              VarUI4FromCy [OLEAUT32.276]
+ * Convert currency to unsigned long
+ */
+HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
+   double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
+   
+   if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
+
+   *pulOut = (ULONG)t;
+
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromUI1 [OLEAUT32.98]
+ * Convert unsigned char to currency
+ */
+HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
+   pcyOut->s.Hi = 0;
+   pcyOut->s.Lo = ((ULONG)bIn) * 10000;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromI2 [OLEAUT32.99]
+ * Convert signed short to currency
+ */
+HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
+   if (sIn < 0) pcyOut->s.Hi = -1;
+   else pcyOut->s.Hi = 0;
+   pcyOut->s.Lo = ((ULONG)sIn) * 10000;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromI4 [OLEAUT32.100]
+ * Convert signed long to currency
+ */
+HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
+      double t = (double)lIn * (double)10000;
+      pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
+      pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
+      if (lIn < 0) pcyOut->s.Hi--;
+   
+      return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromR4 [OLEAUT32.101]
+ * Convert float to currency
+ */
+HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
+   double t = round((double)fltIn * (double)10000);
+   pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
+   pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
+   if (fltIn < 0) pcyOut->s.Hi--;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromR8 [OLEAUT32.102]
+ * Convert double to currency
+ */
+HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
+   double t = round(dblIn * (double)10000);
+   pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
+   pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
+   if (dblIn < 0) pcyOut->s.Hi--;
+
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromDate [OLEAUT32.103]
+ * Convert date to currency
+ */
+HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
+   double t = round((double)dateIn * (double)10000);
+   pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
+   pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
+   if (dateIn < 0) pcyOut->s.Hi--;
+
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromStr [OLEAUT32.104]
+ */
+HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
+				/* FIXME */
+		return E_NOTIMPL;
+}
+
+ 
+/**********************************************************************
+ *              VarCyFromBool [OLEAUT32.106]
+ * Convert boolean to currency
+ */
+HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
+   if (boolIn < 0) pcyOut->s.Hi = -1;
+   else pcyOut->s.Hi = 0;
+   pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromI1 [OLEAUT32.225]
+ * Convert signed char to currency
+ */
+HRESULT WINAPI VarCyFromI1(CHAR cIn, CY* pcyOut) {
+   if (cIn < 0) pcyOut->s.Hi = -1;
+   else pcyOut->s.Hi = 0;
+   pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromUI2 [OLEAUT32.226]
+ * Convert unsigned short to currency
+ */
+HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
+   pcyOut->s.Hi = 0;
+   pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
+   
+   return S_OK;
+}
+
+/**********************************************************************
+ *              VarCyFromUI4 [OLEAUT32.227]
+ * Convert unsigned long to currency
+ */
+HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
+   double t = (double)ulIn * (double)10000;
+   pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
+   pcyOut->s.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 );
+}
+
Index: trunk/src/oleaut32/variant.cpp
===================================================================
--- trunk/src/oleaut32/variant.cpp	(revision 4830)
+++ 	(revision )
@@ -1,4321 +1,0 @@
-/* $Id: variant.cpp,v 1.3 2000-09-17 22:31:42 davidr Exp $ */
-/*
- * 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) + 0.001 );
-			pTm->tm_year += yearsSince1900;
-			/* determine if this is a leap year.
-			 */
-			if( isleap( pTm->tm_year ) )
-			{
-				leapYear = 1;
-				wholePart++;
-			}
-
-			/* 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 their unsigned versions.
-	 */
-
-	/* Trivial Case: If the coercion is from two types that are 
-	 * identical then we can blindly copy from one argument to another.*/
-	if ((vt==vtFrom))
-	{
-	   return VariantCopy(pd,ps);
-	}
-
-	/* Cases requiring thought*/
-	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 ):
-	    if(pvarg->u.pdispVal!=NULL)
-	      ICOM_CALL(Release,pvarg->u.pdispVal);
-	    break;
-	  case( VT_VARIANT ):
-	    VariantClear(pvarg->u.pvarVal);
-	    break;
-	  case( VT_UNKNOWN ):
-	    if(pvarg->u.punkVal!=NULL)
-	      ICOM_CALL(Release,pvarg->u.punkVal);
-	    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 ):
-	      pvargDest->u.pdispVal = pvargSrc->u.pdispVal;
-	      if (pvargDest->u.pdispVal!=NULL)
-		ICOM_CALL(AddRef,pvargDest->u.pdispVal);
-	      break;
-	    case( VT_VARIANT ):
-	      VariantCopy(pvargDest->u.pvarVal,pvargSrc->u.pvarVal);
-	      break;
-	    case( VT_UNKNOWN ):
-	      pvargDest->u.punkVal = pvargSrc->u.punkVal;
-	      if (pvargDest->u.pdispVal!=NULL)
-		ICOM_CALL(AddRef,pvargDest->u.punkVal);
-	      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( dwFlags & VAR_DATEVALUEONLY )
-			strftime( pBuffer, BUFFER_MAX, "%lx", &TM );
-    else if( dwFlags & VAR_TIMEVALUEONLY )
-			strftime( pBuffer, BUFFER_MAX, "%lX", &TM );
-		else
-        strftime( pBuffer, BUFFER_MAX, "%lx %lX", &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 )
-		{
-			*pboolOut = VARIANT_TRUE;
-		}
-		else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 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 );
-}
-
-
