[dcom 1.2] Implement dispatch variant marshalling
Mike Hearn
mike at theoretic.com
Thu Sep 4 13:54:45 CDT 2003
I removed the use of asserts to check the results, and replaced them
with ERRs.
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 18:35:46 -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;
@@ -461,11 +584,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 +597,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