Re: [dcom 1.2] Implement dispatch variant marshalling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In fact, this patch doesn't build. It seems to have got some stuff on
the end changing types, I don't know why exactly. Anyway, I got rid of
it (hopefully my app still works).

ChangeLog:
Implement dispatch variant marshalling

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	4 Sep 2003 19:13:27 -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
@@ -183,6 +184,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 +204,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 +221,107 @@
   }
 }
 
+/* helper: called for VT_DISPATCH variants to marshal the IDispatch* into the buffer. returns Buffer on failure, new position otherwise */
+static unsigned char* dispatch_variant_marshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) {
+  IStream *working; 
+  HGLOBAL working_mem;
+  void *working_memlocked;
+  unsigned char *oldpos;
+  ULONG size;
+  HRESULT hr;
+  
+  TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar);
+
+  oldpos = Buffer;
+  
+  /* 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);
+  if (!working_mem) {
+    ERR("couldn't perform a GlobalAlloc\n");
+    return oldpos;
+  }
+
+  hr = CreateStreamOnHGlobal(working_mem, FALSE, &working);
+  if (hr != S_OK) {
+    ERR("CreateStreamOnHGlobal failed, hr=%ld\n",  hr);
+    return oldpos;
+  }
+
+  hr = CoMarshalInterface(working, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
+  if (hr != S_OK) {
+    ERR("CoMarshalInterface failed, hr=%ld\n", hr);
+    return oldpos;
+  }
+
+  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. returns Buffer on failure, new position otherwise */
+static unsigned char *dispatch_variant_unmarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) {
+  IStream *working;
+  HGLOBAL working_mem;
+  void *working_memlocked;
+  unsigned char *oldpos;
+  ULONG size;
+  HRESULT hr;
+  
+  TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar);
+
+  oldpos = Buffer;
+  
+  /* get the buffersize */
+  memcpy(&size, Buffer, sizeof(ULONG));
+  TRACE("buffersize=%ld\n", size);
+  Buffer += sizeof(ULONG);
+  
+  working_mem = GlobalAlloc(0, size);
+  if (!working_mem) {
+    ERR("failed to get a global alloc\n");
+    return oldpos;
+  }
+
+  hr = CreateStreamOnHGlobal(working_mem, TRUE, &working);
+  if (hr != S_OK) {
+    ERR("CreateStreamOnHGlobal failed, hr=%ld\n", hr);
+    return oldpos;
+  }
+
+  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));
+  if (hr != S_OK) {
+    ERR("CoUnmarshalInterface failed, hr=%ld\n", hr);
+    return oldpos;
+  }
+
+  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 +378,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 +453,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 +523,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;
 
@@ -465,7 +588,7 @@
     DISPPARAMS* pDispParams,
     VARIANT* pVarResult,
     EXCEPINFO* pExcepInfo,
-    UINT* pArgErr,
+    UINT* puArgErr,
     UINT cVarRef,
     UINT* rgVarRefIdx,
     VARIANTARG* rgVarRef)
@@ -474,22 +597,30 @@
   VARIANTARG *rgvarg, *arg;
   UINT u;
 
+  TRACE("(%p)->(%ld,%s,%lx,%x,%p,%p,%p,%p)\n", This,
+        dispIdMember, debugstr_guid(riid),
+        lcid, dwFlags, 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,
@@ -498,8 +629,9 @@
 			pDispParams,
 			pVarResult,
 			pExcepInfo,
-			pArgErr);
+			puArgErr);
 
+  TRACE("returned\n");
   /* copy ref args to out list */
   for (u=0; u<cVarRef; u++) {
     unsigned i = rgVarRefIdx[u];




[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux