summaryrefslogtreecommitdiffstats
path: root/private/ole32/com/remote/coapi.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'private/ole32/com/remote/coapi.cxx')
-rw-r--r--private/ole32/com/remote/coapi.cxx1318
1 files changed, 1318 insertions, 0 deletions
diff --git a/private/ole32/com/remote/coapi.cxx b/private/ole32/com/remote/coapi.cxx
new file mode 100644
index 000000000..14ec0311d
--- /dev/null
+++ b/private/ole32/com/remote/coapi.cxx
@@ -0,0 +1,1318 @@
+//+-------------------------------------------------------------------
+//
+// File: coapi.cxx
+//
+// Contents: Public COM remote subsystem APIs
+//
+// Classes: CStaticMarshaler (private)
+//
+// Functions: CoGetStandardMarshal - returns IMarshal for given object
+// CoGetMarshalSizeMax - returns max size buffer needed
+// CoMarshalInterface - marshals an interface
+// CoUnmarshalInterface - unmarshals an interface
+// CoReleaseMarshalData - releases data from marshaled iface
+// CoLockObjectExternal - keeps object alive
+// CoDisconnectObject - kills sessions held by remote clients
+//
+// History: 23-Nov-92 Rickhi
+// 11-Dec-93 CraigWi Switched to identity object
+// 05-Jul-94 BruceMa Check for end of stream
+//
+//--------------------------------------------------------------------
+
+#include <ole2int.h>
+
+#include <olerem.h>
+#include <iface.h>
+
+
+// function prototypes
+INTERNAL_(IMarshal *) FindOrCreateStdMarshal(IUnknown *pUnk, BOOL fCreate);
+INTERNAL_(IMarshal *) GetStaticMarshaler(void);
+INTERNAL_(void) RewriteHeader(IStream *pStm, void *pv, ULONG cb, ULARGE_INTEGER ulSeekStart);
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CoGetStandardMarshal
+//
+// Synopsis: Returns an instance of the standard IMarshal for the
+// specifed object. See comment about aggregated id objects
+// in FindOrCreateStdMarshal().
+//
+// Algorithm: lookup or create a remote hdlr for the object.
+//
+// History: 23-Nov-92 Rickhi Created
+// 11-Dec-93 CraigWi Switched to identity object
+//
+//--------------------------------------------------------------------
+STDAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
+ DWORD dwDestContext, void *pvDestContext,
+ DWORD mshlflags, IMarshal **ppMarshal)
+{
+ OLETRACEIN((API_CoGetStandardMarshal,
+ PARAMFMT("riid= %I, pUnk= %p, dwDestContext= %x, pvDestContext= %p, mshlflags= %x, ppMarshal= %p"),
+ &riid, pUnk, dwDestContext, pvDestContext, mshlflags, ppMarshal));
+
+ TRACECALL(TRACE_MARSHAL, "CoGetStandardMarshal");
+
+ HRESULT sc = S_OK;
+ IMarshal *pIM;
+
+ if (!IsApartmentInitialized())
+ {
+ sc = CO_E_NOTINITIALIZED;
+ goto errRtn;
+ }
+
+ CALLHOOKOBJECT(S_OK,CLSID_NULL,riid,&pUnk);
+
+ if (pUnk == NULL)
+ {
+ // this is the unmarshal side
+ // sc = CreateIdentityHandler(pUnk, PSTDMARSHAL, IID_IMarshal,
+ // (void**) &pIM);
+ pIM = GetStaticMarshaler();
+ }
+ else
+ {
+ // this is the marshal side
+ pIM = FindOrCreateStdMarshal(pUnk, TRUE);
+ }
+ *ppMarshal = pIM; // fill in the return parameters
+
+ if (SUCCEEDED(sc) && !pIM)
+ {
+ sc = E_OUTOFMEMORY;
+ }
+
+ CairoleDebugOut((DEB_ITRACE, "CoGetStandardMarshal: pUnk=%x pIM=%x sc=%x\n",
+ pUnk, *ppMarshal, sc));
+errRtn:
+ OLETRACEOUT((API_CoGetStandardMarshal, sc));
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CoGetMarshalSizeMax
+//
+// synopsis: returns the max size needed to marshal the specified
+// interface.
+//
+// History: 23-Nov-92 Rickhi Created
+// 11-Dec-93 CraigWi Switched to static marshaler
+//
+//--------------------------------------------------------------------
+STDAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
+ DWORD dwDestCtx, void *pvDestCtx,
+ DWORD mshlflags)
+{
+ OLETRACEIN((API_CoGetMarshalSizeMax,
+ PARAMFMT("pulSize= %p, riid= %I, pUnk= %p, dwDestCtx= %x, pvDestCtx= %p, mshlflags= %x"),
+ pulSize, &riid, pUnk, dwDestCtx, pvDestCtx, mshlflags));
+
+ TRACECALL(TRACE_MARSHAL, "CoGetMarshalSizeMax");
+
+ Win4Assert(MARSHALINTERFACE_MIN >= sizeof(SMiApiDataHdr) + sizeof(CLSID));
+
+ HRESULT sc = S_OK;
+ IMarshal *pIM = NULL;
+ CALLHOOKOBJECT(S_OK,CLSID_NULL,riid,&pUnk);
+
+ if (!IsApartmentInitialized())
+ {
+ sc = CO_E_NOTINITIALIZED;
+ goto errRtn;
+ }
+
+ // find the IMarshal interface, or create a RH for the object
+ if (FAILED(pUnk->QueryInterface(IID_IMarshal, (void **)&pIM)))
+ {
+ // uses standard marshalling; cheaply get marshaler
+ pIM = GetStaticMarshaler();
+ Win4Assert(pIM);
+ }
+
+ if (pIM)
+ {
+ sc = pIM->GetMarshalSizeMax(riid, (void *)pUnk, dwDestCtx,
+ pvDestCtx, mshlflags, pulSize);
+
+ // BUGBUG: may need to release this specialy for custom marshalers
+
+ pIM->Release();
+
+ // add in the size of the stuff CoMarshalInterface will write;
+ // may not, in fact, write clsid, but this conservative.
+ (*pulSize) += sizeof(SMiApiDataHdr) + sizeof(CLSID);
+ }
+ else
+ {
+ sc = E_UNEXPECTED;
+ }
+
+ CairoleDebugOut((DEB_ITRACE, "CoGetMarshalSizeMax: pUnk=%x size=%x dwDest=%x pvDest=%x flags=%x sc=%x\n",
+ pUnk, *pulSize, dwDestCtx, pvDestCtx, mshlflags, sc));
+
+errRtn:
+ OLETRACEOUT((API_CoGetMarshalSizeMax, sc));
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CoMarshalInterface, public
+//
+// Synopsis: fill stream with marshal info for pUnk/iid;
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi
+// 11-Dec-93 CraigWi Switched to identity object and
+// new marshaling format
+//
+//--------------------------------------------------------------------
+
+STDAPI CoMarshalInterface(IStream *pStm,
+ REFIID riid,
+ IUnknown *pUnk,
+ DWORD dwDestCtx,
+ void *pvDestCtx,
+ DWORD mshlflags)
+{
+ OLETRACEIN((API_CoMarshalInterface,
+ PARAMFMT("pStm= %p, riid= %I, pUnk= %p, dwDestCtx= %x, pvDestCtx= %p, mshlflags= %x"),
+ pStm, &riid, pUnk, dwDestCtx, pvDestCtx, mshlflags));
+
+ TRACECALL(TRACE_MARSHAL, "CoMarshalInterface");
+
+ HRESULT sc;
+ IMarshal *pIM = NULL;
+
+ if (!IsApartmentInitialized())
+ {
+ sc = CO_E_NOTINITIALIZED;
+ goto errRtn;
+ }
+
+ // Some parameter checking
+ if (pUnk == NULL)
+ {
+ sc = E_OUTOFMEMORY;
+ goto errRtn;
+ }
+
+ CALLHOOKOBJECT(S_OK,CLSID_NULL,riid,(IUnknown **)&pUnk);
+ CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStream,(IUnknown **)&pStm);
+
+ // Make sure object supports the requested interface. This has the
+ // side effect that if this is a request for a marshal interface and
+ // the object is a proxy for which we have never gotten the interface,
+ // we will get it now and the marshal will work.
+ IUnknown *punkVerifyIf;
+
+ if (pUnk->QueryInterface(riid, (void **) &punkVerifyIf) != NOERROR)
+ {
+ sc = E_NOINTERFACE;
+ goto errRtn;
+ }
+
+ // find the IMarshal interface, or create a RH for the object
+ if (FAILED(pUnk->QueryInterface(IID_IMarshal, (void **)&pIM)))
+ {
+ // returns NULL if failed
+ pIM = FindOrCreateStdMarshal(pUnk, TRUE);
+ }
+
+ if (pIM)
+ {
+ // setup the marshal info structure
+ SMiApiDataHdr ifp;
+ CLSID clsid;
+
+ ifp.dwflags = mshlflags & MIAPIFLAGS_TABLE;
+
+ sc = pIM->GetUnmarshalClass(riid, pUnk, dwDestCtx, pvDestCtx,
+ mshlflags, &clsid);
+
+ if (IsEqualGUID(clsid, CLSID_IdentityUnmarshal))
+ {
+ ifp.dwflags |= MIAPIFLAGS_STDIDENTITY;
+ }
+ else if (IsEqualGUID(clsid, CLSID_InProcFreeMarshaler))
+ {
+ ifp.dwflags |= MIAPIFLAGS_IPFM;
+ }
+
+
+ if (SUCCEEDED(sc))
+ {
+ // write the marshal info into the stream
+ sc = pStm->Write(&ifp, sizeof(ifp), NULL);
+ }
+
+ if (SUCCEEDED(sc)
+ && (ifp.dwflags & (MIAPIFLAGS_STDIDENTITY | MIAPIFLAGS_IPFM)) == 0)
+ {
+ // write non-standard unmarshaler clsid
+ sc = pStm->Write(&clsid, sizeof(clsid), NULL);
+ }
+
+ if (SUCCEEDED(sc))
+ {
+ sc = pIM->MarshalInterface(pStm, riid, pUnk, dwDestCtx,
+ pvDestCtx, mshlflags);
+ }
+
+ pIM->Release();
+ }
+ else
+ {
+ sc = E_OUTOFMEMORY;
+ }
+
+ // Release the interface we used to verify that the interface was supported
+ // here because if we succeeded we have multiple AddRefs to the interface
+ // and therefore the object will not go away.
+ punkVerifyIf->Release();
+
+ CairoleDebugOut((DEB_ITRACE, "CoMarshalInterface: pUnk=%x pIM=%x dwDest=%x pvDest=%x flags=%x sc=%x\n",
+ pUnk, pIM, dwDestCtx, pvDestCtx, mshlflags, sc));
+errRtn:
+ OLETRACEOUT((API_CoMarshalInterface, sc));
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CoUnMarshalInterface, public
+//
+// Algorithm:
+//
+// Notes: when a controlling unknown is supplied, it is assumed that
+// the HANDLER for the class has done a CreateInstance and wants
+// to aggregate just the remote handler, ie. we dont want to
+// instantiate a new class handler (the default unmarshalling
+// behaviour).
+//
+// History: 23-Nov-92 Rickhi
+// 11-Dec-93 CraigWi Switched to static marshaler and
+// new marshaling format
+//
+//--------------------------------------------------------------------
+
+STDAPI CoUnmarshalInterfaceEx(IStream *pStm, REFIID riid, void **ppv, BOOL f);
+
+STDAPI CoUnmarshalInterface(IStream *pStm,
+ REFIID riid,
+ void **ppv)
+{
+ OLETRACEIN((API_CoUnmarshalInterface, PARAMFMT("pStm= %p, riid= %I, ppv= %p"), pStm, &riid, ppv));
+
+ HRESULT hr;
+
+ hr = CoUnmarshalInterfaceEx(pStm, riid, ppv, TRUE /*fNormalDoesRelease*/);
+
+ OLETRACEOUT((API_CoUnmarshalInterface, hr));
+
+ return hr;
+}
+
+
+// This variation allows control over whether the normal marshal case does
+// the release marshal data. This is useful for nested marshaled pointers
+// which need to be released once when the outer marshaling is released.
+STDAPI CoUnmarshalInterfaceEx(IStream *pStm,
+ REFIID riid,
+ void **ppv,
+ BOOL fNormalDoesRelease)
+{
+ TRACECALL(TRACE_MARSHAL, "CoUnmarshalInterface");
+ CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStream,(IUnknown **)&pStm);
+
+ if (!IsApartmentInitialized())
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT sc;
+ IMarshal *pIM = NULL;
+
+ *ppv = NULL;
+
+ SMiApiDataHdr ifp;
+ CLSID clsid;
+ sc = StRead(pStm, &ifp, sizeof(ifp));
+
+ if (SUCCEEDED(sc) && (ifp.dwflags & MIAPIFLAGS_RELEASED) != 0)
+ {
+ // already released, this is an error on the caller's part
+ sc = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(sc)
+ && (ifp.dwflags & (MIAPIFLAGS_STDIDENTITY | MIAPIFLAGS_IPFM)) == 0)
+ {
+ sc = StRead(pStm, &clsid, sizeof(clsid));
+ }
+
+ // deal with extension
+ if (SUCCEEDED(sc) && (ifp.dwflags & MIAPIFLAGS_EXTENSION) != 0)
+ sc = SkipMarshalExtension(pStm);
+
+ if (SUCCEEDED(sc))
+ {
+ // create an instance of the specified class and ask it to do
+ // the unmarshalling. note that since standard marshalling is so
+ // common, we cook up an instance at init time and just always
+ // use that guy to do the unmarshalling.
+
+ if ((ifp.dwflags & MIAPIFLAGS_STDIDENTITY) != 0)
+ {
+ // uses standard marshalling; cheaply get unmarshaler
+ pIM = GetStaticMarshaler();
+ Win4Assert(pIM);
+ }
+ else if ((ifp.dwflags & MIAPIFLAGS_IPFM) != 0)
+ {
+ // Get the in process standard free marshaler.
+ sc = GetInProcFreeMarshaler(&pIM);
+ }
+ else
+ {
+ // uses custom marshalling, create an instance
+ sc = CoCreateInstance(clsid, NULL, CLSCTX_INPROC,
+ IID_IMarshal, (void **)&pIM);
+ }
+
+ if (SUCCEEDED(sc) && pIM)
+ {
+ ULARGE_INTEGER ulSeekStart;
+ LARGE_INTEGER libMove;
+
+ if ((ifp.dwflags & MIAPIFLAGS_TABLE) == MSHLFLAGS_NORMAL)
+ {
+ // save current seek pointer for ReleaseMarshalData
+ LISet32(libMove, 0x00000000);
+ pStm->Seek(libMove, STREAM_SEEK_CUR, &ulSeekStart);
+ }
+
+ // unmarshal the interface
+ sc = pIM->UnmarshalInterface(pStm, riid, ppv);
+
+ // release the marshal data if we are supposed to.
+ // ignore errors because they cant affect that fact that
+ // we already successfully unmarshalled the interface.
+
+ if ((ifp.dwflags & MIAPIFLAGS_TABLE) == MSHLFLAGS_NORMAL &&
+ fNormalDoesRelease)
+ {
+ ULARGE_INTEGER ulSeekEnd;
+ pStm->Seek(libMove, STREAM_SEEK_CUR, &ulSeekEnd);
+ libMove.LowPart = ulSeekStart.LowPart;
+ libMove.HighPart = ulSeekStart.HighPart;
+ if (SUCCEEDED(pStm->Seek(libMove, STREAM_SEEK_SET, &ulSeekStart)))
+ {
+ pIM->ReleaseMarshalData(pStm);
+ }
+ libMove.LowPart = ulSeekEnd.LowPart;
+ libMove.HighPart = ulSeekEnd.HighPart;
+ pStm->Seek(libMove, STREAM_SEEK_SET, NULL);
+ }
+ }
+ }
+
+ if (pIM)
+ pIM->Release();
+
+ CairoleDebugOut((DEB_ITRACE, "CoUnmarshalInterface: pUnk=%x sc=%x\n",
+ *ppv, sc));
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CoReleaseMarshalData, public
+//
+// Synopsis: release the reference created by CoMarshalInterface
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi
+// 11-Dec-93 CraigWi Switched to static marshaler and
+// new marshaling format
+//
+//--------------------------------------------------------------------
+
+STDAPI CoReleaseMarshalData(IStream *pStm)
+{
+ OLETRACEIN((API_CoReleaseMarshalData, PARAMFMT("pStm= %p"), pStm));
+
+ TRACECALL(TRACE_MARSHAL, "CoReleaseMarshalData");
+ CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStream,(IUnknown **)&pStm);
+
+ HRESULT sc;
+ IMarshal *pIM = NULL;
+ SMiApiDataHdr ifp;
+ CLSID clsid;
+ ULARGE_INTEGER ulSeekStart;
+ LARGE_INTEGER libMove;
+
+ if (!IsApartmentInitialized())
+ {
+ sc = CO_E_NOTINITIALIZED;
+ goto errRtn;
+ }
+
+ // save the current stream seek pointer
+ LISet32(libMove, 0x00000000);
+ sc = pStm->Seek(libMove, STREAM_SEEK_CUR, &ulSeekStart);
+
+ if (SUCCEEDED(sc))
+ sc = StRead(pStm, &ifp, sizeof(ifp));
+
+ // ensure this marshalled data has not already been released.
+ if (SUCCEEDED(sc) && (ifp.dwflags & MIAPIFLAGS_RELEASED) != 0)
+ {
+ // already released, this is an error. Stream in undefined
+ // position on errors.
+ sc = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(sc)
+ && ((ifp.dwflags & (MIAPIFLAGS_STDIDENTITY | MIAPIFLAGS_IPFM)) == 0))
+ sc = StRead(pStm, &clsid, sizeof(clsid));
+
+ // deal with extension
+ if (SUCCEEDED(sc) && (ifp.dwflags & MIAPIFLAGS_EXTENSION) != 0)
+ sc = SkipMarshalExtension(pStm);
+
+ if (SUCCEEDED(sc))
+ {
+ // create an instance of the specified class and ask it to do
+ // the unmarshalling. note that since standard marshalling is so
+ // common, we cook up an instance at init time and just always
+ // use that guy to do the unmarshalling.
+
+ if ((ifp.dwflags & MIAPIFLAGS_STDIDENTITY) != 0)
+ {
+ // uses standard marshalling; cheaply get unmarshaler
+ pIM = GetStaticMarshaler();
+ Win4Assert(pIM); // cant fail!!!
+ }
+ else if ((ifp.dwflags & MIAPIFLAGS_IPFM) != 0)
+ {
+ // Uses the free threaded marshaler. So we get it directly.
+ // This really can only fail with out of memory.
+ IUnknown *punk;
+
+ // Get the IUnknown for the free threaded marshaler
+ sc = CoCreateFreeThreadedMarshaler(NULL, &punk);
+
+ if (SUCCEEDED(sc))
+ {
+ // Get the IMarshal interface
+ sc = punk->QueryInterface(IID_IMarshal, (void **) &pIM);
+
+ // We release this no matter what since we no longer need it.
+ punk->Release();
+ }
+ }
+ else
+ {
+ // uses custom marshalling, create an instance
+ sc = CoCreateInstance(clsid, NULL, CLSCTX_INPROC,
+ IID_IMarshal, (void **)&pIM);
+ }
+
+ if (SUCCEEDED(sc))
+ {
+ sc = pIM->ReleaseMarshalData(pStm);
+
+ if (pIM)
+ pIM->Release();
+ }
+ }
+
+ if (SUCCEEDED(sc))
+ {
+ // if overall success...
+ // to ensure we dont allow ReleaseMarshalData multiple times we
+ // mark a bit in the stream to indicate we've already Released it.
+ // UnmarshalInterface will return an error if this bit is set.
+ ifp.dwflags |= MIAPIFLAGS_RELEASED;
+ RewriteHeader(pStm, &ifp, sizeof(ifp), ulSeekStart);
+ }
+
+ CairoleDebugOut((DEB_ITRACE, "CoReleaseMarshalData pIM=%x sc=%x.\n",
+ pIM, sc));
+errRtn:
+ OLETRACEOUT((API_CoReleaseMarshalData, sc));
+
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CoLockObjectExternal
+//
+// synopsis: adds/revokes a strong reference count to/from the
+// identity for the given object.
+//
+// parameters: [punkObject] - IUnknown of the object
+// [fLock] - lock/unlock the object
+// [fLastUR] - last unlock releases.
+//
+// History: 23-Nov-92 Rickhi Created
+// 11-Dec-93 CraigWi Switched to identity object
+//
+//--------------------------------------------------------------------
+
+STDAPI CoLockObjectExternal(IUnknown *punkObject, BOOL fLock, BOOL fLastUR)
+{
+ OLETRACEIN((API_CoLockObjectExternal, PARAMFMT("punkObject= %p, fLock= %B, fLastUR= %B"),
+ punkObject, fLock, fLastUR));
+
+ TRACECALL(TRACE_MARSHAL, "CoLockObjectExternal");
+
+ // REF COUNTING: inc or dec external ref count
+
+ HRESULT sc = E_INVALIDARG;
+ IStdIdentity *pStdID;
+
+ if (!IsValidInterface(punkObject))
+ goto errRtn;
+
+ CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IUnknown,(IUnknown **)&punkObject);
+
+ switch (sc = LookupIDFromUnk(punkObject, fLock, &pStdID))
+ {
+ case S_OK:
+ if (pStdID->GetServer(FALSE) == NULL)
+ {
+ // attempt to lock handler, return error!
+ // BUGBUG: debug printouts
+ sc = E_UNEXPECTED;
+ }
+ else if (fLock)
+ sc = pStdID->AddConnection(EXTCONN_STRONG, 0);
+ else
+ sc = pStdID->ReleaseConnection(EXTCONN_STRONG, 0, fLastUR);
+
+ pStdID->Release();
+ break;
+
+ case CO_E_OBJNOTREG:
+ // unlock when not registered; 16bit code returned NOERROR;
+ // disconnected handler goes to S_OK case above.
+ sc = S_OK;
+ break;
+
+ case E_OUTOFMEMORY:
+ break;
+
+ default:
+ sc = E_UNEXPECTED;
+ break;
+ }
+
+errRtn:
+ CairoleDebugOut((DEB_ITRACE, "CoLockObjectExternal pStdID=%x fLock=%x sc=%x.\n",
+ pStdID, fLock, sc));
+
+ OLETRACEOUT((API_CoLockObjectExternal, sc));
+
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CoDisconnectObject
+//
+// synopsis: disconnects all clients of an object by marking their
+// connections as terminted abnormaly.
+//
+// History: 04-Oct-93 Rickhi Created
+// 11-Dec-93 CraigWi Switched to identity object
+//
+//--------------------------------------------------------------------
+
+STDAPI CoDisconnectObject(IUnknown *punkObject, DWORD dwReserved)
+{
+ OLETRACEIN((API_CoDisconnectObject, PARAMFMT("punkObject= %p, dwReserved= %x"), punkObject, dwReserved));
+
+ TRACECALL(TRACE_MARSHAL, "CoDisconnectObject");
+ CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IUnknown,(IUnknown **)&punkObject);
+
+ HRESULT sc = S_OK;
+ IMarshal *pIM = NULL;
+
+ sc = punkObject->QueryInterface(IID_IMarshal, (void **)&pIM);
+ if (FAILED(sc))
+ {
+ // object does not support IMarshal directly. Find its standard
+ // marshaler if there is one, otherwise return an error.
+
+ pIM = FindOrCreateStdMarshal(punkObject, FALSE);
+ }
+
+ if (pIM)
+ {
+ sc = pIM->DisconnectObject(dwReserved);
+ pIM->Release();
+ }
+ else
+ {
+ // couldn't get std marshal; must be disconnected already
+ sc = NOERROR;
+ }
+
+ CairoleDebugOut((DEB_ITRACE, "CoDisconnectObject pIM=%x sc=%x.\n",
+ pIM, sc));
+
+ OLETRACEOUT((API_CoDisconnectObject, sc));
+
+ return sc;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CoIsHandlerConnected
+//
+// Synopsis: Returns whether or not handler is connected to remote
+//
+// Algorithm: QueryInterface to IProxyManager. If this is supported,
+// then this is a handler. We ask the handler
+// for its opinion otherwise we simply return TRUE.
+//
+// History: 04-Oct-93 Rickhi Created
+//
+// Notes: The answer of this routine may be wrong by the time
+// the routine returns. This is correct behavior as
+// this routine is primilary to cleanup state associated
+// with connections.
+//
+//--------------------------------------------------------------------
+
+STDAPI_(BOOL) CoIsHandlerConnected(LPUNKNOWN pUnk)
+{
+ OLETRACEIN((API_CoIsHandlerConnected, PARAMFMT("pUnk= %p"), pUnk));
+
+ IProxyManager *pPM;
+
+ // Assume it is connected
+ BOOL fResult = TRUE;
+
+ CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IUnknown,(IUnknown **)&pUnk);
+ // Handler should be support IProxyManager
+ if (SUCCEEDED(pUnk->QueryInterface(IID_IProxyManager, (void **) &pPM)))
+ {
+ // We have something that thinks its is an Ole handler so we ask
+ fResult = pPM->IsConnected();
+
+ // Release the interface we used
+ pPM->Release();
+ }
+
+ OLETRACEOUTEX((API_CoIsHandlerConnected, RETURNFMT("%B"), fResult));
+
+ return fResult;
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: FindOrCreateStdMarshal, private
+//
+// Synopsis: looks up or creates the std identity for the object
+// and returns the IMarshal aspect of it. It is assumed
+// that the ID object is not aggregated to the server
+// (BUGBUG: can we assert that???) because we need to QI
+// for IMarshal. When the id object is aggregated, the
+// caller is supposed to use IStdIdentity::GetStdRemMarshal()
+// instead.
+//
+// Arguments: [pUnk] -- The object in question; not necessaryily the
+// controlling unknown.
+// [fCreate] -- TRUE -> creates identity object if it does
+// not exist.
+//
+// Returns: NULL if out of memory; pMarshal otherwise
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+INTERNAL_(IMarshal *)FindOrCreateStdMarshal(IUnknown *pUnk, BOOL fCreate)
+{
+ IStdIdentity *pStdID;
+ if (LookupIDFromUnk(pUnk, fCreate, &pStdID) != NOERROR)
+ // only possible return in this case is E_OUTOFMEMORY.
+ return NULL;
+
+ HRESULT hr;
+ IMarshal *pMarshal;
+ hr = pStdID->QueryInterface(IID_IMarshal, (void **)&pMarshal);
+ pStdID->Release();
+ AssertSz(hr == NOERROR, "What, no IMarshal on an identity object?");
+ CALLHOOKOBJECTCREATE(hr,CLSID_NULL,IID_IMarshal,(IUnknown **)&pMarshal);
+ return (hr == NOERROR) ? pMarshal : NULL;
+}
+
+
+//+----------------------------------------------------------------
+//
+// Class: CStaticMarshaler, private
+//
+// Purpose: Used for three rather disjoint purposes:
+// 1. unmarshaling normal identity packet
+// 2. release marshal data of same and table packets
+// 3. get marshal size max
+//
+// This class exists solely to make the code in the Co*
+// APIs cleaner. It is not integrated into the real
+// identity object itself to avoid confusing the two
+// roles (initial unmarshaler and the real identity).
+//
+// Interface: IMarshal::GetMarshalSizeMax, IMarshal::UnmarshalInterface
+// and IMarshal::ReleaseMarshal; other methods of IMarshal
+// return E_UNEXPECTED.
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+// Note: There is only one instance of this class (for speed) and
+// thus many short cuts are taken.
+//
+//-----------------------------------------------------------------
+
+class CStaticMarshaler : public IMarshal
+{
+public:
+ STDMETHOD(QueryInterface) (REFIID riid, LPVOID *ppvObj);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+
+ // IMarshal
+ STDMETHOD(GetUnmarshalClass)(REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags, LPCLSID pCid);
+ STDMETHOD(GetMarshalSizeMax)(REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags, LPDWORD pSize);
+ STDMETHOD(MarshalInterface)(LPSTREAM pStm, REFIID riid,
+ LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags);
+ STDMETHOD(UnmarshalInterface)(LPSTREAM pStm, REFIID riid,
+ VOID **ppv);
+ STDMETHOD(ReleaseMarshalData)(LPSTREAM pStm);
+ STDMETHOD(DisconnectObject)(DWORD dwReserved);
+
+private:
+#if DBG == 1
+ DWORD m_refs; // for the AddRef/Release return value
+#endif
+
+} sg_StaticMarshaler;
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStaticMarshaler::QueryInterface, public
+//
+// Synopsis: shouldn't be called.
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CStaticMarshaler::QueryInterface(REFIID riid, VOID **ppvObj)
+{
+ AssertSz(FALSE, "This QI should not be called");
+ *ppvObj = NULL;
+ return E_UNEXPECTED;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStaticMarshaler::AddRef, Release, public
+//
+// Synopsis: maintains ref count in debug version only.
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CStaticMarshaler::AddRef(void)
+{
+#if DBG == 1
+ return ++m_refs;
+#else
+ return 0;
+#endif
+}
+
+
+STDMETHODIMP_(ULONG) CStaticMarshaler::Release(void)
+{
+#if DBG == 1
+ return --m_refs;
+#else
+ return 0;
+#endif
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStaticMarshaler::GetUnmarshalClass, public
+//
+// Synopsis: shouldn't be called.
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CStaticMarshaler::GetUnmarshalClass(REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags, LPCLSID pCid)
+{
+ AssertSz(FALSE, "This GetUnmarshalClass should not be called");
+
+ return E_UNEXPECTED;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStaticMarshaler::GetMarshalSizeMax, public
+//
+// Synopsis: Quickly gets an upper bound on the amount of data for
+// a standard marshal (no app data).
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CStaticMarshaler::GetMarshalSizeMax(REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags, LPDWORD pSize)
+{
+ // object doesn't have own imarshal and thus it will use all
+ // standard marshaling (coapi, id, remhdlr, channel).
+ // size is: sizeof id, sizeof rh, upper bound on size of channel
+
+ // don't want to be fancy about this since we want this to be fast;
+ // include handler CLSID since we don't want to check if it is needed.
+
+ *pSize = sizeof(SIdentityDataHdr) + sizeof(CLSID) +
+ sizeof(SHandlerDataHdr) + /* CLSID_RpcChannelBuffer + */
+ sizeof(SChannelDataHdr)
+ + 1024;
+
+ //
+ // BUGBUG: (RichardW, 14 Oct 94, for RickHi, bug # 25942)
+ //
+ // Someone trashed this calculation, adding this random 512 byte pad
+ // on the end. RickHi will apply the correct fix, but for now, for
+ // cairo builds, I have bumped it to 1024.
+ //
+
+
+ // CODEWORK: later when channel is indexable from the dest context,
+ // we use that for the last component of the size. This is also
+ // important to do since we don't really know an upper bound on the
+ // channel data size.
+
+ // When table marshaling differs from normal marshaling, this
+ // routine will have to encode how the size gets calculated.
+ // In both cases some code will be shared (procedures) with std id.
+
+ return NOERROR;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStaticMarshaler::MarshalInterface, public
+//
+// Synopsis: shouldn't be called.
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CStaticMarshaler::MarshalInterface(LPSTREAM pStm,
+ REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags)
+{
+ AssertSz(FALSE, "This MarshalInterface should not be called");
+
+ return E_UNEXPECTED;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: ReadIdentityHeader, private
+//
+// Synopsis: Reads the identity data header and the clsid;
+// if fTransparent, skips back to the beginning;
+// else, skips over extention if present.
+//
+// History: 14-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+INTERNAL ReadIdentityHeader(IStream *pStm, SIdentityDataHdr *pidh,
+ CLSID *pclsidHandler, BOOL fTransparent)
+{
+ HRESULT hr;
+ ULARGE_INTEGER ulSeekStart;
+ LARGE_INTEGER libMove;
+
+ if (fTransparent)
+ {
+ // save current position so that we can set it back here
+ LISet32(libMove, 0x00000000);
+ hr = pStm->Seek(libMove, STREAM_SEEK_CUR, &ulSeekStart);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ hr = StRead(pStm, pidh, sizeof(*pidh));
+
+ if (FAILED(hr))
+ return hr;
+
+ if ((pidh->dwflags & IDENFLAGS_STDMARSHAL) != 0)
+ {
+ // std marshal case
+ *pclsidHandler = CLSID_StdMarshal;
+ }
+ else
+ {
+ hr = StRead(pStm, pclsidHandler, sizeof(*pclsidHandler));
+
+ if (FAILED(hr))
+ return hr;
+ }
+
+ if (fTransparent)
+ {
+ // skip back to the beginning of what was just read
+
+ libMove.LowPart = ulSeekStart.LowPart;
+ libMove.HighPart = ulSeekStart.HighPart;
+ hr = pStm->Seek(libMove, STREAM_SEEK_SET, NULL);
+ }
+ else
+ {
+ // read extension and leave seek pointer after header
+ if (pidh->dwflags & IDENFLAGS_EXTENSION)
+ hr = SkipMarshalExtension(pStm);
+ }
+
+ return hr;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStaticMarshaler::UnmarshalInterface, public
+//
+// Synopsis: First part of unmarshaling an identity object; looks
+// for an existing object and if not found creates one
+// of type clsidHandler and CLSCTX_INPROC_HANDLER. In
+// all cases, skips back to the beginning of the identity
+// information and forwards the unmarshal call on to the
+// identified object. Thus it is the responsibility of
+// handlers that support identity to make sure the identity
+// information is consumed first.
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CStaticMarshaler::UnmarshalInterface(LPSTREAM pStm,
+ REFIID riid, VOID **ppv)
+{
+ // BUGBUG PERF: can we call into identity object directly or bypass it
+ // by getting it's followon marshaler?
+
+ HRESULT hr;
+ SIdentityDataHdr idh;
+ CLSID clsidHandler;
+
+ // read data header and optional clsidHandler; seek back;
+ hr = ReadIdentityHeader(pStm, &idh, &clsidHandler, TRUE /*fTransparent*/);
+ if (FAILED(hr))
+ return hr;
+
+ // lookup id; if exists, feed data to it
+ // else create handler for clsidHandler and feed data to it
+ // works for both normal and table marshal
+
+ IStdIdentity *pStdID;
+ IMarshal *pMarshal;
+ if (LookupIDFromID(idh.ObjectID, TRUE, &pStdID) == NOERROR)
+ {
+ // identity exists; we are holding it alive
+ hr = pStdID->QueryInterface(IID_IMarshal, (void**)&pMarshal);
+ pStdID->Release();
+ if (hr != NOERROR)
+ // something which supports identity must also support custom
+ // marshaling.
+ return E_UNEXPECTED;
+ }
+ else
+ {
+ // identity doesn't not exist; create object; add to table will be in
+ // the unmarshal below.
+
+ // CODEWORK: can we get check for duplicate identity here so
+ // the contention is easier to recover from??? Possibly we
+ // can create a dummy id which indicates we will register one
+ // or remove the dummy. Other thread could wait on that object
+ // and if that object went away, could then create its own
+ // dummy id and continue. All that would happen in LookupIDFromID.
+
+ // NOTE: this CLSCTX_INPROC_HANDLER is significant since we don't
+ // want to confuse an inproc server with what we know must be
+ // a handler. Besides, the 16bit code did it this way.
+
+ // if clsidHandler == CLSID_StdMarshal: create identity handler
+ // BUGBUG: should make the class object code do this (it did in 16bit)
+ if (IsEqualGUID(clsidHandler, CLSID_StdMarshal))
+ {
+UseStdMarshal:
+ hr = CreateIdentityHandler(NULL, PSTDMARSHAL,
+ IID_IMarshal, (void **)&pMarshal);
+ }
+ else
+ {
+ hr = CoCreateInstance(clsidHandler, NULL, CLSCTX_INPROC_HANDLER,
+ IID_IMarshal, (void **)&pMarshal);
+ // if not registered, use StdMarshal
+ if (hr == REGDB_E_CLASSNOTREG)
+ {
+ clsidHandler = CLSID_StdMarshal;
+ goto UseStdMarshal;
+ }
+ }
+
+ // NOTE: this pMarshal must consume the identity information first.
+ // the most common way for people to do that is to expose the IMarshal
+ // on the identity object as the IMarshal of the handler.
+
+ if (hr != NOERROR)
+ return hr;
+ }
+
+ hr = pMarshal->UnmarshalInterface(pStm, riid, ppv);
+ pMarshal->Release();
+
+ // CODEWORK: multithread issue: if already registered,skip back and try again.
+
+ return hr;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStaticMarshaler::ReleaseMarshalData, public
+//
+// Synopsis: First part of releasing the marshal data for an identity
+// object. Very much like UnmarshalInterface above.
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CStaticMarshaler::ReleaseMarshalData(LPSTREAM pStm)
+{
+ // CODEWORK PERF: if normal, we have to re-lookup the the identity;
+ // an alternative is to have the ::UnmarshalInteface method above
+ // do the release and mark the stream as released (perhaps even
+ // moving the HDLRFLAGS_RELEASED bit here); we would still have to
+ // return an error since we cannot actually consume the data. This
+ // works fine for the cases that matter (Unmarshal followed by
+ // Release).
+
+ HRESULT hr;
+ SIdentityDataHdr idh;
+ CLSID clsidHandler;
+
+ // read data header and optional clsidHandler; seek back;
+ hr = ReadIdentityHeader(pStm, &idh, &clsidHandler, TRUE /*fTransparent*/);
+ if (FAILED(hr))
+ return hr;
+
+ // lookup id; if exists, feed data to it
+ // else error (object already released)
+ // works for both normal and table marshal
+
+ // CODEWORK: when table marshaling changes, this code will have to
+ // change too.
+
+ IStdIdentity *pStdID;
+ IMarshal *pMarshal;
+ if (LookupIDFromID(idh.ObjectID, TRUE, &pStdID) == NOERROR)
+ {
+ // identity exists; we are holding it alive
+ hr = pStdID->QueryInterface(IID_IMarshal, (void**)&pMarshal);
+ pStdID->Release();
+ if (hr != NOERROR)
+ // something which supports identity must also support custom
+ // marshaling.
+ return E_UNEXPECTED;
+ }
+ else
+ {
+ // identity doesn't not exist; error
+
+ // BUGBUG: should do better here since this may happen in the
+ // error case. We would create an instance of the handler
+ // just for the destruction of the marshal data.
+ // Happened in bug 13086 before CStdIdentity::IsConnected was changed.
+ // If we don't do this, the marshal connection will not be released
+ // on the server side and the object may not shutdown as it should.
+
+ return CO_E_OBJNOTREG;
+ }
+
+ hr = pMarshal->ReleaseMarshalData(pStm);
+ pMarshal->Release();
+ return hr;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStaticMarshaler::DisconnectObject, public
+//
+// Synopsis: shouldn't be called.
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CStaticMarshaler::DisconnectObject(DWORD dwReserved)
+{
+ AssertSz(FALSE, "This DisconnectObject should not be called");
+
+ return E_UNEXPECTED;
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: GetStaticMarshaler, private
+//
+// Synopsis: Returns the single instance of the std identity unmarshaler.
+//
+// History: 11-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+INTERNAL_(IMarshal *) GetStaticMarshaler()
+{
+#if DBG == 1
+ sg_StaticMarshaler.AddRef();
+#endif
+ return &sg_StaticMarshaler;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: SkipMarshalExtension, private
+//
+// Synopsis: Skips the marshaling extension (DWORD cb, rgcb).
+//
+// Returns: stm errors if problem
+//
+// History: 14-Dec-93 CraigWi Created.
+//
+//--------------------------------------------------------------------
+
+INTERNAL SkipMarshalExtension(IStream *pStm)
+{
+ HRESULT hr;
+ DWORD cb;
+
+ hr = StRead(pStm, &cb, sizeof(cb));
+ if (FAILED(hr))
+ return hr;
+
+ LARGE_INTEGER li;
+ LISet32(li, cb);
+ return pStm->Seek(li, STREAM_SEEK_CUR, NULL);
+}
+
+
+
+
+//+------------------------------------------------------------------------
+//
+// Function: RewriteHeader, private
+//
+// Synopsis: Writes the given data at the offset given and restores the
+// stream to the position it was on entry.
+//
+// Arguments: [pStm] -- The stream into which we write the data
+// [pb] -- The data
+// [cb] -- The amount of data
+// [ulSeekStart] -- The place to write the data
+//
+// History: 15-May-94 CraigWi Created
+//
+//-------------------------------------------------------------------------
+
+INTERNAL_(void) RewriteHeader(IStream *pStm, void *pv, ULONG cb, ULARGE_INTEGER ulSeekStart)
+{
+ LARGE_INTEGER libMove;
+ ULARGE_INTEGER ulSeekEnd;
+
+ LISet32(libMove, 0x00000000);
+ if (SUCCEEDED(pStm->Seek(libMove, STREAM_SEEK_CUR, &ulSeekEnd)))
+ {
+ // go back to the starting position
+ libMove.LowPart = ulSeekStart.LowPart;
+ libMove.HighPart = ulSeekStart.HighPart;
+ if (SUCCEEDED(pStm->Seek(libMove, STREAM_SEEK_SET, NULL)))
+ {
+ // set the header bit and write it back into the stream
+ pStm->Write(pv, cb, NULL);
+ }
+
+ // regardless of whether the write worked, restore the stream
+ // back to the ending positon. ignore any errors generated here.
+
+ libMove.LowPart = ulSeekEnd.LowPart;
+ libMove.HighPart = ulSeekEnd.HighPart;
+ pStm->Seek(libMove, STREAM_SEEK_SET, NULL);
+ }
+}