[dcom 1.1] Implement dispatch variant marshalling

Mike Hearn mike at theoretic.com
Thu Aug 28 07:59:59 CDT 2003


This is a resend. From now on, no more unbuildable patches. Promise :)

ChangeLog:
Implement support for dispatch variant marshalling

Index: include/oaidl.h
===================================================================
RCS file: /home/wine/wine/include/oaidl.h,v
retrieving revision 1.17
diff -u -r1.17 oaidl.h
--- include/oaidl.h	18 Aug 2003 19:59:47 -0000	1.17
+++ include/oaidl.h	28 Aug 2003 12:54:15 -0000
@@ -775,7 +775,7 @@
     DISPID dispIdMember,
     REFIID riid,
     LCID lcid,
-    DWORD dwFlags,
+    WORD wFlags,
     DISPPARAMS* pDispParams,
     VARIANT* pVarResult,
     EXCEPINFO* pExcepInfo,
Index: dlls/oleaut32/usrmarshal.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/usrmarshal.c,v
retrieving revision 1.3
diff -u -r1.3 usrmarshal.c
--- dlls/oleaut32/usrmarshal.c	13 May 2003 00:41:58 -0000	1.3
+++ dlls/oleaut32/usrmarshal.c	28 Aug 2003 12:54:19 -0000
@@ -2,6 +2,7 @@
  * Misc marshalling routines
  *
  * Copyright 2002 Ove Kaaven
+ *           2003 Mike Hearn
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,6 +20,7 @@
  */
 
 #include <string.h>
+#include <assert.h>
 
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
@@ -183,6 +185,9 @@
 
 static unsigned wire_extra(unsigned long *pFlags, VARIANT *pvar)
 {
+  ULONG size;
+  HRESULT hr;
+
   if (V_VT(pvar) & VT_ARRAY) {
     FIXME("wire-size safearray\n");
     return 0;
@@ -200,8 +205,15 @@
     return VARIANT_UserSize(pFlags, 0, V_VARIANTREF(pvar));
   case VT_UNKNOWN:
   case VT_DISPATCH:
-    FIXME("wire-size interfaces\n");
-    return 0;
+    /* find the buffer size of the marshalled dispatch interface */
+    hr = CoGetMarshalSizeMax(&size, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
+    if (FAILED(hr)) {
+      ERR("Dispatch variant buffer size calculation failed, HRESULT=0x%lx\n", hr);
+      return 0;
+    }
+    size += sizeof(ULONG); /* we have to store the buffersize in the stream */
+    TRACE("wire-size extra of dispatch variant is %ld\n", size);
+    return size;
   case VT_RECORD:
     FIXME("wire-size record\n");
     return 0;
@@ -210,6 +222,83 @@
   }
 }
 
+/* helper: called for VT_DISPATCH variants to marshal the IDispatch* into the buffer */
+static unsigned char* dispatch_variant_marshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) {
+  IStream *working; 
+  HGLOBAL working_mem;
+  void *working_memlocked;
+  ULONG size;
+  HRESULT hr;
+  
+  TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar);
+
+  /* CoMarshalInterface needs a stream, whereas at this level we are operating in terms of buffers.
+   * We create a stream on an HGLOBAL, so we can simply do a memcpy to move it to the buffer.
+   * in rpcrt4/ndr_ole.c, a simple IStream implementation is wrapped around the buffer object,
+   * but that would be overkill here, hence this implementation. We save the size because the unmarshal
+   * code has no way to know how long the marshalled buffer is. */
+
+  size = wire_extra(pFlags, pvar);
+  
+  working_mem = GlobalAlloc(0, size);
+  assert( working_mem != NULL );
+
+  hr = CreateStreamOnHGlobal(working_mem, FALSE, &working);
+  assert( hr == S_OK );
+
+  hr = CoMarshalInterface(working, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
+  assert( hr == S_OK );
+
+  IStream_Release(working);
+  
+  working_memlocked = GlobalLock(working_mem);
+  memcpy(Buffer, &size, sizeof(ULONG)); /* copy the buffersize */
+  Buffer += sizeof(ULONG);
+  memcpy(Buffer, working_memlocked, size);
+  
+  GlobalUnlock(working_mem);
+  GlobalFree(working_mem);
+  TRACE("done, size=%ld\n", sizeof(ULONG) + size);
+  return Buffer + sizeof(ULONG) + size;
+}
+
+/* helper: called for VT_DISPATCH variants to unmarshal the buffer back into a dispatch variant */
+static unsigned char* dispatch_variant_unmarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) {
+  IStream *working;
+  HGLOBAL working_mem;
+  void *working_memlocked;
+  ULONG size;
+  HRESULT hr;
+  
+  TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar);
+
+  /* get the buffersize */
+  memcpy(&size, Buffer, sizeof(ULONG));
+  TRACE("buffersize=%ld\n", size);
+  Buffer += sizeof(ULONG);
+  
+  working_mem = GlobalAlloc(0, size);
+  assert( working_mem != NULL );
+
+  hr = CreateStreamOnHGlobal(working_mem, TRUE, &working);
+  assert( hr == S_OK );
+
+  working_memlocked = GlobalLock(working_mem);
+  
+  /* now we copy the contents of the marshalling buffer to working_memlocked, unlock it, and demarshal the stream */
+  memcpy(working_memlocked, Buffer, size);
+  GlobalUnlock(working_mem);
+
+  hr = CoUnmarshalInterface(working, &IID_IDispatch, (void**)&V_DISPATCH(pvar));
+  assert( hr == S_OK );
+
+  IStream_Release(working); /* this also frees the underlying hglobal */
+
+  TRACE("done, processed=%ld bytes\n", sizeof(ULONG) + size);
+  return Buffer + sizeof(ULONG) + size;
+}
+
+
 unsigned long WINAPI VARIANT_UserSize(unsigned long *pFlags, unsigned long Start, VARIANT *pvar)
 {
   TRACE("(%lx,%ld,%p)\n", *pFlags, Start, pvar);
@@ -266,6 +355,13 @@
   case VT_VARIANT | VT_BYREF:
     Pos = VARIANT_UserMarshal(pFlags, Pos, V_VARIANTREF(pvar));
     break;
+  case VT_DISPATCH | VT_BYREF:
+    FIXME("handle DISPATCH by ref\n");
+    break;
+  case VT_DISPATCH:
+    /* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */
+    Pos = dispatch_variant_marshal(pFlags, Pos, pvar);
+    break;
   case VT_RECORD:
     FIXME("handle BRECORD by val\n");
     break;
@@ -334,6 +430,9 @@
   case VT_RECORD | VT_BYREF:
     FIXME("handle BRECORD by ref\n");
     break;
+  case VT_DISPATCH:
+    Pos = dispatch_variant_unmarshal(pFlags, Pos, pvar);
+    break;
   default:
     FIXME("handle unknown complex type\n");
     break;
@@ -401,6 +500,7 @@
         lcid, wFlags, pDispParams, pVarResult,
         pExcepInfo, puArgErr);
 
+  TRACE("riid=%p\n", riid);
   /* [out] args can't be null, use dummy vars if needed */
   if (!pVarResult) pVarResult = &VarResult;
 
@@ -461,11 +561,11 @@
     DISPID dispIdMember,
     REFIID riid,
     LCID lcid,
-    DWORD dwFlags,
+    WORD wFlags,
     DISPPARAMS* pDispParams,
     VARIANT* pVarResult,
     EXCEPINFO* pExcepInfo,
-    UINT* pArgErr,
+    UINT* puArgErr,
     UINT cVarRef,
     UINT* rgVarRefIdx,
     VARIANTARG* rgVarRef)
@@ -474,32 +574,41 @@
   VARIANTARG *rgvarg, *arg;
   UINT u;
 
+  TRACE("(%p)->(%ld,%s,%lx,%x,%p,%p,%p,%p)\n", This,
+        dispIdMember, debugstr_guid(riid),
+        lcid, wFlags, pDispParams, pVarResult,
+        pExcepInfo, puArgErr);
+  
   /* let the real Invoke operate on a copy of the in parameters,
    * so we don't risk losing pointers to allocated memory */
   rgvarg = pDispParams->rgvarg;
   arg = CoTaskMemAlloc(sizeof(VARIANTARG)*pDispParams->cArgs);
   for (u=0; u<pDispParams->cArgs; u++) {
+    TRACE("marshalling\n");
     VariantInit(&arg[u]);
     VariantCopy(&arg[u], &rgvarg[u]);
   }
+  TRACE("done\n");
   pDispParams->rgvarg = arg;
 
   /* initialize out parameters, so that they can be marshalled
    * in case the real Invoke doesn't initialize them */
   VariantInit(pVarResult);
   memset(pExcepInfo, 0, sizeof(*pExcepInfo));
-  *pArgErr = 0;
+  *puArgErr = 0;
 
+  TRACE("calling invoke\n");
   hr = IDispatch_Invoke(This,
 			dispIdMember,
 			riid,
 			lcid,
-			dwFlags,
+			wFlags,
 			pDispParams,
 			pVarResult,
 			pExcepInfo,
-			pArgErr);
+			puArgErr);
 
+  TRACE("returned\n");
   /* copy ref args to out list */
   for (u=0; u<cVarRef; u++) {
     unsigned i = rgVarRefIdx[u];





More information about the wine-patches mailing list