Sync to Wine-0_9_1:
authorGé van Geldorp <ge@gse.nl>
Thu, 17 Nov 2005 21:52:13 +0000 (21:52 +0000)
committerGé van Geldorp <ge@gse.nl>
Thu, 17 Nov 2005 21:52:13 +0000 (21:52 +0000)
Huw Davies <huw@codeweavers.com>
- Treat paramflags == 0 like PARAMFLAG_FIN.
- Don't call Release on a null ptr.
- Deal with pExcepInfo == NULL.
Robert Shearman <rob@codeweavers.com>
- Add IFontEventsDisp and IProvideMultipleClassInfo.
- Make sure to clean up properly on error.
- Restrict the critical section to getting the channel buffer and
  adding a reference to it.
- There is no need to call IUnknown_QueryInterface since getting the
  correct object is handled by the proxy manager.
- Forward IDispatch functions to the MIDL-generated proxy.
- Remove special cases caused by previous marshaling of IDispatch &
  IUnknown that is no longer done.
- Add error messages if an IUnknown or IDispatch method is called when
  it no longer should be.
- Cleanup formating of DispCallFunc.
- Fix DispCallFunc for functions with return values.
- Don't rely on _copy_arg as it is going away soon.
- Make wParamFlags in the paramdesc dumping function human readable.
- Enums should be VT_I4 instead of VT_INT.
- Trace the return value from the ITypeInfo_fnInvoke.
- Read DLL name from modules in MSFT typelibs.
- A name offset of -1 for a parameter means that it has the same name
  as the function.
- Print an error if a ReadName is attempted with an offset of -1,
  since this will read garbage.
- Implement ITypeInfo_GetDllEntry.
- Fix a crash during +variant logging caused by a typo causing an array
  to be one element less than expected.
- The PSDispatch PS class factory can manage both typelib marshalled and
  IDispatch, which is NDR marshalled, so we need a wrapper to call the
  appropriate CreateProxy or CreateStub function.
Alex Villacís Lasso <a_villacis@palosanto.com>
- Implement complete VarDecDiv() for any valid DECIMAL.
- Implement complete VarDecMul() for any valid DECIMAL.
- Implement complete VarBstrFromDec() for any valid DECIMAL, with
  internationalization support borrowed from VARIANT_BstrFromReal(). The
  decimal fix for VARIANT_BstrFromReal was encapsulated in a separate
  function and reused.
Michael Stefaniuc <mstefani@redhat.de>
- Handle VT_DECIMAL in VarCmp().
- Handle VT_CY in VarDiv().
Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
- Extend VarCmp() and add test cases.
Marcus Meissner <marcus@jet.franken.de>
- Added support of loading of IPicture data from non-statable
  IStreams. Added testcases for this.
- Added support for VT_I8/VT_UI8 marshalling.
- Fixed FMT_DATE_GENERAL and FMT_DATE_TIME_SYS cases in
  VARIANT_FormatDate.

svn path=/trunk/; revision=19313

14 files changed:
reactos/include/wine/ocidl.h
reactos/lib/oleaut32/oleaut.c
reactos/lib/oleaut32/oleaut32.rc
reactos/lib/oleaut32/oleaut32_Ko.rc [new file with mode: 0644]
reactos/lib/oleaut32/olepicture.c
reactos/lib/oleaut32/regsvr.c
reactos/lib/oleaut32/tmarshal.c
reactos/lib/oleaut32/typelib.c
reactos/lib/oleaut32/typelib.h
reactos/lib/oleaut32/usrmarshal.c
reactos/lib/oleaut32/varformat.c
reactos/lib/oleaut32/variant.c
reactos/lib/oleaut32/vartype.c
reactos/w32api/include/oaidl.h

index ddcbce5..af38481 100644 (file)
@@ -5,6 +5,7 @@
 
 DEFINE_GUID(IID_IFont, 0xbef6e002, 0xa874, 0x101a, 0x8b,0xba, 0x00,0xaa,0x00,0x30,0x0c,0xab);
 DEFINE_GUID(IID_IFontDisp, 0xbef6e003, 0xa874, 0x101a, 0x8b,0xba, 0x00,0xaa,0x00,0x30,0x0c,0xab);
+DEFINE_GUID(IID_IFontEventsDisp, 0x4ef6100a, 0xaf88, 0x11d0, 0x98,0x46, 0x00,0xc0,0x4f,0xc2,0x99,0x93);
 DEFINE_GUID(IID_IPicture, 0x7bf80980, 0xbf32, 0x101a, 0x8b,0xbb, 0x00,0xaa,0x00,0x30,0x0c,0xab);
 DEFINE_GUID(IID_IPictureDisp, 0x7bf80981, 0xbf32, 0x101a, 0x8b,0xbb, 0x00,0xaa,0x00,0x30,0x0c,0xab);
 DEFINE_GUID(IID_IOleControl, 0xb196b288, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa,0x00,0x34,0x1d,0x07);
@@ -16,6 +17,7 @@ DEFINE_GUID(IID_IClassFactory2, 0xb196b28f, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa
 DEFINE_GUID(IID_IViewObjectEx, 0x3af24292, 0x0c96, 0x11ce, 0xa0,0xcf, 0x00,0xaa,0x00,0x60,0x0a,0xb8);
 DEFINE_GUID(IID_IProvideClassInfo, 0xb196b283, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa,0x00,0x34,0x1d,0x07);
 DEFINE_GUID(IID_IProvideClassInfo2, 0xa6bc3ac0, 0xdbaa, 0x11ce, 0x9d,0xe3, 0x00,0xaa,0x00,0x4b,0xb8,0x51);
+DEFINE_GUID(IID_IProvideMultipleClassInfo, 0xa7aba9c1, 0x8983, 0x11cf, 0x8f,0x20, 0x00,0x80,0x5f,0x2c,0xd0,0x64);
 DEFINE_GUID(IID_IConnectionPoint, 0xb196b286, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa,0x00,0x34,0x1d,0x07);
 DEFINE_GUID(IID_IConnectionPointContainer, 0xb196b284, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa,0x00,0x34,0x1d,0x07);
 DEFINE_GUID(IID_IEnumConnections, 0xb196b287, 0xbab4, 0x101a, 0xb6,0x9c, 0x00,0xaa,0x00,0x34,0x1d,0x07);
index 1b0f133..3ef2088 100644 (file)
@@ -699,6 +699,76 @@ extern HRESULT OLEAUTPS_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *
 extern void _get_STDFONT_CF(LPVOID);
 extern void _get_STDPIC_CF(LPVOID);
 
+static HRESULT WINAPI PSDispatchFacBuf_QueryInterface(IPSFactoryBuffer *iface, REFIID riid, void **ppv)
+{
+    if (IsEqualIID(riid, &IID_IUnknown) ||
+        IsEqualIID(riid, &IID_IPSFactoryBuffer))
+    {
+        IUnknown_AddRef(iface);
+        *ppv = (void *)iface;
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI PSDispatchFacBuf_AddRef(IPSFactoryBuffer *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI PSDispatchFacBuf_Release(IPSFactoryBuffer *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI PSDispatchFacBuf_CreateProxy(IPSFactoryBuffer *iface, IUnknown *pUnkOuter, REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv)
+{
+    IPSFactoryBuffer *pPSFB;
+    HRESULT hr;
+
+    if (IsEqualIID(riid, &IID_IDispatch))
+        hr = OLEAUTPS_DllGetClassObject(&CLSID_PSDispatch, &IID_IPSFactoryBuffer, (void **)&pPSFB);
+    else
+        hr = TMARSHAL_DllGetClassObject(&CLSID_PSOAInterface, &IID_IPSFactoryBuffer, (void **)&pPSFB);
+
+    if (FAILED(hr)) return hr;
+
+    hr = IPSFactoryBuffer_CreateProxy(pPSFB, pUnkOuter, riid, ppProxy, ppv);
+
+    IPSFactoryBuffer_Release(pPSFB);
+    return hr;
+}
+
+static HRESULT WINAPI PSDispatchFacBuf_CreateStub(IPSFactoryBuffer *iface, REFIID riid, IUnknown *pUnkOuter, IRpcStubBuffer **ppStub)
+{
+    IPSFactoryBuffer *pPSFB;
+    HRESULT hr;
+
+    if (IsEqualIID(riid, &IID_IDispatch))
+        hr = OLEAUTPS_DllGetClassObject(&CLSID_PSDispatch, &IID_IPSFactoryBuffer, (void **)&pPSFB);
+    else
+        hr = TMARSHAL_DllGetClassObject(&CLSID_PSOAInterface, &IID_IPSFactoryBuffer, (void **)&pPSFB);
+
+    if (FAILED(hr)) return hr;
+
+    hr = IPSFactoryBuffer_CreateStub(pPSFB, riid, pUnkOuter, ppStub);
+
+    IPSFactoryBuffer_Release(pPSFB);
+    return hr;
+}
+
+static const IPSFactoryBufferVtbl PSDispatchFacBuf_Vtbl =
+{
+    PSDispatchFacBuf_QueryInterface,
+    PSDispatchFacBuf_AddRef,
+    PSDispatchFacBuf_Release,
+    PSDispatchFacBuf_CreateProxy,
+    PSDispatchFacBuf_CreateStub
+};
+
+/* This is the whole PSFactoryBuffer object, just the vtableptr */
+static const IPSFactoryBufferVtbl *pPSDispatchFacBuf = &PSDispatchFacBuf_Vtbl;
+
 /***********************************************************************
  *             DllGetClassObject (OLEAUT32.@)
  */
@@ -719,12 +789,16 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
            return S_OK;
        }
     }
-    if (IsEqualCLSID(rclsid, &CLSID_PSDispatch) ||
-        IsEqualCLSID(rclsid, &CLSID_PSTypeInfo) ||
+    if (IsEqualCLSID(rclsid, &CLSID_PSTypeInfo) ||
         IsEqualCLSID(rclsid, &CLSID_PSTypeLib) ||
         IsEqualCLSID(rclsid, &CLSID_PSEnumVariant)) {
         return OLEAUTPS_DllGetClassObject(&CLSID_PSDispatch, iid, ppv);
     }
+    if (IsEqualCLSID(rclsid, &CLSID_PSDispatch) && IsEqualIID(iid, &IID_IPSFactoryBuffer)) {
+        *ppv = &pPSDispatchFacBuf;
+        IPSFactoryBuffer_AddRef((IPSFactoryBuffer *)*ppv);
+        return S_OK;
+    }
     if (IsEqualGUID(rclsid,&CLSID_PSOAInterface)) {
        if (S_OK==TMARSHAL_DllGetClassObject(rclsid,iid,ppv))
            return S_OK;
index 068cb7b..40f3f45 100644 (file)
@@ -34,6 +34,7 @@
 #include "oleaut32_Hu.rc"
 #include "oleaut32_It.rc"
 #include "oleaut32_Ja.rc"
+#include "oleaut32_Ko.rc"
 #include "oleaut32_Nl.rc"
 #include "oleaut32_No.rc"
 #include "oleaut32_Pl.rc"
diff --git a/reactos/lib/oleaut32/oleaut32_Ko.rc b/reactos/lib/oleaut32/oleaut32_Ko.rc
new file mode 100644 (file)
index 0000000..cfd2f77
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Korean resources for oleaut32
+ *
+ * 
+ *Copyright 2005 YunSong Hwang(hys545@dreamwiz.com)
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+  IDS_TRUE  "Áø½Ç"
+  IDS_FALSE "°ÅÁþ"
+  IDS_YES   "¿¹"
+  IDS_NO    "¾Æ´Ï¿À"
+  IDS_ON    "ÀÛµ¿"
+  IDS_OFF   "ºñÀÛµ¿"
+}
index e1e4024..3420bdd 100644 (file)
@@ -1056,6 +1056,7 @@ static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
   HRESULT      hr = E_FAIL;
   BOOL         headerisdata = FALSE;
+  BOOL         statfailed = FALSE;
   ULONG                xread, toread;
   BYTE                 *xbuf;
   DWORD                header[2];
@@ -1065,19 +1066,29 @@ static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
   
   TRACE("(%p,%p)\n",This,pStm);
 
+  /****************************************************************************************
+   * Part 1: Load the data
+   */
   /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
    * out whether we do.
    *
    * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
-   * compound file. This may explain most, if not all, of the cases of "no header",
-   * and the header validation should take this into account. At least in Visual Basic 6,
-   * resource streams, valid headers are
+   * compound file. This may explain most, if not all, of the cases of "no
+   * header", and the header validation should take this into account.
+   * At least in Visual Basic 6, resource streams, valid headers are
    *    header[0] == "lt\0\0",
    *    header[1] == length_of_stream.
+   *
+   * Also handle streams where we do not have a working "Stat" method by
+   * reading all data until the end of the stream.
    */
   hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
-  if (hr)
-      FIXME("Stat failed with hres %lx\n",hr);
+  if (hr) {
+      TRACE("stat failed with hres %lx, proceeding to read all data.\n",hr);
+      statfailed = TRUE;
+      /* we will read at least 8 byte ... just right below */
+      statstg.cbSize.QuadPart = 8;
+  }
   hr=IStream_Read(pStm,header,8,&xread);
   if (hr || xread!=8) {
       FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
@@ -1089,42 +1100,77 @@ static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
   if (!memcmp(&(header[0]),"lt\0\0", 4) && (header[1] <= statstg.cbSize.QuadPart-8)) {
       toread = header[1];
   } else {
-      if (!memcmp(&(header[0]), "GIF8",     4) ||   /* GIF header */
-         !memcmp(&(header[0]), "BM",       2)  ||   /* BMP header */
-         !memcmp(&(header[0]), "\xff\xd8", 2)  ||   /* JPEG header */
-         (header[1] > statstg.cbSize.QuadPart) ||   /* invalid size */
-         (header[1]==0)
+      if (!memcmp(&(header[0]), "GIF8",     4) ||   /* GIF header */
+          !memcmp(&(header[0]), "BM",       2) ||   /* BMP header */
+          !memcmp(&(header[0]), "\xff\xd8", 2) ||   /* JPEG header */
+          (header[1] > statstg.cbSize.QuadPart)||   /* invalid size */
+          (header[1]==0)
       ) {/* Incorrect header, assume none. */
           headerisdata = TRUE;
           toread = statstg.cbSize.QuadPart-8;
-         xread = 8;
+          xread = 8;
       } else {
-         FIXME("Unknown stream header magic: %08lx\n", header[0]);
+          FIXME("Unknown stream header magic: %08lx\n", header[0]);
           toread = header[1];
       }
   }
 
-  This->datalen = toread+(headerisdata?8:0);
-  xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
-
-  if (headerisdata)
-      memcpy (xbuf, &header, 8);
-
-  while (xread < This->datalen) {
-      ULONG nread;
-      hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
-      xread+=nread;
-      if (hr || !nread)
-       break;
+  if (statfailed) { /* we don't know the size ... read all we get */
+      int sizeinc = 4096;
+      int origsize = sizeinc;
+      ULONG nread = 42;
+
+      TRACE("Reading all data from stream.\n");
+      xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
+      if (headerisdata)
+          memcpy (xbuf, &header, 8);
+      while (1) {
+          while (xread < origsize) {
+              hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
+              xread+=nread;
+              if (hr || !nread)
+                  break;
+          }
+          if (!nread || hr) /* done, or error */
+              break;
+          if (xread == origsize) {
+              origsize += sizeinc;
+              sizeinc = 2*sizeinc; /* exponential increase */
+              xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
+          }
+      }
+      if (hr)
+          TRACE("hr in no-stat loader case is %08lx\n", hr);
+      TRACE("loaded %ld bytes.\n", xread);
+      This->datalen = xread;
+      This->data    = xbuf;
+  } else {
+      This->datalen = toread+(headerisdata?8:0);
+      xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
+
+      if (headerisdata)
+          memcpy (xbuf, &header, 8);
+
+      while (xread < This->datalen) {
+          ULONG nread;
+          hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
+          xread+=nread;
+          if (hr || !nread)
+              break;
+      }
+      if (xread != This->datalen)
+          FIXME("Could only read %ld of %d bytes out of stream?\n",xread,This->datalen);
   }
-  if (xread != This->datalen)
-      FIXME("Could only read %ld of %d bytes out of stream?\n",xread,This->datalen);
-
-  if (This->datalen == 0) {    /* Marks the "NONE" picture */
+  if (This->datalen == 0) { /* Marks the "NONE" picture */
       This->desc.picType = PICTYPE_NONE;
       return S_OK;
   }
 
+
+  /****************************************************************************************
+   * Part 2: Process the loaded data
+   */
+
   magic = xbuf[0] + (xbuf[1]<<8);
   switch (magic) {
   case 0x4947: { /* GIF */
index 9ab5fd4..fc92295 100644 (file)
@@ -544,15 +544,6 @@ static struct regsvr_coclass const coclass_list[] = {
 /***********************************************************************
  *             interface list
  */
-
-/* FIXME: these interfaces should be defined in ocidl.idl */
-
-static IID const IID_IFontEventsDisp = {
-    0x4EF6100A, 0xAF88, 0x11D0, {0x98,0x46,0x00,0xC0,0x4F,0xC2,0x99,0x93} };
-
-static IID const IID_IProvideMultipleClassInfo = {
-    0xA7ABA9C1, 0x8983, 0x11CF, {0x8F,0x20,0x00,0x80,0x5F,0x2C,0xD0,0x64} };
-
 static struct regsvr_interface const interface_list[] = {
     {   &IID_IDispatch,
        "IDispatch",
index a6931ca..0886fc3 100644 (file)
 #include "typelib.h"
 #include "wine/debug.h"
 
-static const WCHAR riidW[5] = {'r','i','i','d',0};
-static const WCHAR pdispparamsW[] = {'p','d','i','s','p','p','a','r','a','m','s',0};
-static const WCHAR ppvObjectW[] = {'p','p','v','O','b','j','e','c','t',0};
 static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0};
-static const WCHAR GetIDsOfNamesW[] = { 'G','e','t','I','D','s','O','f','N','a','m','e','s',0};
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
@@ -60,9 +56,6 @@ typedef struct _marshal_state {
     LPBYTE     base;
     int                size;
     int                curoff;
-
-    BOOL       thisisiid;
-    IID                iid;    /* HACK: for VT_VOID */
 } marshal_state;
 
 /* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */
@@ -360,6 +353,7 @@ typedef struct _TMProxyImpl {
     IID                                        iid;
     CRITICAL_SECTION   crit;
     IUnknown                           *outerunknown;
+    IDispatch                          *dispatch;
 } TMProxyImpl;
 
 static HRESULT WINAPI
@@ -396,6 +390,7 @@ TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
 
     if (!refCount)
     {
+        if (This->dispatch) IDispatch_Release(This->dispatch);
         DeleteCriticalSection(&This->crit);
         if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
         VirtualFree(This->asmstubs, 0, MEM_RELEASE);
@@ -450,6 +445,8 @@ static const IRpcProxyBufferVtbl tmproxyvtable = {
 int
 _argsize(DWORD vt) {
     switch (vt) {
+    case VT_UI8:
+       return 8/sizeof(DWORD);
     case VT_R8:
         return sizeof(double)/sizeof(DWORD);
     case VT_CY:
@@ -478,6 +475,9 @@ _xsize(TYPEDESC *td) {
            arrsize *= adesc->rgbounds[i].cElements;
        return arrsize*_xsize(&adesc->tdescElem);
     }
+    case VT_UI8:
+    case VT_I8:
+       return 8;
     case VT_UI2:
     case VT_I2:
        return 2;
@@ -506,6 +506,13 @@ serialize_param(
     switch (tdesc->vt) {
     case VT_EMPTY: /* nothing. empty variant for instance */
        return S_OK;
+    case VT_I8:
+    case VT_UI8:
+       hres = S_OK;
+       if (debugout) TRACE_(olerelay)("%lx%lx",arg[0],arg[1]);
+       if (writeit)
+           hres = xbuf_add(buf,(LPBYTE)arg,8);
+       return hres;
     case VT_BOOL:
     case VT_ERROR:
     case VT_UINT:
@@ -726,8 +733,6 @@ serialize_param(
                if (debugout && (i<(tattr->cVars-1)))
                    TRACE_(olerelay)(",");
            }
-           if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
-               memcpy(&(buf->iid),arg,sizeof(buf->iid));
            if (debugout) TRACE_(olerelay)("}");
            break;
        }
@@ -773,295 +778,6 @@ serialize_param(
     }
 }
 
-/* IDL desc:
- * HRESULT GetIDsOfNames(
- *   [in] REFIID riid,                                 args[1]
- *   [in, size_is(cNames)] LPOLESTR *rgszNames,                args[2]
- *   [in] UINT cNames,                                 args[3]
- *   [in] LCID lcid,                                   args[4]
- *   [out, size_is(cNames)] DISPID *rgDispId);         args[5]
- *
- * line format:
- *     IID     iid;
- *     DWORD   cNames;
- *     LPOLESTR rgszNames[cNames];
- *             DWORD bytestrlen        (incl 0)
- *             BYTE data[bytestrlen]   (incl 0)
- *     LCID
- */
-static HRESULT
-serialize_IDispatch_GetIDsOfNames(
-    BOOL               inputparams,
-    BOOL               debugout,
-    DWORD              *args,
-    marshal_state      *buf)
-{
-    HRESULT    hres;
-    DWORD      cNames = args[2];
-    LPOLESTR    *rgszNames = (LPOLESTR*)args[1];
-    int                i;
-
-    if (inputparams) {
-       if (debugout) TRACE_(olerelay)("riid=%s,",debugstr_guid((REFIID)args[0]));
-       hres = xbuf_add(buf, (LPBYTE)args[0], sizeof(IID));
-       if (hres) {
-           FIXME("serialize of IID failed.\n");
-           return hres;
-       }
-       if (debugout) TRACE_(olerelay)("cNames=%ld,",cNames);
-       hres = xbuf_add(buf, (LPBYTE)&cNames, sizeof(DWORD));
-       if (hres) {
-           FIXME("serialize of cNames failed.\n");
-           return hres;
-       }
-       if (debugout) TRACE_(olerelay)("rgszNames=[");
-        for (i=0;i<cNames;i++) {
-           DWORD len = 2*(lstrlenW(rgszNames[i])+1);
-
-           if (debugout) TRACE_(olerelay)("%s,",relaystr(rgszNames[i]));
-           hres = xbuf_add(buf, (LPBYTE)&len, sizeof(DWORD));
-           if (hres) {
-               FIXME("serialize of len failed.\n");
-               return hres;
-           }
-           hres = xbuf_add(buf, (LPBYTE)rgszNames[i], len);
-           if (hres) {
-               FIXME("serialize of rgszNames[i] failed.\n");
-               return hres;
-           }
-        }
-       if (debugout) TRACE_(olerelay)("],lcid=%04lx)",args[3]);
-       hres = xbuf_add(buf, (LPBYTE)&args[3], sizeof(DWORD));
-       if (hres) {
-           FIXME("serialize of lcid failed.\n");
-           return hres;
-       }
-    } else {
-       DISPID *rgDispId = (DISPID*)args[4];
-
-       hres = xbuf_add(buf, (LPBYTE)rgDispId, sizeof(DISPID) * cNames);
-       if (hres) {
-           FIXME("serialize of rgDispId failed.\n");
-           return hres;
-       }
-       if (debugout) {
-           TRACE_(olerelay)("riid=[in],rgszNames=[in],cNames=[in],rgDispId=[");
-           for (i=0;i<cNames;i++)
-               TRACE_(olerelay)("%08lx,",rgDispId[i]);
-           TRACE_(olerelay)("])");
-       }
-       HeapFree(GetProcessHeap(),0,(IID*)args[0]);
-       rgszNames = (LPOLESTR*)args[1];
-       for (i=0;i<cNames;i++) HeapFree(GetProcessHeap(),0,rgszNames[i]);
-       HeapFree(GetProcessHeap(),0,rgszNames);
-       HeapFree(GetProcessHeap(),0,rgDispId);
-    }
-    return S_OK;
-}
-
-static HRESULT
-deserialize_IDispatch_GetIDsOfNames(
-    BOOL               inputparams,
-    BOOL               debugout,
-    DWORD              *args,
-    marshal_state      *buf)
-{
-    HRESULT    hres;
-    DWORD      cNames;
-    LPOLESTR    *rgszNames;
-    int                i;
-
-    if (inputparams) {
-       args[0] = (DWORD)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IID));
-       if (!args[0]) return E_FAIL;
-       hres = xbuf_get(buf, (LPBYTE)args[0], sizeof(IID));
-       if (hres) {
-           FIXME("deserialize of IID failed.\n");
-           return hres;
-       }
-       if (debugout) TRACE_(olerelay)("riid=%s,",debugstr_guid((REFIID)args[0]));
-
-       hres = xbuf_get(buf, (LPBYTE)&cNames, sizeof(DWORD));
-       if (hres) {
-           FIXME("deserialize of cNames failed.\n");
-           return hres;
-       }
-        args[2] = cNames;
-       if (debugout) TRACE_(olerelay)("cNames=%ld,",cNames);
-       if (debugout) TRACE_(olerelay)("rgszNames=[");
-        rgszNames = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPOLESTR) * cNames);
-       if (!rgszNames) return E_FAIL;
-       args[1] = (DWORD)rgszNames;
-        for (i=0;i<cNames;i++) {
-           DWORD len;
-
-           hres = xbuf_get(buf, (LPBYTE)&len, sizeof(DWORD));
-           if (hres) {
-               FIXME("serialize of len failed.\n");
-               return hres;
-           }
-           rgszNames[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
-           if (!rgszNames[i]) {
-               FIXME("heapalloc of %ld bytes failed\n", len);
-               return E_FAIL;
-           }
-           hres = xbuf_get(buf, (LPBYTE)rgszNames[i], len);
-           if (hres) {
-               FIXME("serialize of rgszNames[i] failed.\n");
-               return hres;
-           }
-           if (debugout) TRACE_(olerelay)("%s,",relaystr(rgszNames[i]));
-        }
-       hres = xbuf_get(buf, (LPBYTE)&args[3], sizeof(DWORD));
-       if (hres) {
-           FIXME("deserialize of lcid failed.\n");
-           return hres;
-       }
-       if (debugout) TRACE_(olerelay)("],lcid=%04lx,rgDispId=[out])",args[3]);
-        args[4] = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID) * cNames);
-    } else {
-       hres = xbuf_get(buf, (LPBYTE)args[4], sizeof(DISPID) * args[2]);
-       if (hres) {
-           FIXME("serialize of rgDispId failed.\n");
-           return hres;
-       }
-       if (debugout) {
-           TRACE_(olerelay)("dispid=[");
-           for (i=0;i<args[2];i++)
-               TRACE_(olerelay)("%08lx,",((DISPID*)args[4])[i]);
-           TRACE_(olerelay)("])");
-       }
-    }
-    return S_OK;
-}
-
-static HRESULT
-serialize_LPVOID_ptr(
-    ITypeInfo          *tinfo,
-    BOOL               writeit,
-    BOOL               debugout,
-    BOOL               dealloc,
-    TYPEDESC           *tdesc,
-    DWORD              *arg,
-    marshal_state      *buf)
-{
-    HRESULT    hres;
-    DWORD      cookie;
-
-    if ((tdesc->vt != VT_PTR)                  ||
-       (tdesc->u.lptdesc->vt != VT_PTR)        ||
-       (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
-    ) {
-       FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
-       return E_FAIL;
-    }
-    cookie = (*(DWORD*)*arg) ? 0x42424242: 0x0;
-    if (writeit) {
-       hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie));
-       if (hres)
-           return hres;
-    }
-    if (!*(DWORD*)*arg) {
-       if (debugout) TRACE_(olerelay)("<lpvoid NULL>");
-       return S_OK;
-    }
-    if (debugout)
-       TRACE_(olerelay)("ppv(%p)",*(LPUNKNOWN*)*arg);
-    if (writeit) {
-       hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg);
-       if (hres)
-           return hres;
-    }
-    if (dealloc)
-       HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
-    return S_OK;
-}
-
-static HRESULT
-serialize_DISPPARAM_ptr(
-    ITypeInfo          *tinfo,
-    BOOL               writeit,
-    BOOL               debugout,
-    BOOL               dealloc,
-    TYPEDESC           *tdesc,
-    DWORD              *arg,
-    marshal_state      *buf)
-{
-    DWORD      cookie;
-    HRESULT    hres;
-    DISPPARAMS *disp;
-    int                i;
-
-    if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
-       FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
-       return E_FAIL;
-    }
-
-    cookie = *arg ? 0x42424242 : 0x0;
-    if (writeit) {
-       hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
-       if (hres)
-           return hres;
-    }
-    if (!*arg) {
-       if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>");
-       return S_OK;
-    }
-    disp = (DISPPARAMS*)*arg;
-    if (writeit) {
-       hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs));
-       if (hres)
-           return hres;
-    }
-    if (debugout) TRACE_(olerelay)("D{");
-    for (i=0;i<disp->cArgs;i++) {
-       TYPEDESC        vtdesc;
-
-       vtdesc.vt = VT_VARIANT;
-       serialize_param(
-           tinfo,
-           writeit,
-           debugout,
-           dealloc,
-           &vtdesc,
-           (DWORD*)(disp->rgvarg+i),
-           buf
-        );
-       if (debugout && (i<disp->cArgs-1))
-           TRACE_(olerelay)(",");
-    }
-    if (dealloc)
-       HeapFree(GetProcessHeap(),0,disp->rgvarg);
-    if (writeit) {
-       hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs));
-       if (hres)
-           return hres;
-    }
-    if (debugout) TRACE_(olerelay)("}{");
-    for (i=0;i<disp->cNamedArgs;i++) {
-       TYPEDESC        vtdesc;
-
-       vtdesc.vt = VT_UINT;
-       serialize_param(
-           tinfo,
-           writeit,
-           debugout,
-           dealloc,
-           &vtdesc,
-           (DWORD*)(disp->rgdispidNamedArgs+i),
-           buf
-       );
-       if (debugout && (i<disp->cNamedArgs-1))
-           TRACE_(olerelay)(",");
-    }
-    if (debugout) TRACE_(olerelay)("}");
-    if (dealloc) {
-       HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs);
-       HeapFree(GetProcessHeap(),0,disp);
-    }
-    return S_OK;
-}
-
 static HRESULT
 deserialize_param(
     ITypeInfo          *tinfo,
@@ -1107,6 +823,14 @@ deserialize_param(
                return S_OK;
            }
        }
+        case VT_I8:
+        case VT_UI8:
+           if (readit) {
+               hres = xbuf_get(buf,(LPBYTE)arg,8);
+               if (hres) ERR("Failed to read integer 8 byte\n");
+           }
+           if (debugout) TRACE_(olerelay)("%lx%lx",arg[0],arg[1]);
+           return hres;
         case VT_ERROR:
        case VT_BOOL:
         case VT_I4:
@@ -1331,8 +1055,6 @@ deserialize_param(
                        );
                        if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
                    }
-                   if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
-                       memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
                    if (debugout) TRACE_(olerelay)("}");
                    break;
                }
@@ -1383,130 +1105,6 @@ deserialize_param(
     }
 }
 
-static HRESULT
-deserialize_LPVOID_ptr(
-    ITypeInfo          *tinfo,
-    BOOL               readit,
-    BOOL               debugout,
-    BOOL               alloc,
-    TYPEDESC           *tdesc,
-    DWORD              *arg,
-    marshal_state      *buf
-) {
-    HRESULT    hres;
-    DWORD      cookie;
-
-    if ((tdesc->vt != VT_PTR)                  ||
-       (tdesc->u.lptdesc->vt != VT_PTR)        ||
-       (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
-    ) {
-       FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
-       return E_FAIL;
-    }
-    if (alloc)
-       *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID));
-    if (readit) {
-       hres = xbuf_get(buf, (LPVOID)&cookie, sizeof(cookie));
-       if (hres)
-           return hres;
-       if (cookie != 0x42424242) {
-           *(DWORD*)*arg = 0;
-           if (debugout) TRACE_(olerelay)("<lpvoid NULL>");
-           return S_OK;
-       }
-    }
-    if (readit) {
-       hres = _unmarshal_interface(buf,&buf->iid,(LPUNKNOWN*)*arg);
-       if (hres) {
-           FIXME("_unmarshal_interface of %s , %p failed with %lx\n", debugstr_guid(&buf->iid), (LPUNKNOWN*)*arg, hres);
-           return hres;
-       }
-    }
-    if (debugout) TRACE_(olerelay)("ppv(%p)",(LPVOID)*arg);
-    return S_OK;
-}
-
-static HRESULT
-deserialize_DISPPARAM_ptr(
-    ITypeInfo          *tinfo,
-    BOOL               readit,
-    BOOL               debugout,
-    BOOL               alloc,
-    TYPEDESC           *tdesc,
-    DWORD              *arg,
-    marshal_state      *buf)
-{
-    DWORD      cookie;
-    DISPPARAMS *disps;
-    HRESULT    hres;
-    int                i;
-
-    if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
-       FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
-       return E_FAIL;
-    }
-    if (readit) {
-       hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
-       if (hres)
-           return hres;
-       if (cookie == 0) {
-           *arg = 0;
-           if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>");
-           return S_OK;
-       }
-    }
-    if (alloc)
-       *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPPARAMS));
-    disps = (DISPPARAMS*)*arg;
-    if (!readit)
-       return S_OK;
-    hres = xbuf_get(buf, (LPBYTE)&disps->cArgs, sizeof(disps->cArgs));
-    if (hres)
-       return hres;
-    if (alloc)
-        disps->rgvarg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(VARIANT)*disps->cArgs);
-    if (debugout) TRACE_(olerelay)("D{");
-    for (i=0; i< disps->cArgs; i++) {
-        TYPEDESC vdesc;
-
-       vdesc.vt = VT_VARIANT;
-       hres = deserialize_param(
-           tinfo,
-           readit,
-           debugout,
-           alloc,
-           &vdesc,
-           (DWORD*)(disps->rgvarg+i),
-           buf
-       );
-    }
-    if (debugout) TRACE_(olerelay)("}{");
-    hres = xbuf_get(buf, (LPBYTE)&disps->cNamedArgs, sizeof(disps->cNamedArgs));
-    if (hres)
-       return hres;
-    if (disps->cNamedArgs) {
-       if (alloc)
-           disps->rgdispidNamedArgs = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID)*disps->cNamedArgs);
-       for (i=0; i< disps->cNamedArgs; i++) {
-           TYPEDESC vdesc;
-
-           vdesc.vt = VT_UINT;
-           hres = deserialize_param(
-               tinfo,
-               readit,
-               debugout,
-               alloc,
-               &vdesc,
-               (DWORD*)(disps->rgdispidNamedArgs+i),
-               buf
-           );
-           if (debugout && i<(disps->cNamedArgs-1)) TRACE_(olerelay)(",");
-       }
-    }
-    if (debugout) TRACE_(olerelay)("}");
-    return S_OK;
-}
-
 /* Searches function, also in inherited interfaces */
 static HRESULT
 _get_funcdesc(
@@ -1575,18 +1173,18 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
     BSTR               fname,iname;
     BSTR               names[10];
     UINT               nrofnames;
-    int                        is_idispatch_getidsofnames = 0;
     DWORD              remoteresult = 0;
     ITypeInfo          *tinfo;
+    IRpcChannelBuffer *chanbuf;
 
     EnterCriticalSection(&tpinfo->crit);
 
     hres = _get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname);
     if (hres) {
-       ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
+        ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
         ITypeInfo_Release(tinfo);
         LeaveCriticalSection(&tpinfo->crit);
-       return E_FAIL;
+        return E_FAIL;
     }
 
     if (!tpinfo->chanbuf)
@@ -1596,6 +1194,10 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
         LeaveCriticalSection(&tpinfo->crit);
         return RPC_E_DISCONNECTED;
     }
+    chanbuf = tpinfo->chanbuf;
+    IRpcChannelBuffer_AddRef(chanbuf);
+
+    LeaveCriticalSection(&tpinfo->crit);
 
     if (relaydeb) {
        TRACE_(olerelay)("->");
@@ -1607,33 +1209,11 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
            TRACE_(olerelay)("%d",method);
        TRACE_(olerelay)("(");
     }
-    if (iname && fname && !lstrcmpW(iname,IDispatchW) && !lstrcmpW(fname,GetIDsOfNamesW))
-        is_idispatch_getidsofnames = 1;
 
     if (iname) SysFreeString(iname);
     if (fname) SysFreeString(fname);
 
     memset(&buf,0,sizeof(buf));
-    buf.iid = IID_IUnknown;
-
-    /* Special IDispatch::GetIDsOfNames() serializer */
-    if (is_idispatch_getidsofnames) {
-       hres = serialize_IDispatch_GetIDsOfNames(TRUE,relaydeb,args,&buf);
-       if (hres != S_OK) {
-           FIXME("serialize of IDispatch::GetIDsOfNames failed!\n");
-            ITypeInfo_Release(tinfo);
-            LeaveCriticalSection(&tpinfo->crit);
-           return hres;
-       }
-       goto afterserialize;
-    }
-
-    /* special QueryInterface serialize */
-    if (method == 0) {
-       xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID));
-       if (relaydeb) TRACE_(olerelay)("riid=%s,[out])",debugstr_guid((REFIID)args[0]));
-       goto afterserialize;
-    }
 
     /* normal typelib driven serializing */
 
@@ -1647,61 +1227,26 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
     xargs = args;
     for (i=0;i<fdesc->cParams;i++) {
        ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
-       BOOL    isserialized = FALSE;
        if (relaydeb) {
            if (i) TRACE_(olerelay)(",");
            if (i+1<nrofnames && names[i+1])
                TRACE_(olerelay)("%s=",relaystr(names[i+1]));
        }
        /* No need to marshal other data than FIN and any VT_PTR. */
-       if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) && (elem->tdesc.vt != VT_PTR)) {
+       if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags) && (elem->tdesc.vt != VT_PTR)) {
            xargs+=_argsize(elem->tdesc.vt);
            if (relaydeb) TRACE_(olerelay)("[out]");
            continue;
        }
-       if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
-           /* If the parameter is 'riid', we use it as interface IID
-            * for a later ppvObject serialization.
-            */
-           buf.thisisiid = !lstrcmpW(names[i+1],riidW);
-
-           /* DISPPARAMS* needs special serializer */
-           if (!lstrcmpW(names[i+1],pdispparamsW)) {
-               hres = serialize_DISPPARAM_ptr(
-                   tinfo,
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
-                   relaydeb,
-                   FALSE,
-                   &elem->tdesc,
-                   xargs,
-                   &buf
-               );
-               isserialized = TRUE;
-           }
-           if (!lstrcmpW(names[i+1],ppvObjectW)) {
-               hres = serialize_LPVOID_ptr(
-                   tinfo,
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
-                   relaydeb,
-                   FALSE,
-                   &elem->tdesc,
-                   xargs,
-                   &buf
-               );
-               if (hres == S_OK)
-                   isserialized = TRUE;
-           }
-       }
-       if (!isserialized)
-           hres = serialize_param(
-               tinfo,
-               elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
-               relaydeb,
-               FALSE,
-               &elem->tdesc,
-               xargs,
-               &buf
-           );
+       hres = serialize_param(
+           tinfo,
+           elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags,
+           relaydeb,
+           FALSE,
+           &elem->tdesc,
+           xargs,
+           &buf
+       );
 
        if (hres) {
            ERR("Failed to serialize param, hres %lx\n",hres);
@@ -1711,23 +1256,20 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
     }
     if (relaydeb) TRACE_(olerelay)(")");
 
-afterserialize:
     memset(&msg,0,sizeof(msg));
     msg.cbBuffer = buf.curoff;
     msg.iMethod  = method;
-    hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid));
+    hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid));
     if (hres) {
        ERR("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
-        LeaveCriticalSection(&tpinfo->crit);
-       return hres;
+       goto exit;
     }
     memcpy(msg.Buffer,buf.base,buf.curoff);
     if (relaydeb) TRACE_(olerelay)("\n");
-    hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);
+    hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status);
     if (hres) {
        ERR("RpcChannelBuffer SendReceive failed, %lx\n",hres);
-        LeaveCriticalSection(&tpinfo->crit);
-       return hres;
+       goto exit;
     }
 
     if (relaydeb) TRACE_(olerelay)(" status = %08lx (",status);
@@ -1739,28 +1281,11 @@ afterserialize:
     memcpy(buf.base,msg.Buffer,buf.size);
     buf.curoff = 0;
 
-    /* Special IDispatch::GetIDsOfNames() deserializer */
-    if (is_idispatch_getidsofnames) {
-       hres = deserialize_IDispatch_GetIDsOfNames(FALSE,relaydeb,args,&buf);
-       if (hres != S_OK) {
-           FIXME("deserialize of IDispatch::GetIDsOfNames failed!\n");
-           return hres;
-       }
-       goto after_deserialize;
-    }
-    /* Special QueryInterface deserializer */
-    if (method == 0) {
-       _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]);
-       if (relaydeb) TRACE_(olerelay)("[in],%p",*((DWORD**)args[1]));
-       goto after_deserialize;
-    }
-
     /* generic deserializer using typelib description */
     xargs = args;
     status = S_OK;
     for (i=0;i<fdesc->cParams;i++) {
        ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
-       BOOL    isdeserialized = FALSE;
 
        if (relaydeb) {
            if (i) TRACE_(olerelay)(",");
@@ -1772,53 +1297,15 @@ afterserialize:
            if (relaydeb) TRACE_(olerelay)("[in]");
            continue;
        }
-       if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
-           /* If the parameter is 'riid', we use it as interface IID
-            * for a later ppvObject serialization.
-            */
-           buf.thisisiid = !lstrcmpW(names[i+1],riidW);
-
-           /* deserialize DISPPARAM */
-           if (!lstrcmpW(names[i+1],pdispparamsW)) {
-               hres = deserialize_DISPPARAM_ptr(
-                   tinfo,
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
-                   relaydeb,
-                   FALSE,
-                   &(elem->tdesc),
-                   xargs,
-                   &buf
-               );
-               if (hres) {
-                   ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
-                   break;
-               }
-               isdeserialized = TRUE;
-           }
-           if (!lstrcmpW(names[i+1],ppvObjectW)) {
-               hres = deserialize_LPVOID_ptr(
-                   tinfo,
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
-                   relaydeb,
-                   FALSE,
-                   &elem->tdesc,
-                   xargs,
-                   &buf
-               );
-               if (hres == S_OK)
-                   isdeserialized = TRUE;
-           }
-       }
-       if (!isdeserialized)
-           hres = deserialize_param(
-               tinfo,
-               elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
-               relaydeb,
-               FALSE,
-               &(elem->tdesc),
-               xargs,
-               &buf
-           );
+       hres = deserialize_param(
+           tinfo,
+           elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+           relaydeb,
+           FALSE,
+           &(elem->tdesc),
+           xargs,
+           &buf
+        );
        if (hres) {
            ERR("Failed to unmarshall param, hres %lx\n",hres);
            status = hres;
@@ -1826,19 +1313,20 @@ afterserialize:
        }
        xargs += _argsize(elem->tdesc.vt);
     }
-after_deserialize:
+
     hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));
     if (hres != S_OK)
-       return hres;
+        goto exit;
     if (relaydeb) TRACE_(olerelay)(") = %08lx\n", remoteresult);
 
-    if (status != S_OK) /* OLE/COM internal error */
-       return status;
+    hres = remoteresult;
 
+exit:
     HeapFree(GetProcessHeap(),0,buf.base);
+    IRpcChannelBuffer_Release(chanbuf);
     ITypeInfo_Release(tinfo);
-    LeaveCriticalSection(&tpinfo->crit);
-    return remoteresult;
+    TRACE("-- 0x%08lx\n", hres);
+    return hres;
 }
 
 HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
@@ -1878,6 +1366,83 @@ ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)
     return 1; /* FIXME */
 }
 
+static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
+{
+    TMProxyImpl *This = (TMProxyImpl *)iface;
+    HRESULT hr;
+
+    TRACE("(%p)\n", pctinfo);
+
+    if (!This->dispatch)
+    {
+        hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
+                                     (LPVOID *)&This->dispatch);
+    }
+    if (This->dispatch)
+        hr = IDispatch_GetTypeInfoCount(This->dispatch, pctinfo);
+
+    return hr;
+}
+
+static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
+{
+    TMProxyImpl *This = (TMProxyImpl *)iface;
+    HRESULT hr = S_OK;
+
+    TRACE("(%d, %lx, %p)\n", iTInfo, lcid, ppTInfo);
+
+    if (!This->dispatch)
+    {
+        hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
+                                     (LPVOID *)&This->dispatch);
+    }
+    if (This->dispatch)
+        hr = IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo);
+
+    return hr;
+}
+
+static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
+{
+    TMProxyImpl *This = (TMProxyImpl *)iface;
+    HRESULT hr;
+
+    TRACE("(%s, %p, %d, 0x%lx, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
+
+    if (!This->dispatch)
+    {
+        hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
+                                     (LPVOID *)&This->dispatch);
+    }
+    if (This->dispatch)
+        hr = IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames,
+                                     cNames, lcid, rgDispId);
+
+    return hr;
+}
+
+static HRESULT WINAPI ProxyIDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid,
+                                            WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult,
+                                            EXCEPINFO * pExcepInfo, UINT * puArgErr)
+{
+    TMProxyImpl *This = (TMProxyImpl *)iface;
+    HRESULT hr;
+
+    TRACE("(%ld, %s, 0x%lx, 0x%x, %p, %p, %p, %p)\n", dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+    if (!This->dispatch)
+    {
+        hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
+                                     (LPVOID *)&This->dispatch);
+    }
+    if (This->dispatch)
+        hr = IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid,
+                              wFlags, pDispParams, pVarResult, pExcepInfo,
+                              puArgErr);
+
+    return hr;
+}
+
 static HRESULT WINAPI
 PSFacBuf_CreateProxy(
     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
@@ -1888,6 +1453,7 @@ PSFacBuf_CreateProxy(
     int                i, nroffuncs;
     FUNCDESC   *fdesc;
     TMProxyImpl        *proxy;
+    TYPEATTR   *typeattr;
 
     TRACE("(...%s...)\n",debugstr_guid(riid));
     hres = _get_typeinfo_for_iid(riid,&tinfo);
@@ -1901,6 +1467,7 @@ PSFacBuf_CreateProxy(
 
     assert(sizeof(TMAsmProxy) == 12);
 
+    proxy->dispatch = NULL;
     proxy->outerunknown = pUnkOuter;
     proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
     if (!proxy->asmstubs) {
@@ -1973,6 +1540,21 @@ PSFacBuf_CreateProxy(
            }
        }
     }
+
+    /* if we derive from IDispatch then defer to its proxy for its methods */
+    hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
+    if (hres == S_OK)
+    {
+        if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
+        {
+            proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount;
+            proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo;
+            proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames;
+            proxy->lpvtbl[6] = ProxyIDispatch_Invoke;
+        }
+        ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
+    }
+
     proxy->lpvtbl2     = &tmproxyvtable;
     /* one reference for the proxy */
     proxy->ref         = 1;
@@ -2072,8 +1654,7 @@ TMStubImpl_Invoke(
     marshal_state      buf;
     UINT       nrofnames;
     BSTR       names[10];
-    BSTR       fname = NULL,iname = NULL;
-    BOOL       is_idispatch_getidsofnames = 0;
+    BSTR       iname = NULL;
     ITypeInfo  *tinfo;
 
     memset(&buf,0,sizeof(buf));
@@ -2081,31 +1662,28 @@ TMStubImpl_Invoke(
     buf.base   = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);
     memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);
     buf.curoff = 0;
-    buf.iid    = IID_IUnknown;
 
     TRACE("...\n");
-    if (xmsg->iMethod == 0) { /* QI */
-       IID             xiid;
-       /* in: IID, out: <iface> */
-
-       xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid));
-       buf.curoff = 0;
-       hres = _marshal_interface(&buf,&xiid,This->pUnk);
-       xmsg->Buffer    = buf.base; /* Might have been reallocated */
-       xmsg->cbBuffer  = buf.size;
-       return hres;
+
+    if (xmsg->iMethod < 3) {
+        ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n");
+        return E_UNEXPECTED;
     }
-    hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,&fname);
+
+    hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL);
     if (hres) {
        ERR("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);
        return hres;
     }
 
-    if (iname && fname && !lstrcmpW(iname, IDispatchW) && !lstrcmpW(fname, GetIDsOfNamesW))
-       is_idispatch_getidsofnames = 1;
+    if (iname && !lstrcmpW(iname, IDispatchW))
+    {
+        ERR("IDispatch cannot be marshaled by the typelib marshaler\n");
+        ITypeInfo_Release(tinfo);
+        return E_UNEXPECTED;
+    }
 
     if (iname) SysFreeString (iname);
-    if (fname) SysFreeString (fname);
 
     /* Need them for hack below */
     memset(names,0,sizeof(names));
@@ -2121,154 +1699,55 @@ TMStubImpl_Invoke(
     args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
     if (!args) return E_OUTOFMEMORY;
 
-    if (is_idispatch_getidsofnames) {
-       hres = deserialize_IDispatch_GetIDsOfNames(TRUE,FALSE,args+1,&buf);
-       if (hres != S_OK) {
-           FIXME("deserialize_IDispatch_GetIDsOfNames failed!\n");
-           return hres;
-       }
-       xargs = args+1+5;
-       goto afterdeserialize;
-    }
-
     /* Allocate all stuff used by call. */
     xargs = args+1;
     for (i=0;i<fdesc->cParams;i++) {
        ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
-       BOOL            isdeserialized = FALSE;
 
-       if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
-           /* If the parameter is 'riid', we use it as interface IID
-            * for a later ppvObject serialization.
-            */
-           buf.thisisiid = !lstrcmpW(names[i+1],riidW);
-
-           /* deserialize DISPPARAM */
-           if (!lstrcmpW(names[i+1],pdispparamsW)) {
-               hres = deserialize_DISPPARAM_ptr(
-                   tinfo,
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
-                   FALSE,
-                   TRUE,
-                   &(elem->tdesc),
-                   xargs,
-                   &buf
-               );
-               if (hres) {
-                   ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
-                   break;
-               }
-               isdeserialized = TRUE;
-           }
-           if (!lstrcmpW(names[i+1],ppvObjectW)) {
-               hres = deserialize_LPVOID_ptr(
-                   tinfo,
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
-                   FALSE,
-                   TRUE,
-                   &elem->tdesc,
-                   xargs,
-                   &buf
-               );
-               if (hres == S_OK)
-                   isdeserialized = TRUE;
-           }
-       }
-       if (!isdeserialized)
-           hres = deserialize_param(
-               tinfo,
-               elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
-               FALSE,
-               TRUE,
-               &(elem->tdesc),
-               xargs,
-               &buf
-           );
+       hres = deserialize_param(
+          tinfo,
+          elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags,
+          FALSE,
+          TRUE,
+          &(elem->tdesc),
+          xargs,
+          &buf
+       );
        xargs += _argsize(elem->tdesc.vt);
        if (hres) {
            ERR("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres);
            break;
        }
     }
-afterdeserialize:
-    hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0]));
-    if (hres) {
-       ERR("Does not support iface %s, returning %lx\n",debugstr_guid(&(This->iid)), hres);
-       return hres;
-    }
+
+    args[0] = (DWORD)This->pUnk;
     res = _invoke(
        (*((FARPROC**)args[0]))[fdesc->oVft/4],
        fdesc->callconv,
        (xargs-args),
        args
     );
-    IUnknown_Release((LPUNKNOWN)args[0]);
     buf.curoff = 0;
 
-    /* special IDispatch::GetIDsOfNames serializer */
-    if (is_idispatch_getidsofnames) {
-       hres = serialize_IDispatch_GetIDsOfNames(FALSE,FALSE,args+1,&buf);
-       if (hres != S_OK) {
-           FIXME("serialize of IDispatch::GetIDsOfNames failed!\n");
-           return hres;
-       }
-       goto afterserialize;
-    }
     xargs = args+1;
     for (i=0;i<fdesc->cParams;i++) {
        ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
-       BOOL            isserialized = FALSE;
-
-       if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
-           /* If the parameter is 'riid', we use it as interface IID
-            * for a later ppvObject serialization.
-            */
-           buf.thisisiid = !lstrcmpW(names[i+1],riidW);
-
-           /* DISPPARAMS* needs special serializer */
-           if (!lstrcmpW(names[i+1],pdispparamsW)) {
-               hres = serialize_DISPPARAM_ptr(
-                   tinfo,
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
-                   FALSE,
-                   TRUE,
-                   &elem->tdesc,
-                   xargs,
-                   &buf
-               );
-               isserialized = TRUE;
-           }
-           if (!lstrcmpW(names[i+1],ppvObjectW)) {
-               hres = serialize_LPVOID_ptr(
-                   tinfo,
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
-                   FALSE,
-                   TRUE,
-                   &elem->tdesc,
-                   xargs,
-                   &buf
-               );
-               if (hres == S_OK)
-                   isserialized = TRUE;
-           }
-       }
-       if (!isserialized)
-           hres = serialize_param(
-              tinfo,
-              elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
-              FALSE,
-              TRUE,
-              &elem->tdesc,
-              xargs,
-              &buf
-           );
+       hres = serialize_param(
+          tinfo,
+          elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+          FALSE,
+          TRUE,
+          &elem->tdesc,
+          xargs,
+          &buf
+       );
        xargs += _argsize(elem->tdesc.vt);
        if (hres) {
            ERR("Failed to stuballoc param, hres %lx\n",hres);
            break;
        }
     }
-afterserialize:
+
     hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));
     if (hres != S_OK)
        return hres;
index 79fe164..a65cbf1 100644 (file)
@@ -5,6 +5,7 @@
  *                   1999  Rein Klazes
  *                   2000  Francois Jacques
  *                   2001  Huw D M Davies for CodeWeavers
+ *                   2005  Robert Shearman, for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -979,6 +980,7 @@ typedef struct tagITypeInfoImpl
      */
     BSTR Name;
     BSTR DocString;
+    BSTR DllName;
     unsigned long  dwHelpContext;
     unsigned long  dwHelpStringContext;
 
@@ -1072,10 +1074,19 @@ static void dump_TypeDesc(TYPEDESC *pTD,char *szVarType) {
 
 static void dump_ELEMDESC(ELEMDESC *edesc) {
   char buf[200];
+  USHORT flags = edesc->u.paramdesc.wParamFlags;
   dump_TypeDesc(&edesc->tdesc,buf);
   MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
-  MESSAGE("\t\tu.parmadesc.flags %x\n",edesc->u.paramdesc.wParamFlags);
-  MESSAGE("\t\tu.parmadesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
+  MESSAGE("\t\tu.paramdesc.wParamFlags");
+  if (!flags) MESSAGE(" PARAMFLAGS_NONE");
+  if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
+  if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
+  if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
+  if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
+  if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
+  if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
+  if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
+  MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
 }
 static void dump_FUNCDESC(FUNCDESC *funcdesc) {
   int i;
@@ -1275,6 +1286,7 @@ static void dump_TypeInfo(ITypeInfoImpl * pty)
       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));
+    if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
     dump_TLBFuncDesc(pty->funclist);
     dump_TLBVarDesc(pty->varlist);
     dump_TLBImplType(pty->impltypelist);
@@ -1437,6 +1449,11 @@ static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
     WCHAR* pwstring = NULL;
     BSTR bstrName = NULL;
 
+    if (offset < 0)
+    {
+        ERR_(typelib)("bad offset %d\n", offset);
+        return NULL;
+    }
     MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
                      pcx->pTblDir->pNametab.offset+offset);
     niName.namelen &= 0xFF; /* FIXME: correct ? */
@@ -1765,7 +1782,16 @@ MSFT_DoFuncs(TLBContext*     pcx,
 
                 (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags = paraminfo.Flags;
 
-                (*pptfd)->pParamDesc[j].Name = (void *) paraminfo.oName;
+                /* name */
+                if (paraminfo.oName == -1)
+                    /* this occurs for [propput] or [propget] methods, so
+                     * we should just set the name of the parameter to the
+                     * name of the method. */
+                    (*pptfd)->pParamDesc[j].Name = SysAllocString((*pptfd)->Name);
+                else
+                    (*pptfd)->pParamDesc[j].Name =
+                        MSFT_ReadName( pcx, paraminfo.oName );
+                TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w((*pptfd)->pParamDesc[j].Name));
 
                 /* SEEK value = jump to offset,
                  * from there jump to the end of record,
@@ -1844,10 +1870,6 @@ MSFT_DoFuncs(TLBContext*     pcx,
             /* second time around */
             for(j=0;j<pFuncRec->nrargs;j++)
             {
-                /* name */
-                (*pptfd)->pParamDesc[j].Name =
-                    MSFT_ReadName( pcx, (int)(*pptfd)->pParamDesc[j].Name );
-
                 /* default value */
                 if ( (PARAMFLAG_FHASDEFAULT &
                       (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags) &&
@@ -2029,6 +2051,7 @@ static ITypeInfoImpl * MSFT_DoTypeInfo(
     ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor();
     MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
                       pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
+
 /* this is where we are coming from */
     ptiRet->pTypeLib = pLibInfo;
     ptiRet->index=count;
@@ -2064,6 +2087,10 @@ static ITypeInfoImpl * MSFT_DoTypeInfo(
     ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
     ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
     ptiRet->dwHelpContext=tiBase.helpcontext;
+
+    if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
+        ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
+
 /* note: InfoType's Help file and HelpStringDll come from the containing
  * library. Further HelpString and Docstring appear to be the same thing :(
  */
@@ -3522,7 +3549,7 @@ static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
     ITypeLibImpl *This = (ITypeLibImpl *)iface;
     ITypeInfoImpl *pTypeInfo = This->pTypeInfo;
 
-    TRACE("(%p)->(index=%d) \n", This, index);
+    TRACE("(%p)->(index=%d)\n", This, index);
 
     if (!ppTInfo) return E_INVALIDARG;
 
@@ -3558,7 +3585,7 @@ static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
     int i;
     ITypeInfoImpl *pTInfo = This->pTypeInfo;
 
-    TRACE("(%p) index %d \n",This, index);
+    TRACE("(%p) index %d\n", This, index);
 
     if(!pTKind) return E_INVALIDARG;
 
@@ -3992,7 +4019,7 @@ static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
         }
     }else{
-        ERR(" OUT OF MEMORY! \n");
+        ERR(" OUT OF MEMORY!\n");
         return E_OUTOFMEMORY;
     }
     return S_OK;
@@ -4160,6 +4187,12 @@ static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
           This->DocString = 0;
       }
 
+      if (This->DllName)
+      {
+          SysFreeString(This->DllName);
+          This->DllName = 0;
+      }
+
       if (This->next)
       {
         ITypeInfo_Release((ITypeInfo*)This->next);
@@ -4731,7 +4764,7 @@ static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTY
     switch (tattr->typekind)
     {
     case TKIND_ENUM:
-        *vt |= VT_INT;
+        *vt |= VT_I4;
         break;
 
     case TKIND_ALIAS:
@@ -4829,46 +4862,47 @@ static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYP
 HRESULT WINAPI
 DispCallFunc(
     void* pvInstance, ULONG oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
-    VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult
-{
+    VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
+{
     int i, argsize, argspos;
     DWORD *args;
     HRESULT hres;
 
     TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
-       pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult)
-    );
-    /* DispCallFunc is only used to invoke methods belonging to an IDispatch-derived COM interface.
-    So we need to add a first parameter to the list of arguments, to supply the interface pointer */
+        pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
+        pvargResult, V_VT(pvargResult));
+
+    /* DispCallFunc is only used to invoke methods belonging to an
+     * IDispatch-derived COM interface. So we need to add a first parameter
+     * to the list of arguments, to supply the interface pointer */
     argsize = 1;
-    for (i=0;i<cActuals;i++) {
-       TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
-       dump_Variant(prgpvarg[i]);
-       argsize += _argsize(prgvt[i]);
+    for (i=0;i<cActuals;i++)
+    {
+        TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i]));
+        dump_Variant(prgpvarg[i]);
+        argsize += _argsize(prgvt[i]);
     }
     args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize);
     args[0] = (DWORD)pvInstance;      /* this is the fake IDispatch interface pointer */
     argspos = 1;
-    for (i=0;i<cActuals;i++) {
-       VARIANT *arg = prgpvarg[i];
-       TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
-       _copy_arg(NULL, NULL, &args[argspos], arg, prgvt[i]);
-       argspos += _argsize(prgvt[i]);
-    }
-
-    if(pvargResult!=NULL && V_VT(pvargResult)==VT_EMPTY)
+    for (i=0;i<cActuals;i++)
     {
-        _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
-        hres=S_OK;
+        VARIANT *arg = prgpvarg[i];
+        TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]);
+        memcpy(&args[argspos], &V_NONE(arg), _argsize(prgvt[i]) * sizeof(DWORD));
+        argspos += _argsize(prgvt[i]);
     }
-    else
+
+    hres = _invoke((*(FARPROC**)pvInstance)[oVft/sizeof(void *)],cc,argsize,args);
+    if (pvargResult && (vtReturn != VT_EMPTY))
     {
-        FIXME("Do not know how to handle pvargResult %p. Expect crash ...\n",pvargResult);
-        hres = _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args);
-        FIXME("Method returned %lx\n",hres);
+        TRACE("Method returned 0x%08lx\n",hres);
+        V_VT(pvargResult) = vtReturn;
+        V_UI4(pvargResult) = hres;
     }
+
     HeapFree(GetProcessHeap(),0,args);
-    return hres;
+    return S_OK;
 }
 
 static HRESULT WINAPI ITypeInfo_fnInvoke(
@@ -5031,7 +5065,10 @@ static HRESULT WINAPI ITypeInfo_fnInvoke(
                          * variants here too */
                         if ((V_VT(&varresult) == (VT_UNKNOWN | VT_BYREF)) ||
                             (V_VT(&varresult) == (VT_DISPATCH | VT_BYREF)))
-                            IUnknown_Release(*V_UNKNOWNREF(&varresult));
+                        {
+                            if(*V_UNKNOWNREF(&varresult))
+                                IUnknown_Release(*V_UNKNOWNREF(&varresult));
+                        }
                         break;
                    }
                }
@@ -5072,6 +5109,7 @@ func_fail:
         }
 
         ITypeInfo2_ReleaseFuncDesc(iface, func_desc);
+        TRACE("-- 0x%08lx\n", hres);
         return hres;
 
     } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
@@ -5171,18 +5209,22 @@ static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid
     ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
     TLBFuncDesc *pFDesc;
 
-    FIXME("(%p, memid %lx, %d, %p, %p, %p), partial stub!\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
+    TRACE("(%p)->(memid %lx, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
+
+    if (pBstrDllName) *pBstrDllName = NULL;
+    if (pBstrName) *pBstrName = NULL;
+    if (pwOrdinal) *pwOrdinal = 0;
+
+    if (This->TypeAttr.typekind != TKIND_MODULE)
+        return TYPE_E_BADMODULEKIND;
 
     for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next)
         if(pFDesc->funcdesc.memid==memid){
            dump_TypeInfo(This);
            dump_TLBFuncDescOne(pFDesc);
 
-           /* FIXME: This is wrong, but how do you find that out? */
-           if (pBstrDllName) {
-               static const WCHAR oleaut32W[] = {'O','L','E','A','U','T','3','2','.','D','L','L',0};
-               *pBstrDllName = SysAllocString(oleaut32W);
-           }
+           if (pBstrDllName)
+               *pBstrDllName = SysAllocString(This->DllName);
 
            if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
                if (pBstrName)
@@ -5197,7 +5239,7 @@ static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid
                *pwOrdinal = (DWORD)pFDesc->Entry;
            return S_OK;
         }
-    return E_FAIL;
+    return TYPE_E_ELEMENTNOTFOUND;
 }
 
 /* ITypeInfo::GetRefTypeInfo
@@ -5728,7 +5770,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
             VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data);
         }
     }else{
-        ERR(" OUT OF MEMORY! \n");
+        ERR(" OUT OF MEMORY!\n");
         return E_OUTOFMEMORY;
     }
     return S_OK;
@@ -5764,7 +5806,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
                         & pCData->data);
             }
         }else{
-            ERR(" OUT OF MEMORY! \n");
+            ERR(" OUT OF MEMORY!\n");
             return E_OUTOFMEMORY;
         }
         return S_OK;
@@ -5801,7 +5843,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
                         & pCData->data);
             }
         }else{
-            ERR(" OUT OF MEMORY! \n");
+            ERR(" OUT OF MEMORY!\n");
             return E_OUTOFMEMORY;
         }
         return S_OK;
@@ -5837,7 +5879,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
                         & pCData->data);
             }
         }else{
-            ERR(" OUT OF MEMORY! \n");
+            ERR(" OUT OF MEMORY!\n");
             return E_OUTOFMEMORY;
         }
         return S_OK;
@@ -5875,7 +5917,7 @@ static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
                         & pCData->data);
             }
         }else{
-            ERR(" OUT OF MEMORY! \n");
+            ERR(" OUT OF MEMORY!\n");
             return E_OUTOFMEMORY;
         }
         return S_OK;
index 031eb85..86fae31 100644 (file)
@@ -152,6 +152,7 @@ typedef struct tagMSFT_TypeInfoBase {
                                 /* or in base intefaces */
                                 /* if coclass: offset in reftable */
                                 /* if interface: reference to inherited if */
+                                /* if module: offset to dllname in name table */
         INT     datatype2;      /* if 0x8000, entry above is valid */
                                 /* actually dunno */
                                 /* else it is zero? */
index 5b58df7..9e942da 100644 (file)
@@ -537,6 +537,7 @@ HRESULT CALLBACK IDispatch_Invoke_Proxy(
   VARIANTARG* rgVarRef = NULL;
   UINT u, cVarRef;
   UINT uArgErr;
+  EXCEPINFO ExcepInfo;
 
   TRACE("(%p)->(%ld,%s,%lx,%x,%p,%p,%p,%p)\n", This,
         dispIdMember, debugstr_guid(riid),
@@ -546,6 +547,7 @@ HRESULT CALLBACK IDispatch_Invoke_Proxy(
   /* [out] args can't be null, use dummy vars if needed */
   if (!pVarResult) pVarResult = &VarResult;
   if (!puArgErr) puArgErr = &uArgErr;
+  if (!pExcepInfo) pExcepInfo = &ExcepInfo;
 
   /* count by-ref args */
   for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) {
@@ -596,6 +598,13 @@ HRESULT CALLBACK IDispatch_Invoke_Proxy(
     CoTaskMemFree(rgVarRef);
     CoTaskMemFree(rgVarRefIdx);
   }
+
+  if(pExcepInfo == &ExcepInfo)
+  {
+    SysFreeString(pExcepInfo->bstrSource);
+    SysFreeString(pExcepInfo->bstrDescription);
+    SysFreeString(pExcepInfo->bstrHelpFile);
+  }
   return hr;
 }
 
index 5c04dc5..13458a2 100644 (file)
@@ -55,7 +55,7 @@ static const WCHAR szPercentZeroStar_d[] = { '%','0','*','d','\0' };
 
 #if 0
 #define dump_tokens(rgb) do { \
-  int i_; TRACE("Tokens->{ \n"); \
+  int i_; TRACE("Tokens->{\n"); \
   for (i_ = 0; i_ < rgb[0]; i_++) \
     TRACE("%s0x%02x", i_?",":"",rgb[i_]); \
   TRACE(" }\n"); \
@@ -1598,10 +1598,11 @@ static HRESULT VARIANT_FormatDate(LPVARIANT pVarIn, LPOLESTR lpszFormat,
     case FMT_DATE_GENERAL:
       {
         BSTR date = NULL;
-        WCHAR *pDate = date;
-        hRes = VarBstrFromDate(V_DATE(&vDate), lcid, 0, pbstrOut);
+        WCHAR *pDate;
+        hRes = VarBstrFromDate(V_DATE(&vDate), lcid, 0, &date);
         if (FAILED(hRes))
           goto VARIANT_FormatDate_Exit;
+       pDate = date;
         while (*pDate)
           *pBuff++ = *pDate++;
         SysFreeString(date);
@@ -1623,10 +1624,11 @@ static HRESULT VARIANT_FormatDate(LPVARIANT pVarIn, LPOLESTR lpszFormat,
       {
         /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */
         BSTR date = NULL;
-        WCHAR *pDate = date;
-        hRes = VarBstrFromDate(V_DATE(&vDate), lcid, VAR_TIMEVALUEONLY, pbstrOut);
+        WCHAR *pDate;
+        hRes = VarBstrFromDate(V_DATE(&vDate), lcid, VAR_TIMEVALUEONLY, &date);
         if (FAILED(hRes))
           goto VARIANT_FormatDate_Exit;
+       pDate = date;
         while (*pDate)
           *pBuff++ = *pDate++;
         SysFreeString(date);
index 9305d3f..953595b 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(variant);
 
-const char* wine_vtypes[VT_CLSID] =
+const char* wine_vtypes[VT_CLSID+1] =
 {
   "VT_EMPTY","VT_NULL","VT_I2","VT_I4","VT_R4","VT_R8","VT_CY","VT_DATE",
   "VT_BSTR","VT_DISPATCH","VT_ERROR","VT_BOOL","VT_VARIANT","VT_UNKNOWN",
   "VT_DECIMAL","15","VT_I1","VT_UI1","VT_UI2","VT_UI4","VT_I8","VT_UI8",
   "VT_INT","VT_UINT","VT_VOID","VT_HRESULT","VT_PTR","VT_SAFEARRAY",
-  "VT_CARRAY","VT_USERDEFINED","VT_LPSTR","VT_LPWSTR""32","33","34","35",
+  "VT_CARRAY","VT_USERDEFINED","VT_LPSTR","VT_LPWSTR","32","33","34","35",
   "VT_RECORD","VT_INT_PTR","VT_UINT_PTR","39","40","41","42","43","44","45",
   "46","47","48","49","50","51","52","53","54","55","56","57","58","59","60",
   "61","62","63","VT_FILETIME","VT_BLOB","VT_STREAM","VT_STORAGE",
@@ -2512,11 +2512,14 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
 {
     BOOL       lOk        = TRUE;
     BOOL       rOk        = TRUE;
+    BOOL       l_isR      = FALSE;
+    BOOL       r_isR      = FALSE;
     LONGLONG   lVal = -1;
     LONGLONG   rVal = -1;
     VARIANT    rv,lv;
     DWORD      xmask;
     HRESULT    rc;
+    double     lDouble =0.0,rDouble=0.0;
 
     TRACE("(%p->(%s%s),%p->(%s%s),0x%08lx,0x%08lx)\n", left, debugstr_VT(left),
           debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), lcid, flags);
@@ -2537,6 +2540,13 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
     }
 
     xmask = (1<<(V_VT(left)&VT_TYPEMASK))|(1<<(V_VT(right)&VT_TYPEMASK));
+    if (xmask & VTBIT_DECIMAL) {
+       rc = VariantChangeType(&lv,left,0,VT_DECIMAL);
+       if (FAILED(rc)) return rc;
+       rc = VariantChangeType(&rv,right,0,VT_DECIMAL);
+       if (FAILED(rc)) return rc;
+        return VarDecCmp(&V_DECIMAL(&lv), &V_DECIMAL(&rv));
+    }
     if (xmask & VTBIT_R8) {
        rc = VariantChangeType(&lv,left,0,VT_R8);
        if (FAILED(rc)) return rc;
@@ -2574,6 +2584,8 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
     case VT_UINT : lVal = V_UI4(left); break;
     case VT_BOOL : lVal = V_BOOL(left); break;
     case VT_EMPTY : lVal = 0; break;
+    case VT_R4 : lDouble = V_R4(left); lOk = FALSE; l_isR= TRUE; break;
+    case VT_R8 : lDouble = V_R8(left); lOk = FALSE; l_isR= TRUE; break;
     default: lOk = FALSE;
     }
 
@@ -2589,6 +2601,8 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
     case VT_UINT : rVal = V_UI4(right); break;
     case VT_BOOL : rVal = V_BOOL(right); break;
     case VT_EMPTY : rVal = 0; break;
+    case VT_R4 : rDouble = V_R4(right); rOk = FALSE;r_isR= TRUE; break;
+    case VT_R8 : rDouble = V_R8(right); rOk = FALSE;r_isR= TRUE; break;
     default: rOk = FALSE;
     }
 
@@ -2601,7 +2615,47 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
             return VARCMP_EQ;
         }
     }
-
+    else if (l_isR && r_isR) {
+        if (lDouble < rDouble) {
+            return VARCMP_LT;
+        } else if (lDouble > rDouble) {
+            return VARCMP_GT;
+        } else {
+            return VARCMP_EQ;
+        }
+    }
+    else if (lOk && r_isR) {
+        if (lVal < rDouble) {
+            return VARCMP_LT;
+        } else if (lVal > rDouble) {
+            return VARCMP_GT;
+        } else {
+            return VARCMP_EQ;
+        }
+    }
+    else if (l_isR && rOk) {
+        if (lDouble < rVal) {
+            return VARCMP_LT;
+        } else if (lDouble > rVal) {
+            return VARCMP_GT;
+        } else {
+            return VARCMP_EQ;
+        }
+    }
+    if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR ) {
+       if(((V_VT(right)&VT_TYPEMASK) == VT_EMPTY ) && !(V_BSTR(left))) {
+           return VARCMP_EQ;
+       } else {
+           return VARCMP_GT;
+       }
+    }
+    if ((V_VT(right)&VT_TYPEMASK) == VT_BSTR ) {
+       if(((V_VT(left)&VT_TYPEMASK) == VT_EMPTY ) && !(V_BSTR(right))) {
+           return VARCMP_EQ;
+       } else {
+           return VARCMP_LT;
+       }
+    }
     /* Dates */
     if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
         (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
@@ -2635,7 +2689,9 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
             return VARCMP_GT;
         }
     }
-    FIXME("VarCmp partial implementation, doesn't support vt 0x%x / 0x%x\n",V_VT(left), V_VT(right));
+    else if((V_VT(right)&VT_TYPEMASK) == VT_EMPTY)
+        return VARCMP_GT;
+    FIXME("VarCmp partial implementation, doesn't support %s / %s\n",wine_vtypes[V_VT(left)], wine_vtypes[V_VT(right)]);
     return E_FAIL;
 }
 
@@ -3120,7 +3176,7 @@ HRESULT WINAPI VarDiv(LPVARIANT left, LPVARIANT right, LPVARIANT result)
     lvt = V_VT(left)&VT_TYPEMASK;
     rvt = V_VT(right)&VT_TYPEMASK;
     found = FALSE;resvt = VT_VOID;
-    if (((1<<lvt) | (1<<rvt)) & (VTBIT_R4|VTBIT_R8)) {
+    if (((1<<lvt) | (1<<rvt)) & (VTBIT_R4|VTBIT_R8|VTBIT_CY)) {
        found = TRUE;
        resvt = VT_R8;
     }
index ec54eb3..2075827 100644 (file)
@@ -4594,6 +4594,600 @@ VarDecAdd_AsPositive:
   return hRet;
 }
 
+/* internal representation of the value stored in a DECIMAL. The bytes are
+   stored from LSB at index 0 to MSB at index 11
+ */
+typedef struct DECIMAL_internal
+{
+    DWORD bitsnum[3];  /* 96 significant bits, unsigned */
+    unsigned char scale;      /* number scaled * 10 ^ -(scale) */
+    unsigned int  sign : 1;   /* 0 - positive, 1 - negative */
+} VARIANT_DI;
+
+/* translate from external DECIMAL format into an internal representation */
+static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
+{
+    to->scale = DEC_SCALE(from);
+    to->sign = DEC_SIGN(from) ? 1 : 0;
+
+    to->bitsnum[0] = DEC_LO32(from);
+    to->bitsnum[1] = DEC_MID32(from);
+    to->bitsnum[2] = DEC_HI32(from);
+}
+
+static void VARIANT_DecFromDI(VARIANT_DI * from, DECIMAL * to)
+{
+    if (from->sign) {
+        DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
+    } else {
+        DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
+    }
+
+    DEC_LO32(to) = from->bitsnum[0];
+    DEC_MID32(to) = from->bitsnum[1];
+    DEC_HI32(to) = from->bitsnum[2];
+}
+
+/* clear an internal representation of a DECIMAL */
+static void VARIANT_DI_clear(VARIANT_DI * i)
+{
+    memset(i, 0, sizeof(VARIANT_DI));
+}
+
+/* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
+   size is supported. The value in p is replaced by the quotient of the division, and
+   the remainder is returned as a result. This routine is most often used with a divisor
+   of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
+ */
+static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
+{
+    if (divisor == 0) {
+        /* division by 0 */
+        return 0xFF;
+    } else if (divisor == 1) {
+        /* dividend remains unchanged */
+        return 0;
+    } else {
+        unsigned char remainder = 0;
+        ULONGLONG iTempDividend;
+        signed int i;
+        
+        for (i = n - 1; i >= 0 && !p[i]; i--);  /* skip leading zeros */
+        for (; i >= 0; i--) {
+            iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
+            remainder = iTempDividend % divisor;
+            p[i] = iTempDividend / divisor;
+        }
+        
+        return remainder;
+    }
+}
+
+/* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
+static int VARIANT_int_iszero(DWORD * p, unsigned int n)
+{
+    for (; n > 0; n--) if (*p++ != 0) return 0;
+    return 1;
+}
+
+/* multiply two DECIMALS, without changing either one, and place result in third
+   parameter. Result is normalized when scale is > 0. Attempts to remove significant
+   digits when scale > 0 in order to fit an overflowing result. Final overflow
+   flag is returned.
+ */
+static int VARIANT_DI_mul(VARIANT_DI * a, VARIANT_DI * b, VARIANT_DI * result)
+{
+    int r_overflow = 0;
+    DWORD running[6];
+    signed int mulstart;
+
+    VARIANT_DI_clear(result);
+    result->sign = (a->sign ^ b->sign) ? 1 : 0;
+
+    /* Multiply 128-bit operands into a (max) 256-bit result. The scale
+       of the result is formed by adding the scales of the operands.
+     */
+    result->scale = a->scale + b->scale;
+    memset(running, 0, sizeof(running));
+
+    /* count number of leading zero-bytes in operand A */
+    for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
+    if (mulstart < 0) {
+        /* result is 0, because operand A is 0 */
+        result->scale = 0;
+        result->sign = 0;
+    } else {
+        unsigned char remainder = 0;
+        int iA;        
+
+        /* perform actual multiplication */
+        for (iA = 0; iA <= mulstart; iA++) {
+            ULONG iOverflowMul;
+            int iB;
+            
+            for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
+                ULONG iRV;
+                int iR;
+                
+                iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
+                iR = iA + iB;
+                do {
+                    running[iR] = VARIANT_Add(running[iR], 0, &iRV);
+                    iR++;
+                } while (iRV);
+            }
+        }
+
+/* Too bad - native oleaut does not do this, so we should not either */
+#if 0
+        /* While the result is divisible by 10, and the scale > 0, divide by 10.
+           This operation should not lose significant digits, and gives an
+           opportunity to reduce the possibility of overflows in future
+           operations issued by the application.
+         */
+        while (result->scale > 0) {
+            memcpy(quotient, running, sizeof(quotient));
+            remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
+            if (remainder > 0) break;
+            memcpy(running, quotient, sizeof(quotient));
+            result->scale--;
+        }
+#endif
+        /* While the 256-bit result overflows, and the scale > 0, divide by 10.
+           This operation *will* lose significant digits of the result because
+           all the factors of 10 were consumed by the previous operation.
+        */
+        while (result->scale > 0 && !VARIANT_int_iszero(
+            running + sizeof(result->bitsnum) / sizeof(DWORD),
+            (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
+            
+            remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
+            if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
+            result->scale--;
+        }
+        
+        /* round up the result - native oleaut32 does this */
+        if (remainder >= 5) {
+            unsigned int i;
+            for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
+                ULONGLONG digit = running[i] + 1;
+                remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
+                running[i] = digit & 0xFFFFFFFF;
+            }
+        }
+
+        /* Signal overflow if scale == 0 and 256-bit result still overflows,
+           and copy result bits into result structure
+        */
+        r_overflow = !VARIANT_int_iszero(
+            running + sizeof(result->bitsnum)/sizeof(DWORD), 
+            (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
+        memcpy(result->bitsnum, running, sizeof(result->bitsnum));
+    }
+    return r_overflow;
+}
+
+/* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
+   hardcoded (period for decimal separator, dash as negative sign). Returns 0 for
+   success, nonzero if insufficient space in output buffer.
+ */
+static int VARIANT_DI_tostringW(VARIANT_DI * a, WCHAR * s, unsigned int n)
+{
+    int overflow = 0;
+    DWORD quotient[3];
+    unsigned char remainder;
+    unsigned int i;
+
+    /* place negative sign */
+    if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
+        if (n > 0) {
+            *s++ = '-';
+            n--;
+        }
+        else overflow = 1;
+    }
+
+    /* prepare initial 0 */
+    if (!overflow) {
+        if (n >= 2) {
+            s[0] = '0';
+            s[1] = '\0';
+        } else overflow = 1;
+    }
+
+    i = 0;
+    memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
+    while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
+        remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
+        if (i + 2 > n) {
+            overflow = 1;
+        } else {
+            s[i++] = '0' + remainder;
+            s[i] = '\0';
+        }
+    }
+
+    if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
+
+        /* reverse order of digits */
+        WCHAR * x = s; WCHAR * y = s + i - 1;
+        while (x < y) {
+            *x ^= *y;
+            *y ^= *x;
+            *x++ ^= *y--;
+        }
+
+        /* check for decimal point. "i" now has string length */
+        if (i <= a->scale) {
+            unsigned int numzeroes = a->scale + 1 - i;
+            if (i + 1 + numzeroes >= n) {
+                overflow = 1;
+            } else {
+                memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
+                i += numzeroes;
+                while (numzeroes > 0) {
+                    s[--numzeroes] = '0';
+                }
+            }
+        }
+
+        /* place decimal point */
+        if (a->scale > 0) {
+            unsigned int periodpos = i - a->scale;
+            if (i + 2 >= n) {
+                overflow = 1;
+            } else {
+                memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
+                s[periodpos] = '.'; i++;
+                
+                /* remove extra zeros at the end, if any */
+                while (s[i - 1] == '0') s[--i] = '\0';
+                if (s[i - 1] == '.') s[--i] = '\0';
+            }
+        }
+    }
+
+    return overflow;
+}
+
+/* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
+static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
+{
+    DWORD shifted;
+    unsigned int i;
+    
+    /* shift whole DWORDs to the left */
+    while (shift >= 32)
+    {
+        memmove(p + 1, p, (n - 1) * sizeof(DWORD));
+        *p = 0; shift -= 32;
+    }
+    
+    /* shift remainder (1..31 bits) */
+    shifted = 0;
+    if (shift > 0) for (i = 0; i < n; i++)
+    {
+        DWORD b;
+        b = p[i] >> (32 - shift);
+        p[i] = (p[i] << shift) | shifted;
+        shifted = b;
+    }
+}
+
+/* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
+   Value at v is incremented by the value at p. Any size is supported, provided
+   that v is not shorter than p. Any unapplied carry is returned as a result.
+ */
+static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, DWORD * p, 
+    unsigned int np)
+{
+    unsigned char carry = 0;
+
+    if (nv >= np) {
+        ULONGLONG sum;
+        unsigned int i;
+
+        for (i = 0; i < np; i++) {
+            sum = (ULONGLONG)v[i]
+                + (ULONGLONG)p[i]
+                + (ULONGLONG)carry;
+            v[i] = sum & 0xffffffff;
+            carry = sum >> 32;
+        }
+        for (; i < nv && carry; i++) {
+            sum = (ULONGLONG)v[i]
+                + (ULONGLONG)carry;
+            v[i] = sum & 0xffffffff;
+            carry = sum >> 32;
+        }
+    }
+    return carry;
+}
+
+/* perform integral division with operand p as dividend. Parameter n indicates 
+   number of available DWORDs in divisor p, but available space in p must be 
+   actually at least 2 * n DWORDs, because the remainder of the integral 
+   division is built in the next n DWORDs past the start of the quotient. This 
+   routine replaces the dividend in p with the quotient, and appends n 
+   additional DWORDs for the remainder.
+
+   Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
+   C/C++ :-) where the "longhand binary division" algorithm was exposed for the
+   source code to the VLI (Very Large Integer) division operator. This algorithm
+   was then heavily modified by me (Alex Villacis Lasso) in order to handle
+   variably-scaled integers such as the MS DECIMAL representation.
+ */
+static void VARIANT_int_div(DWORD * p, unsigned int n, DWORD * divisor,
+    unsigned int dn)
+{
+    unsigned int i;
+    DWORD tempsub[8];
+    DWORD * negdivisor = tempsub + n;
+
+    /* build 2s-complement of divisor */
+    for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
+    p[n] = 1;
+    VARIANT_int_add(negdivisor, n, p + n, 1);
+    memset(p + n, 0, n * sizeof(DWORD));
+
+    /* skip all leading zero DWORDs in quotient */
+    for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
+    /* i is now number of DWORDs left to process */
+    for (i <<= 5; i < (n << 5); i++) {
+        VARIANT_int_shiftleft(p, n << 1, 1);    /* shl quotient+remainder */
+
+        /* trial subtraction */
+        memcpy(tempsub, p + n, n * sizeof(DWORD));
+        VARIANT_int_add(tempsub, n, negdivisor, n);
+
+        /* check whether result of subtraction was negative */
+        if ((tempsub[n - 1] & 0x80000000) == 0) {
+            memcpy(p + n, tempsub, n * sizeof(DWORD));
+            p[0] |= 1;
+        }
+    }
+}
+
+/* perform integral multiplication by a byte operand. Used for scaling by 10 */
+static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
+{
+    unsigned int i;
+    ULONG iOverflowMul;
+    
+    for (iOverflowMul = 0, i = 0; i < n; i++)
+        p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
+    return (unsigned char)iOverflowMul;
+}
+
+/* increment value in A by the value indicated in B, with scale adjusting. 
+   Modifies parameters by adjusting scales. Returns 0 if addition was 
+   successful, nonzero if a parameter underflowed before it could be 
+   successfully used in the addition.
+ */
+static int VARIANT_int_addlossy(
+    DWORD * a, int * ascale, unsigned int an,
+    DWORD * b, int * bscale, unsigned int bn)
+{
+    int underflow = 0;
+
+    if (VARIANT_int_iszero(a, an)) {
+        /* if A is zero, copy B into A, after removing digits */
+        while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
+            VARIANT_int_divbychar(b, bn, 10);
+            (*bscale)--;
+        }
+        memcpy(a, b, an * sizeof(DWORD));
+        *ascale = *bscale;
+    } else if (!VARIANT_int_iszero(b, bn)) {
+        unsigned int tn = an + 1;
+        DWORD t[5];
+
+        if (bn + 1 > tn) tn = bn + 1;
+        if (*ascale != *bscale) {
+            /* first (optimistic) try - try to scale down the one with the bigger
+               scale, while this number is divisible by 10 */
+            DWORD * digitchosen;
+            unsigned int nchosen;
+            int * scalechosen;
+            int targetscale;
+
+            if (*ascale < *bscale) {
+                targetscale = *ascale;
+                scalechosen = bscale;
+                digitchosen = b;
+                nchosen = bn;
+            } else {
+                targetscale = *bscale;
+                scalechosen = ascale;
+                digitchosen = a;
+                nchosen = an;
+            }
+            memset(t, 0, tn * sizeof(DWORD));
+            memcpy(t, digitchosen, nchosen * sizeof(DWORD));
+
+            /* divide by 10 until target scale is reached */
+            while (*scalechosen > targetscale) {
+                unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
+                if (!remainder) {
+                    (*scalechosen)--;
+                    memcpy(digitchosen, t, nchosen * sizeof(DWORD));
+                } else break;
+            }
+        }
+
+        if (*ascale != *bscale) {
+            DWORD * digitchosen;
+            unsigned int nchosen;
+            int * scalechosen;
+            int targetscale;
+
+            /* try to scale up the one with the smaller scale */
+            if (*ascale > *bscale) {
+                targetscale = *ascale;
+                scalechosen = bscale;
+                digitchosen = b;
+                nchosen = bn;
+            } else {
+                targetscale = *bscale;
+                scalechosen = ascale;
+                digitchosen = a;
+                nchosen = an;
+            }
+            memset(t, 0, tn * sizeof(DWORD));
+            memcpy(t, digitchosen, nchosen * sizeof(DWORD));
+
+            /* multiply by 10 until target scale is reached, or
+               significant bytes overflow the number
+             */
+            while (*scalechosen < targetscale && t[nchosen] == 0) {
+                VARIANT_int_mulbychar(t, tn, 10);
+                if (t[nchosen] == 0) {
+                    /* still does not overflow */
+                    (*scalechosen)++;
+                    memcpy(digitchosen, t, nchosen * sizeof(DWORD));
+                }
+            }
+        }
+
+        if (*ascale != *bscale) {
+            /* still different? try to scale down the one with the bigger scale
+               (this *will* lose significant digits) */
+            DWORD * digitchosen;
+            unsigned int nchosen;
+            int * scalechosen;
+            int targetscale;
+
+            if (*ascale < *bscale) {
+                targetscale = *ascale;
+                scalechosen = bscale;
+                digitchosen = b;
+                nchosen = bn;
+            } else {
+                targetscale = *bscale;
+                scalechosen = ascale;
+                digitchosen = a;
+                nchosen = an;
+            }
+            memset(t, 0, tn * sizeof(DWORD));
+            memcpy(t, digitchosen, nchosen * sizeof(DWORD));
+
+            /* divide by 10 until target scale is reached */
+            while (*scalechosen > targetscale) {
+                VARIANT_int_divbychar(t, tn, 10);
+                (*scalechosen)--;
+                memcpy(digitchosen, t, nchosen * sizeof(DWORD));
+            }
+        }
+
+        /* check whether any of the operands still has significant digits
+           (underflow case 1)
+         */
+        if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
+            underflow = 1;
+        } else {
+            /* at this step, both numbers have the same scale and can be added
+               as integers. However, the result might not fit in A, so further
+               scaling down might be necessary.
+             */
+            while (!underflow) {
+                memset(t, 0, tn * sizeof(DWORD));
+                memcpy(t, a, an * sizeof(DWORD));
+
+                VARIANT_int_add(t, tn, b, bn);
+                if (VARIANT_int_iszero(t + an, tn - an)) {
+                    /* addition was successful */
+                    memcpy(a, t, an * sizeof(DWORD));
+                    break;
+                } else {
+                    /* addition overflowed - remove significant digits
+                       from both operands and try again */
+                    VARIANT_int_divbychar(a, an, 10); (*ascale)--;
+                    VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
+                    /* check whether any operand keeps significant digits after
+                       scaledown (underflow case 2)
+                     */
+                    underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
+                }
+            }
+        }
+    }
+    return underflow;
+}
+
+/* perform complete DECIMAL division in the internal representation. Returns
+   0 if the division was completed (even if quotient is set to 0), or nonzero
+   in case of quotient overflow.
+ */
+static HRESULT VARIANT_DI_div(VARIANT_DI * dividend, VARIANT_DI * divisor, VARIANT_DI * quotient)
+{
+    HRESULT r_overflow = S_OK;
+
+    if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
+        /* division by 0 */
+        r_overflow = DISP_E_DIVBYZERO;
+    } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
+        VARIANT_DI_clear(quotient);
+    } else {
+        int quotientscale, remainderscale, tempquotientscale;
+        DWORD remainderplusquotient[8];
+        int underflow;
+
+        quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
+        tempquotientscale = quotientscale;
+        VARIANT_DI_clear(quotient);
+        quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
+
+        /*  The following strategy is used for division
+            1) if there was a nonzero remainder from previous iteration, use it as
+               dividend for this iteration, else (for first iteration) use intended
+               dividend
+            2) perform integer division in temporary buffer, develop quotient in
+               low-order part, remainder in high-order part
+            3) add quotient from step 2 to final result, with possible loss of
+               significant digits
+            4) multiply integer part of remainder by 10, while incrementing the
+               scale of the remainder. This operation preserves the intended value
+               of the remainder.
+            5) loop to step 1 until one of the following is true:
+                a) remainder is zero (exact division achieved)
+                b) addition in step 3 fails to modify bits in quotient (remainder underflow)
+         */
+        memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
+        memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
+        do {
+            VARIANT_int_div(
+                remainderplusquotient, 4,
+                divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
+            underflow = VARIANT_int_addlossy(
+                quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
+                remainderplusquotient, &tempquotientscale, 4);
+            VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
+            memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
+            tempquotientscale = ++remainderscale;
+        } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
+
+        /* quotient scale might now be negative (extremely big number). If, so, try
+           to multiply quotient by 10 (without overflowing), while adjusting the scale,
+           until scale is 0. If this cannot be done, it is a real overflow.
+         */
+        while (!r_overflow && quotientscale < 0) {
+            memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
+            memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
+            VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
+            if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
+                (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
+                quotientscale++;
+                memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
+            } else r_overflow = DISP_E_OVERFLOW;
+        }
+        if (!r_overflow) {
+            if (quotientscale <= 255) quotient->scale = quotientscale;
+            else VARIANT_DI_clear(quotient);
+        }
+    }
+    return r_overflow;
+}
+
 /************************************************************************
  * VarDecDiv (OLEAUT32.178)
  *
@@ -4610,8 +5204,59 @@ VarDecAdd_AsPositive:
  */
 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
 {
-  FIXME("(%p,%p,%p)-stub!\n",pDecLeft,pDecRight,pDecOut);
-  return DISP_E_OVERFLOW;
+  HRESULT hRet = S_OK;
+  VARIANT_DI di_left, di_right, di_result;
+  HRESULT divresult;
+
+  if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
+
+  VARIANT_DIFromDec(pDecLeft, &di_left);
+  VARIANT_DIFromDec(pDecRight, &di_right);
+  divresult = VARIANT_DI_div(&di_left, &di_right, &di_result);
+  if (divresult)
+  {
+      /* division actually overflowed */
+      hRet = divresult;
+  }
+  else
+  {
+      hRet = S_OK;
+
+      if (di_result.scale > DEC_MAX_SCALE)
+      {
+        unsigned char remainder = 0;
+      
+        /* division underflowed. In order to comply with the MSDN
+           specifications for DECIMAL ranges, some significant digits
+           must be removed
+         */
+        WARN("result scale is %u, scaling (with loss of significant digits)...\n",
+            di_result.scale);
+        while (di_result.scale > DEC_MAX_SCALE && 
+               !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
+        {
+            remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
+            di_result.scale--;
+        }
+        if (di_result.scale > DEC_MAX_SCALE)
+        {
+            WARN("result underflowed, setting to 0\n");
+            di_result.scale = 0;
+            di_result.sign = 0;
+        }
+        else if (remainder >= 5)    /* round up result - native oleaut32 does this */
+        {
+            unsigned int i;
+            for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
+                ULONGLONG digit = di_result.bitsnum[i] + 1;
+                remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
+                di_result.bitsnum[i] = digit & 0xFFFFFFFF;
+            }
+        }
+      }
+      VARIANT_DecFromDI(&di_result, pDecOut);
+  }
+  return hRet;
 }
 
 /************************************************************************
@@ -4630,42 +5275,44 @@ HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECI
  */
 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
 {
-  /* FIXME: This only allows multiplying by a fixed integer <= 0xffffffff */
+  HRESULT hRet = S_OK;
+  VARIANT_DI di_left, di_right, di_result;
+  int mulresult;
 
-  if (!DEC_SCALE(pDecLeft) || !DEC_SCALE(pDecRight))
+  VARIANT_DIFromDec(pDecLeft, &di_left);
+  VARIANT_DIFromDec(pDecRight, &di_right);
+  mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
+  if (mulresult)
   {
-    /* At least one term is an integer */
-    const DECIMAL* pDecInteger = DEC_SCALE(pDecLeft) ? pDecRight : pDecLeft;
-    const DECIMAL* pDecOperand = DEC_SCALE(pDecLeft) ? pDecLeft  : pDecRight;
-    HRESULT hRet = S_OK;
-    unsigned int multiplier = DEC_LO32(pDecInteger);
-    ULONG overflow = 0;
-
-    if (DEC_HI32(pDecInteger) || DEC_MID32(pDecInteger))
-    {
-      FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
-      return DISP_E_OVERFLOW;
-    }
-
-    DEC_LO32(pDecOut)  = VARIANT_Mul(DEC_LO32(pDecOperand),  multiplier, &overflow);
-    DEC_MID32(pDecOut) = VARIANT_Mul(DEC_MID32(pDecOperand), multiplier, &overflow);
-    DEC_HI32(pDecOut)  = VARIANT_Mul(DEC_HI32(pDecOperand),  multiplier, &overflow);
-
-    if (overflow)
-       hRet = DISP_E_OVERFLOW;
-    else
+    /* multiplication actually overflowed */
+    hRet = DISP_E_OVERFLOW;
+  }
+  else
+  {
+    if (di_result.scale > DEC_MAX_SCALE)
     {
-      BYTE sign = DECIMAL_POS;
-
-      if (DEC_SIGN(pDecLeft) != DEC_SIGN(pDecRight))
-        sign = DECIMAL_NEG; /* pos * neg => negative */
-      DEC_SIGN(pDecOut) = sign;
-      DEC_SCALE(pDecOut) = DEC_SCALE(pDecOperand);
+      /* multiplication underflowed. In order to comply with the MSDN
+         specifications for DECIMAL ranges, some significant digits
+         must be removed
+       */
+      WARN("result scale is %u, scaling (with loss of significant digits)...\n",
+          di_result.scale);
+      while (di_result.scale > DEC_MAX_SCALE && 
+            !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
+      {
+        VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
+        di_result.scale--;
+      }
+      if (di_result.scale > DEC_MAX_SCALE)
+      {
+        WARN("result underflowed, setting to 0\n");
+        di_result.scale = 0;
+        di_result.sign = 0;
+      }
     }
-    return hRet;
+    VARIANT_DecFromDI(&di_result, pDecOut);
   }
-  FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut);
-  return DISP_E_OVERFLOW;
+  return hRet;
 }
 
 /************************************************************************
@@ -5409,6 +6056,58 @@ HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
   return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
 }
 
+static BSTR VARIANT_BstrReplaceDecimal(WCHAR * buff, LCID lcid, ULONG dwFlags)
+{
+  BSTR bstrOut;
+  WCHAR lpDecimalSep[16];
+
+  /* Native oleaut32 uses the locale-specific decimal separator even in the
+     absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin 
+     American locales will see "one thousand and one tenth" as "1000,1" 
+     instead of "1000.1" (notice the comma). The following code checks for
+     the need to replace the decimal separator, and if so, will prepare an
+     appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
+   */
+  GetLocaleInfoW(lcid, LOCALE_SDECIMAL, lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
+  if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
+  {
+    /* locale is compatible with English - return original string */
+    bstrOut = SysAllocString(buff);
+  }
+  else
+  {
+    WCHAR *p;
+    WCHAR numbuff[256];
+    WCHAR empty[1] = {'\0'};
+    NUMBERFMTW minFormat;
+
+    minFormat.NumDigits = 0;
+    minFormat.LeadingZero = 0;
+    minFormat.Grouping = 0;
+    minFormat.lpDecimalSep = lpDecimalSep;
+    minFormat.lpThousandSep = empty;
+    minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
+
+    /* count number of decimal digits in string */
+    p = strchrW( buff, '.' );
+    if (p) minFormat.NumDigits = strlenW(p + 1);
+
+    numbuff[0] = '\0';
+    if (!GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
+                   buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
+    {
+      WARN("GetNumberFormatW() failed, returning raw number string instead\n");
+      bstrOut = SysAllocString(buff);
+    }
+    else
+    {
+      TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
+      bstrOut = SysAllocString(numbuff);
+    }
+  }
+  return bstrOut;
+}
+
 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
                                     BSTR* pbstrOut, LPCWSTR lpszFormat)
 {
@@ -5445,52 +6144,7 @@ static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
   }
   else
   {
-    WCHAR lpDecimalSep[16];
-
-    /* Native oleaut32 uses the locale-specific decimal separator even in the
-       absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin 
-       American locales will see "one thousand and one tenth" as "1000,1" 
-       instead of "1000.1" (notice the comma). The following code checks for
-       the need to replace the decimal separator, and if so, will prepare an
-       appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
-     */
-    GetLocaleInfoW(lcid, LOCALE_SDECIMAL, lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
-    if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
-    {
-      /* locale is compatible with English - return original string */
-      *pbstrOut = SysAllocString(buff);
-    }
-    else
-    {
-      WCHAR *p;
-      WCHAR numbuff[256];
-      WCHAR empty[1] = {'\0'};
-      NUMBERFMTW minFormat;
-
-      minFormat.NumDigits = 0;
-      minFormat.LeadingZero = 0;
-      minFormat.Grouping = 0;
-      minFormat.lpDecimalSep = lpDecimalSep;
-      minFormat.lpThousandSep = empty;
-      minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
-
-      /* count number of decimal digits in string */
-      p = strchrW( buff, '.' );
-      if (p) minFormat.NumDigits = strlenW(p + 1);
-
-      numbuff[0] = '\0';
-      if (!GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
-                     buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
-      {
-        WARN("GetNumberFormatW() failed, returning raw number string instead\n");
-        *pbstrOut = SysAllocString(buff);
-      }
-      else
-      {
-        TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
-        *pbstrOut = SysAllocString(numbuff);
-      }
-    }
+    *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
   }
   return *pbstrOut ? S_OK : E_OUTOFMEMORY;
 }
@@ -5812,25 +6466,33 @@ HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrO
  */
 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
 {
+  WCHAR buff[256];
+  VARIANT_DI temp;
+
   if (!pbstrOut)
     return E_INVALIDARG;
 
-  if (!DEC_SCALE(pDecIn) && !DEC_HI32(pDecIn))
-  {
-    WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
+  VARIANT_DIFromDec(pDecIn, &temp);
+  VARIANT_DI_tostringW(&temp, buff, 256);
 
-    /* Create the basic number string */
-    *szOut-- = '\0';
-    szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut);
-    if (DEC_SIGN(pDecIn))
-      dwFlags |= VAR_NEGATIVE;
+  if (dwFlags & LOCALE_USE_NLS)
+  {
+    WCHAR numbuff[256];
 
-    *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
-    TRACE("returning %s\n", debugstr_w(*pbstrOut));
-    return *pbstrOut ? S_OK : E_OUTOFMEMORY;
+    /* Format the number for the locale */
+    numbuff[0] = '\0';
+    GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
+                     buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
+    TRACE("created NLS string %s\n", debugstr_w(numbuff));
+    *pbstrOut = SysAllocString(numbuff);
+  }
+  else
+  {
+    *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
   }
-  FIXME("semi-stub\n");
-  return E_INVALIDARG;
+  
+  TRACE("returning %s\n", debugstr_w(*pbstrOut));
+  return *pbstrOut ? S_OK : E_OUTOFMEMORY;
 }
 
 /************************************************************************
index f97bd8a..8c8f20f 100644 (file)
@@ -49,6 +49,7 @@ extern "C" {
 #define PARAMFLAG_FRETVAL (8)
 #define PARAMFLAG_FOPT (16)
 #define PARAMFLAG_FHASDEFAULT (32)
+#define PARAMFLAG_FHASCUSTDATA (64)
 #define IDLFLAG_NONE PARAMFLAG_NONE
 #define IDLFLAG_FIN PARAMFLAG_FIN
 #define IDLFLAG_FOUT PARAMFLAG_FOUT