1319 lines
41 KiB
C++
1319 lines
41 KiB
C++
|
//+-------------------------------------------------------------------
|
||
|
//
|
||
|
// 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);
|
||
|
}
|
||
|
}
|