//+------------------------------------------------------------------- // // File: ipmrshl.cpp // // Contents: Code the implements the standard free thread in process // marshaler. // // Classes: CFreeMarshaler // CFmCtrlUnknown // // Functions: CoCreateFreeThreadedMarshaler // // History: 03-Nov-94 Ricksa // //-------------------------------------------------------------------- #include #include //+------------------------------------------------------------------- // // Class: CFreeMarshaler // // Synopsis: Generic marshaling class // // Methods: IUnknown // IMarshal // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- class CFreeMarshaler : public IMarshal, public CPrivAlloc { public: CFreeMarshaler(IUnknown *punk); // IUnknown STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IMarshal Interface STDMETHODIMP GetUnmarshalClass( REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid); STDMETHODIMP GetMarshalSizeMax( REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize); STDMETHODIMP MarshalInterface( IStream __RPC_FAR *pStm, REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags); STDMETHODIMP UnmarshalInterface( IStream *pStm, REFIID riid, void **ppv); STDMETHODIMP ReleaseMarshalData(IStream *pStm); STDMETHODIMP DisconnectObject(DWORD dwReserved); private: friend class CFmCtrlUnknown; // Pointer to the controlling unknown. IUnknown * _punkCtrl; }; //+------------------------------------------------------------------- // // Class: CFmCtrlUnknown // // Synopsis: Controlling IUnknown for generic marshaling class. // // Methods: IUnknown // IMarshal // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- class CFmCtrlUnknown : public IUnknown, public CPrivAlloc { // IUnknown STDMETHODIMP QueryInterface(REFIID iid, void **ppv); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); private: friend HRESULT CoCreateFreeThreadedMarshaler( IUnknown *punkCtrl, IUnknown **punkMarshal); friend HRESULT GetInProcFreeMarshaler(IMarshal **ppIM); CFmCtrlUnknown(void); ~CFmCtrlUnknown(void); CFreeMarshaler * _pfm; ULONG _cRefs; }; //+------------------------------------------------------------------- // // Function: CoCreateFreeThreadedMarshaler, public // // Synopsis: Create the controlling unknown for the marshaler // // Arguments: [punkOuter] - controlling unknown // [ppunkMarshal] - controlling unknown for marshaler. // // Returns: NOERROR // E_INVALIDARG // E_OUTOFMEMORY // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- HRESULT CoCreateFreeThreadedMarshaler( IUnknown *punkOuter, IUnknown **ppunkMarshal) { HRESULT hr = E_INVALIDARG; // Validate the parameters if (((punkOuter == NULL) || IsValidInterface(punkOuter)) && IsValidPtrOut(ppunkMarshal, sizeof(IUnknown *))) { CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IUnknown,(IUnknown **)&punkOuter); // Assume failure *ppunkMarshal = NULL; hr = E_OUTOFMEMORY; // Allocate new free marshal object CFmCtrlUnknown *pfmc = new CFmCtrlUnknown(); if (pfmc != NULL) { if (punkOuter == NULL) { // Caller wants a non-aggreagated object punkOuter = pfmc; } // Initialize the pointer pfmc->_pfm = new CFreeMarshaler(punkOuter); if (pfmc->_pfm != NULL) { *ppunkMarshal = pfmc; CALLHOOKOBJECTCREATE(S_OK,CLSID_NULL,IID_IUnknown, (IUnknown **)ppunkMarshal); hr = S_OK; } else { delete pfmc; } } } return hr; } //+------------------------------------------------------------------- // // Function: GetInProcFreeMarshaler, public // // Synopsis: Create the controlling unknown for the marshaler // // Arguments: [ppIM] - where to put inproc marshaler // // Returns: NOERROR // E_OUTOFMEMORY // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- HRESULT GetInProcFreeMarshaler(IMarshal **ppIM) { HRESULT hr = E_OUTOFMEMORY; // Allocate new free marshal object CFmCtrlUnknown *pfmc = new CFmCtrlUnknown(); if (pfmc != NULL) { // Initialize the pointer pfmc->_pfm = new CFreeMarshaler(pfmc); if (pfmc->_pfm != NULL) { *ppIM = pfmc->_pfm; hr = S_OK; } else { delete pfmc; } } return hr; } //+------------------------------------------------------------------- // // Member: CFmCtrlUnknown::CFmCtrlUnknown // // Synopsis: The constructor for controling IUnknown of free marshaler // // Arguments: None // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- CFmCtrlUnknown::CFmCtrlUnknown(void) : _cRefs(1), _pfm(NULL) { // Header does all the work. } //+------------------------------------------------------------------- // // Member: CFmCtrlUnknown::~CFmCtrlUnknown // // Synopsis: The destructor for controling IUnknown of free marshaler // // Arguments: None // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- CFmCtrlUnknown::~CFmCtrlUnknown(void) { delete _pfm; } //+------------------------------------------------------------------- // // Member: CFmCtrlUnknown::QueryInterface // // Returns: S_OK // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP CFmCtrlUnknown::QueryInterface(REFIID iid, void **ppv) { *ppv = NULL; HRESULT hr = E_NOINTERFACE; if (IsEqualGUID(iid, IID_IUnknown)) { *ppv = this; AddRef(); hr = S_OK; } else if (IsEqualGUID(iid, IID_IMarshal)) { *ppv = _pfm; _pfm->AddRef(); hr = S_OK; } return hr; } //+------------------------------------------------------------------- // // Member: CFmCtrlUnknown::AddRef // // Synopsis: Standard stuff // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP_(ULONG) CFmCtrlUnknown::AddRef(void) { InterlockedIncrement((LONG *) &_cRefs); return _cRefs; } //+------------------------------------------------------------------- // // Member: CFmCtrlUnknown::Release // // Synopsis: Standard stuff // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP_(ULONG) CFmCtrlUnknown::Release(void) { ULONG cRefs = InterlockedDecrement((LONG *) &_cRefs); if (cRefs == 0) { delete this; } return cRefs; } //+------------------------------------------------------------------- // // Member: CFreeMarshaler::CFreeMarshaler() // // Synopsis: The constructor for CFreeMarshaler. // // Arguments: None // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- CFreeMarshaler::CFreeMarshaler(IUnknown *punkCtrl) : _punkCtrl(punkCtrl) { // Header does all the work. } //+------------------------------------------------------------------- // // Member: CFreeMarshaler::QueryInterface // // Synopsis: Pass QI to our controlling IUnknown // // Returns: S_OK // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP CFreeMarshaler::QueryInterface(REFIID iid, void **ppv) { return _punkCtrl->QueryInterface(iid, ppv); } //+------------------------------------------------------------------- // // Member: CFreeMarshaler::AddRef // // Synopsis: Pass AddRef to our controlling IUnknown // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP_(ULONG) CFreeMarshaler::AddRef(void) { return _punkCtrl->AddRef(); } //+------------------------------------------------------------------- // // Member: CFreeMarshaler::Release // // Synopsis: Pass release to our controlling IUnknown // // History: 15-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP_(ULONG) CFreeMarshaler::Release(void) { return _punkCtrl->Release(); } //+------------------------------------------------------------------- // // Member: CFreeMarshaler::GetUnmarshalClass // // Synopsis: Return the unmarshaling class // // History: 08-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP CFreeMarshaler::GetUnmarshalClass( REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid) { // Inprocess context? if (dwDestContext == MSHCTX_INPROC) { // If this is an inproc marshal then we are the class // that can unmarshal. *pCid = CLSID_InProcFreeMarshaler; return S_OK; } // we can just use the static guy here and save a lot of work. IMarshal *pmrshlStd; HRESULT hr = GetStaticUnMarshaler(&pmrshlStd); if (pmrshlStd != NULL) { hr = pmrshlStd->GetUnmarshalClass(riid, pv, dwDestContext, pvDestContext, mshlflags, pCid); pmrshlStd->Release(); } return hr; } //+------------------------------------------------------------------- // // Member: CFreeMarshaler::GetMarshalSizeMax // // Synopsis: Return maximum bytes need for marshaling // // History: 08-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP CFreeMarshaler::GetMarshalSizeMax( REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize) { // Inprocess context? if (dwDestContext == MSHCTX_INPROC) { // If this is an inproc marshal then we know the size *pSize = sizeof(this); return S_OK; } // we can just use the static guy here and save a lot of work. IMarshal *pmrshlStd; HRESULT hr = GetStaticUnMarshaler(&pmrshlStd); if (pmrshlStd != NULL) { hr = pmrshlStd->GetMarshalSizeMax(riid, pv, dwDestContext, pvDestContext, mshlflags, pSize); pmrshlStd->Release(); } return hr; } //+------------------------------------------------------------------- // // Member: CFreeMarshaler::MarshalInterface // // Synopsis: Marshal the interface // // History: 08-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP CFreeMarshaler::MarshalInterface( IStream *pStm, REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags) { HRESULT hr; // Inprocess context? if (dwDestContext == MSHCTX_INPROC) { // Write the marshal flags into the stream hr = pStm->Write(&mshlflags, sizeof(mshlflags), NULL); if (hr == NOERROR) { // Write the pointer into the stream ULONG cb; hr = pStm->Write(&pv, sizeof(pv), NULL); // Bump reference count based on type of marshal if ((hr == NOERROR) && (mshlflags != MSHLFLAGS_TABLEWEAK)) { ((IUnknown *) pv)->AddRef(); } } return hr; } // find or create a stdid for this object. Make sure we get a strong // reference to gaurd against a simultaneous last release by another // thread. CStdIdentity *pStdId; hr = LookupIDFromUnk((IUnknown *) pv, IDLF_CREATE | IDLF_STRONG, &pStdId); if (SUCCEEDED(hr)) { hr = pStdId->MarshalInterface(pStm, riid, pv, dwDestContext, pvDestContext, mshlflags); pStdId->DecStrongCnt(TRUE); // fKeepAlive } return hr; } //+------------------------------------------------------------------- // // Member: CFreeMarshaler::UnmarshalInterface // // Synopsis: Unmarshal the interface // // History: 08-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP CFreeMarshaler::UnmarshalInterface( IStream *pStm, REFIID riid, void **ppv) { HRESULT hr; // The marshal flags will tell us if we have to AddRef the object DWORD mshlflags; hr = pStm->Read(&mshlflags, sizeof(mshlflags), NULL); if (hr == NOERROR) { // If Inprocess, we just read the pointer out of the stream hr = pStm->Read(ppv, sizeof(*ppv), NULL); // AddRef the pointer if marshaled for a table. if ((hr == NOERROR) && ((mshlflags == MSHLFLAGS_TABLEWEAK) || (mshlflags == MSHLFLAGS_TABLESTRONG))) { ((IUnknown *) *ppv)->AddRef(); } } return hr; } //+------------------------------------------------------------------- // // Member: CFreeMarshaler::ReleaseMarshalData // // Synopsis: Release the marshaled data // // History: 08-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP CFreeMarshaler::ReleaseMarshalData(IStream *pStm) { // Get the marshal flags DWORD mshlflags; HRESULT hr = pStm->Read(&mshlflags, sizeof(mshlflags), NULL); if (hr == NOERROR) { IUnknown *punk; // If Inprocess, we just read the pointer out of the stream hr = pStm->Read(&punk, sizeof(punk), NULL); if ((hr == NOERROR) && (mshlflags != MSHLFLAGS_TABLEWEAK)) { // Dump the extra AddRef we put on when we put the object // during marshal. punk->Release(); } } return hr; } //+------------------------------------------------------------------- // // Member: CFreeMarshaler::DisconnectObject // // Synopsis: Disconnect the object // // History: 08-Nov-94 Ricksa Created // //-------------------------------------------------------------------- STDMETHODIMP CFreeMarshaler::DisconnectObject(DWORD dwReserved) { CStdIdentity *pStdId; HRESULT hr = LookupIDFromUnk(_punkCtrl, 0, &pStdId); if (SUCCEEDED(hr)) { hr = pStdId->DisconnectObject(dwReserved); pStdId->Release(); } else { // already disconnected, report success hr = S_OK; } return hr; }