//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1993. // // File: transmit.cxx // // Contents: Support for Windows/OLE data types for oleprx32.dll. // Used to be transmit_as routines, now user_marshal routines. // // Functions: HGLOBAL_UserSize // HGLOBAL_UserMarshal // HGLOBAL_UserUnmarshal // HGLOBAL_UserFree // HMETAFILEPICT_UserSize // HMETAFILEPICT_UserMarshal // HMETAFILEPICT_UserUnmarshal // HMETAFILEPICT_UserFree // HENHMETAFILE_UserSize // HENHMETAFILE_UserMarshal // HENHMETAFILE_UserUnmarshal // HENHMETAFILE_UserFree // HBITMAP_UserSize // HBITMAP_UserMarshal // HBITMAP_UserUnmarshal // HBITMAP_UserFree // HBRUSH_UserSize // HBRUSH_UserMarshal // HBRUSH_UserUnmarshal // HBRUSH_UserFree // STGMEDIUM_UserSize // STGMEDIUM_UserMarshal // STGMEDIUM_UserUnmarshal // STGMEDIUM_UserFree // HACCEL_UserSize // HACCEL_UserMarshal // HACCEL_UserUnmarshal // HACCEL_UserFree // HWND_UserSize // HWND_UserMarshal // HWND_UserUnmarshal // HWND_UserFree // HMENU_UserSize // HMENU_UserMarshal // HMENU_UserUnmarshal // HMENU_UserFree // // History: 24-Aug-93 ShannonC Created // 24-Nov-93 ShannonC Added HGLOBAL // 14-May-94 DavePl Added HENHMETAFILE // 18-May-94 ShannonC Added HACCEL, UINT, WPARAM // 19-May-94 DavePl Added HENHMETAFILE to STGMEDIUM code // May-95 Ryszardk Wrote all the _User* routines // //-------------------------------------------------------------------------- #include "stdrpc.hxx" #pragma hdrstop #include #include #include "transmit.h" #include WINOLEAPI_(void) ReleaseStgMedium(LPSTGMEDIUM pStgMed); #pragma code_seg(".orpc") EXTERN_C const CLSID CLSID_MyPSFactoryBuffer = {0x6f11fe5c,0x2fc5,0x101b,{0x9e,0x45,0x00,0x00,0x0b,0x65,0xc7,0xef}}; //+------------------------------------------------------------------------- // // class: CPunkForRelease // // purpose: special IUnknown for remoted STGMEDIUMs // // history: 02-Mar-94 Rickhi Created // // notes: This class is used to do the cleanup correctly when certain // types of storages are passed between processes or machines // in Nt and Chicago. // // On NT, GLOBAL, GDI, and BITMAP handles cannot be passed between // processes, so we actually copy the whole data and create a // new handle in the receiving process. However, STGMEDIUMs have // this weird behaviour where if PunkForRelease is non-NULL then // the sender is responsible for cleanup, not the receiver. Since // we create a new handle in the receiver, we would leak handles // if we didnt do some special processing. So, we do the // following... // // During STGMEDIUM_UserUnmarshal, if there is a pUnkForRelease // replace it with a CPunkForRelease. When Release is called // on the CPunkForRelease, do the necessary cleanup work, // then call the real PunkForRelease. // //+------------------------------------------------------------------------- class CPunkForRelease : public IUnknown { public: CPunkForRelease( STGMEDIUM *pStgMed, ulong fTopLayerOnly); // IUnknown Methods STDMETHOD(QueryInterface)(REFIID riid, void **ppunk); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(ULONG, Release)(void); private: ~CPunkForRelease(void); ULONG _cRefs; // reference count ULONG _fTopLayerMFP:1; // optimisation flag for Chicago STGMEDIUM _stgmed; // storage medium IUnknown * _pUnkForRelease; // real pUnkForRelease }; inline CPunkForRelease::CPunkForRelease( STGMEDIUM * pStgMed, ulong fTopLayerMFPict ) : _cRefs(1), _fTopLayerMFP( fTopLayerMFPict), _stgmed(*pStgMed) { // NOTE: we assume the caller has verified pStgMed is not NULL, // and the pUnkForRelease is non-null, otherwise there is no // point in constructing this object. The tymed must also be // one of the special ones. UserNdrAssert(pStgMed); UserNdrAssert(pStgMed->tymed == TYMED_HGLOBAL || pStgMed->tymed == TYMED_GDI || pStgMed->tymed == TYMED_MFPICT || pStgMed->tymed == TYMED_ENHMF); _pUnkForRelease = pStgMed->pUnkForRelease; } inline CPunkForRelease::~CPunkForRelease() { // since we really have our own copies of these handles' data, just // pretend like the callee is responsible for the release, and // recurse into ReleaseStgMedium to do the cleanup. _stgmed.pUnkForRelease = NULL; // There is this weird optimized case of Chicago MFPICT when we have two // layers with a HENHMETAFILE handle inside. Top layer is an HGLOBAL. if ( _fTopLayerMFP ) GlobalFree( _stgmed.hGlobal ); else ReleaseStgMedium( &_stgmed ); // release the callers punk _pUnkForRelease->Release(); } STDMETHODIMP_(ULONG) CPunkForRelease::AddRef(void) { InterlockedIncrement((LONG *)&_cRefs); return _cRefs; } STDMETHODIMP_(ULONG) CPunkForRelease::Release(void) { long Ref = _cRefs - 1; UserNdrAssert( _cRefs ); if (InterlockedDecrement((LONG *)&_cRefs) == 0) { // null out the vtable. long * p = (long *)this; *p = 0; delete this; return 0; } else return Ref; } STDMETHODIMP CPunkForRelease::QueryInterface(REFIID riid, void **ppv) { if (IsEqualIID(riid, IID_IUnknown)) { *ppv = (void *)(IUnknown *) this; AddRef(); return S_OK; } else { *ppv = NULL; return E_NOINTERFACE; } } // These methods are needed as the object is used for interface marshaling. /***************************************************************************/ STDMETHODIMP_(ULONG) CStreamOnMessage::AddRef( THIS ) { return ref_count += 1; } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::Clone(THIS_ IStream * *ppstm) { return ResultFromScode(E_NOTIMPL); } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::Commit(THIS_ DWORD grfCommitFlags) { return ResultFromScode(E_NOTIMPL); } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::CopyTo(THIS_ IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) { return ResultFromScode(E_NOTIMPL); } /***************************************************************************/ CStreamOnMessage::CStreamOnMessage(unsigned char **ppMessageBuffer) : ref_count(1), ppBuffer(ppMessageBuffer), cbMaxStreamLength(0xFFFFFFFF) { pStartOfStream = *ppMessageBuffer; } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::LockRegion(THIS_ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { return ResultFromScode(E_NOTIMPL); } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::QueryInterface( REFIID riid, LPVOID FAR* ppvObj) { if (IsEqualIID(riid, IID_IUnknown)) { *ppvObj = (IUnknown *) this; ref_count += 1; return ResultFromScode(S_OK); } else if (IsEqualIID(riid, IID_IStream)) { *ppvObj = (IStream *) this; ref_count += 1; return ResultFromScode(S_OK); } else return ResultFromScode(E_NOINTERFACE); } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::Read(THIS_ VOID HUGEP *pv, ULONG cb, ULONG *pcbRead) { memcpy( pv, *ppBuffer, cb ); *ppBuffer += cb; if (pcbRead != NULL) *pcbRead = cb; return ResultFromScode(S_OK); } /***************************************************************************/ STDMETHODIMP_(ULONG) CStreamOnMessage::Release( THIS ) { ref_count -= 1; if (ref_count == 0) { delete this; return 0; } else return ref_count; } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::Revert(THIS) { return ResultFromScode(E_NOTIMPL); } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::Seek(THIS_ LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { ULONG pos; // Verify that the offset isn't out of range. if (dlibMove.HighPart != 0) return ResultFromScode( E_FAIL ); // Determine the new seek pointer. switch (dwOrigin) { case STREAM_SEEK_SET: pos = dlibMove.LowPart; break; case STREAM_SEEK_CUR: /* Must use signed math here. */ pos = *ppBuffer - pStartOfStream; if ((long) dlibMove.LowPart < 0 && pos < (unsigned long) - (long) dlibMove.LowPart) return ResultFromScode( E_FAIL ); pos += (long) dlibMove.LowPart; break; case STREAM_SEEK_END: return ResultFromScode(E_NOTIMPL); break; default: return ResultFromScode( E_FAIL ); } // Set the seek pointer. *ppBuffer = pStartOfStream + pos; if (plibNewPosition != NULL) { plibNewPosition->LowPart = pos; plibNewPosition->HighPart = 0; } return ResultFromScode(S_OK); } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::SetSize(THIS_ ULARGE_INTEGER libNewSize) { return ResultFromScode(E_NOTIMPL); } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::Stat(THIS_ STATSTG *pstatstg, DWORD grfStatFlag) { return ResultFromScode(E_NOTIMPL); } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::UnlockRegion(THIS_ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { return ResultFromScode(E_NOTIMPL); } /***************************************************************************/ STDMETHODIMP CStreamOnMessage::Write(THIS_ VOID const HUGEP *pv, ULONG cb, ULONG *pcbWritten) { // Write the data. memcpy( *ppBuffer, pv, cb ); if (pcbWritten != NULL) *pcbWritten = cb; *ppBuffer += cb; return ResultFromScode(S_OK); } //+------------------------------------------------------------------------- // // Function: SNB_UserSize // // Synopsis: Sizes an SNB. // // Derivation: An array of strings in one block of memory. // // history: June-95 Ryszardk Created, based on SNB_*_xmit. // //-------------------------------------------------------------------------- unsigned long __RPC_USER SNB_UserSize ( unsigned long * pFlags, unsigned long Offset, SNB * pSnb ) { if ( ! pSnb ) return Offset; // calculate the number of strings and characters (with their terminators) ULONG ulCntStr = 0; ULONG ulCntChar = 0; if (pSnb && *pSnb) { SNB snb = *pSnb; WCHAR *psz = *snb; while (psz) { ulCntChar += wcslen(psz) + 1; ulCntStr++; snb++; psz = *snb; } } // The wire size is: conf size, 2 fields and the wchars. LENGTH_ALIGN( Offset, 3 ); return ( Offset + 3 * sizeof(long) + ulCntChar * sizeof( WCHAR ) ); } //+------------------------------------------------------------------------- // // Function: SNB_UserMarshall // // Synopsis: Marshalls an SNB into the RPC buffer. // // Derivation: An array of strings in one block of memory. // // history: June-95 Ryszardk Created, based on SNB_*_xmit. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER SNB_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, SNB * pSnb ) { UserNdrDebugOut((UNDR_FORCE, "SNB_UserMarshal\n")); if ( ! pSnb ) return pBuffer; // calculate the number of strings and characters (with their terminators) ULONG ulCntStr = 0; ULONG ulCntChar = 0; if (pSnb && *pSnb) { SNB snb = *pSnb; WCHAR *psz = *snb; while (psz) { ulCntChar += wcslen(psz) + 1; ulCntStr++; snb++; psz = *snb; } } // conformant size ALIGN( pBuffer, 3 ); *( PULONG_LV_CAST pBuffer)++ = ulCntChar; // fields *( PULONG_LV_CAST pBuffer)++ = ulCntStr; *( PULONG_LV_CAST pBuffer)++ = ulCntChar; // actual strings only if ( pSnb && *pSnb ) { // There is a NULL string pointer to mark the end of the pointer array. // However, the strings don't have to follow tightly. // Hence, we have to copy one string at a time. SNB snb = *pSnb; WCHAR *pszSrc; while (pszSrc = *snb++) { ULONG ulCopyLen = (wcslen(pszSrc) + 1) * sizeof(WCHAR); WdtpMemoryCopy( pBuffer, pszSrc, ulCopyLen ); pBuffer += ulCopyLen; } } return pBuffer; } //+------------------------------------------------------------------------- // // Function: SNB_UserUnmarshall // // Synopsis: Unmarshalls an SNB from the RPC buffer. // // Derivation: An array of strings in one block of memory. // // history: June-95 Ryszardk Created, based on SNB_*_xmit. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER SNB_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, SNB * pSnb ) { UserNdrDebugOut((UNDR_FORCE, "SNB_UserUnmarshal\n")); ALIGN( pBuffer, 3 ); // conf size unsigned long ulCntChar = *( PULONG_LV_CAST pBuffer)++; // fields unsigned long ulCntStr = *( PULONG_LV_CAST pBuffer)++; pBuffer += sizeof(long); // no reusage of pSNB. if ( *pSnb ) WdtpFree( pFlags, *pSnb ); if ( ulCntStr == 0 ) { *pSnb = NULL; return pBuffer; } // construct the SNB. SNB Snb = (SNB) WdtpAllocate( pFlags, ( (ulCntStr + 1) * sizeof(WCHAR *) + ulCntChar * sizeof(WCHAR)) ); *pSnb = Snb; if (Snb) { // create the pointer array within the SNB. WCHAR *pszSrc = (WCHAR *) pBuffer; WCHAR *pszTgt = (WCHAR *) (Snb + ulCntStr + 1); // right behind array for (ULONG i = ulCntStr; i > 0; i--) { *Snb++ = pszTgt; ULONG ulLen = wcslen(pszSrc) + 1; pszSrc += ulLen; pszTgt += ulLen; } *Snb++ = NULL; // Copy the actual strings. // We can do a block copy here as we packed them tight in the buffer. // Snb points right behind the lastarray of pointers within the SNB. WdtpMemoryCopy( Snb, pBuffer, ulCntChar * sizeof(WCHAR) ); pBuffer += ulCntChar * sizeof(WCHAR); } return pBuffer; } //+------------------------------------------------------------------------- // // Function: SNB_UserFree // // Synopsis: Frees an SNB. // // Derivation: An array of strings in one block of memory. // // history: June-95 Ryszardk Created, based on SNB_*_xmit. // //-------------------------------------------------------------------------- void __RPC_USER SNB_UserFree( unsigned long * pFlags, SNB * pSnb ) { if ( pSnb && *pSnb ) WdtpFree( pFlags, *pSnb ); } //+------------------------------------------------------------------------- // // Function: WdtpVoidStar_UserSize // // Synopsis: Sizes a remotable void star as ulong. // // history: June-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned long __RPC_USER WdtpVoidStar_UserSize ( unsigned long * pFlags, unsigned long Offset, unsigned long * pVoid ) { if ( !pVoid ) return Offset; LENGTH_ALIGN( Offset, 3 ); return( Offset + 4 ) ; } //+------------------------------------------------------------------------- // // Function: WdtpVoidStar_UserMarshall // // Synopsis: Marshalls a remotable void star as ulong. // // history: June-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER WdtpVoidStar_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, unsigned long * pVoid ) { if ( !pVoid ) return pBuffer; ALIGN( pBuffer, 3 ); *( PULONG_LV_CAST pBuffer)++ = *pVoid; return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: WdtpVoidStaer_UserUnmarshall // // Synopsis: Unmarshalls a remotable void star as ulong. // // history: June-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER WdtpVoidStar_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, unsigned long * pVoid ) { ALIGN( pBuffer, 3 ); *pVoid= *( PULONG_LV_CAST pBuffer)++; return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: WdtpVoidStar_UserFree // //-------------------------------------------------------------------------- void __RPC_USER WdtpVoidStar_UserFree( unsigned long * pFlags, unsigned long * pVoid ) { } //+------------------------------------------------------------------------- // // Function: HWND_UserSize // // Synopsis: Sizes an HWND handle. // //-------------------------------------------------------------------------- unsigned long __RPC_USER HWND_UserSize ( unsigned long * pFlags, unsigned long Offset, HWND * pH ) { return WdtpVoidStar_UserSize( pFlags, Offset, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HWND_UserMarshall // // Synopsis: Marshalls an HWND handle into the RPC buffer. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HWND_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, HWND * pH ) { return WdtpVoidStar_UserMarshal( pFlags, pBuffer, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HWND_UserUnmarshall // // Synopsis: Unmarshalls an HWND handle from the RPC buffer. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HWND_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, HWND * pH ) { return WdtpVoidStar_UserUnmarshal( pFlags, pBuffer, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HWND_UserFree // // Synopsis: Shouldn't be called. // //-------------------------------------------------------------------------- void __RPC_USER HWND_UserFree( unsigned long * pFlags, HWND * pH ) { } //+------------------------------------------------------------------------- // // Function: HMENU_UserSize // // Synopsis: Sizes an HMENU handle. // //-------------------------------------------------------------------------- unsigned long __RPC_USER HMENU_UserSize ( unsigned long * pFlags, unsigned long Offset, HMENU * pH ) { return WdtpVoidStar_UserSize( pFlags, Offset, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HMENU_UserMarshall // // Synopsis: Marshalls an HMENU handle into the RPC buffer. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HMENU_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, HMENU * pH ) { return WdtpVoidStar_UserMarshal( pFlags, pBuffer, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HMENU_UserUnmarshall // // Synopsis: Unmarshalls an HMENU handle from the RPC buffer. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HMENU_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, HMENU * pH ) { return WdtpVoidStar_UserUnmarshal( pFlags, pBuffer, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HMENU_UserFree // // Synopsis: Free an HMENU. // //-------------------------------------------------------------------------- void __RPC_USER HMENU_UserFree( unsigned long * pFlags, HMENU * pH ) { } //+------------------------------------------------------------------------- // // Function: HACCEL_UserSize // // Synopsis: Sizes an HACCEL handle. // //-------------------------------------------------------------------------- unsigned long __RPC_USER HACCEL_UserSize ( unsigned long * pFlags, unsigned long Offset, HACCEL * pH ) { return WdtpVoidStar_UserSize( pFlags, Offset, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HACCEL_UserMarshall // // Synopsis: Marshalls an HACCEL handle into the RPC buffer. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HACCEL_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, HACCEL * pH ) { return WdtpVoidStar_UserMarshal( pFlags, pBuffer, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HACCEL_UserUnmarshall // // Synopsis: Unmarshalls an HACCEL handle from the RPC buffer. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HACCEL_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, HACCEL * pH ) { return WdtpVoidStar_UserUnmarshal( pFlags, pBuffer, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HACCEL_UserFree // // Synopsis: Free an HACCEL. // //-------------------------------------------------------------------------- void __RPC_USER HACCEL_UserFree( unsigned long * pFlags, HACCEL * pH ) { } //+------------------------------------------------------------------------- // // Function: HBRUSH_UserSize // // Synopsis: Sizes an HBRUSH handle. // //-------------------------------------------------------------------------- unsigned long __RPC_USER HBRUSH_UserSize ( unsigned long * pFlags, unsigned long Offset, HBRUSH * pH ) { return WdtpVoidStar_UserSize( pFlags, Offset, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HBRUSH_UserMarshall // // Synopsis: Marshalls an HBRUSH handle into the RPC buffer. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HBRUSH_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, HBRUSH * pH ) { return WdtpVoidStar_UserMarshal( pFlags, pBuffer, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HBRUSH_UserUnmarshall // // Synopsis: Unmarshalls an HBRUSH handle from the RPC buffer. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HBRUSH_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, HBRUSH * pH ) { return WdtpVoidStar_UserUnmarshal( pFlags, pBuffer, (ulong*)pH ); } //+------------------------------------------------------------------------- // // Function: HBRUSH_UserFree // // Synopsis: Free an HBRUSH. // //-------------------------------------------------------------------------- void __RPC_USER HBRUSH_UserFree( unsigned long * pFlags, HBRUSH * pH ) { } // ######################################################################### // // HGLOBAL. // See transmit.h for explanation of strict data/handle passing. // // ######################################################################### //+------------------------------------------------------------------------- // // Function: HGLOBAL_UserSize // // Synopsis: Get the wire size the HGLOBAL handle and data. // // Derivation: Conformant struct with a flag field: // align + 12 + data size. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned long __RPC_USER HGLOBAL_UserSize ( unsigned long * pFlags, unsigned long Offset, HGLOBAL * pGlobal) { if ( !pGlobal ) return Offset; // userHGLOBAL: the encapsulated union. // Discriminant and then handle or pointer from the union arm. LENGTH_ALIGN( Offset, 3 ); Offset += sizeof(long) + sizeof(void*); if ( ! *pGlobal ) return Offset; if ( HGLOBAL_DATA_PASSING(*pFlags) ) { unsigned long ulDataSize = GlobalSize( *pGlobal ); Offset += 3 * sizeof(long) + ulDataSize; } return( Offset ); } //+------------------------------------------------------------------------- // // Function: HGLOBAL_UserMarshall // // Synopsis: Marshalls an HGLOBAL object into the RPC buffer. // // Derivation: Conformant struct with a flag field: // align, size, null flag, size, data (bytes, if any) // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HGLOBAL_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, HGLOBAL * pGlobal) { if ( !pGlobal ) return pBuffer; // We marshal a null handle, too. UserNdrDebugOut((UNDR_OUT4, "HGLOBAL_UserMarshal\n")); ALIGN( pBuffer, 3 ); // Discriminant of the encapsulated union and union arm. if ( HGLOBAL_DATA_PASSING(*pFlags) ) { unsigned long ulDataSize; // userHGLOBAL *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong) *pGlobal; if ( ! *pGlobal ) return pBuffer; // FLAGGED_BYTE_BLOB ulDataSize = GlobalSize( *pGlobal ); *( PULONG_LV_CAST pBuffer)++ = ulDataSize; // Handle is the non-null flag *( PULONG_LV_CAST pBuffer)++ = (ulong)*pGlobal; *( PULONG_LV_CAST pBuffer)++ = ulDataSize; if( ulDataSize ) { void * pData = GlobalLock( *pGlobal); memcpy( pBuffer, pData, ulDataSize ); GlobalUnlock( *pGlobal); } pBuffer += ulDataSize; } else { // Sending a handle. *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong) *pGlobal; } return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: WdtpGlobalUnmarshal // // Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer. // // Derivation: Conformant struct with a flag field: // align, size, null flag, size, data (bytes, if any) // // Note: Reallocation is forbidden when the hglobal is part of // an [in,out] STGMEDIUM in IDataObject::GetDataHere. // This affects only data passing with old handles being // non null. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER WdtpGlobalUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, HGLOBAL * pGlobal, BOOL fCanReallocate ) { unsigned long ulDataSize, fHandle, UnionDisc; HGLOBAL hGlobal; ALIGN( pBuffer, 3 ); UnionDisc = *( PULONG_LV_CAST pBuffer)++; hGlobal = (HGLOBAL) *( PULONG_LV_CAST pBuffer)++; if ( IS_DATA_MARKER( UnionDisc) ) { if ( ! hGlobal ) { if ( *pGlobal ) GlobalFree( *pGlobal ); *pGlobal = NULL; return pBuffer; } // There is a handle data on wire. ulDataSize = *( PULONG_LV_CAST pBuffer)++; // fhandle and data size again. pBuffer += 8; if ( *pGlobal ) { // Check for reallocation if ( GlobalSize( *pGlobal ) == ulDataSize ) hGlobal = *pGlobal; else { if ( fCanReallocate ) { // hGlobal = GlobalReAlloc( *pGlobal, ulDataSize, GMEM_MOVEABLE ); GlobalFree( *pGlobal ); hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize ); } else { if ( GlobalSize(*pGlobal) < ulDataSize ) RpcRaiseException( STG_E_MEDIUMFULL ); else hGlobal = *pGlobal; } } } else { // allocate a new block hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize ); } if ( hGlobal == NULL ) RpcRaiseException(E_OUTOFMEMORY); else { void * pData = GlobalLock( hGlobal); memcpy( pData, pBuffer, ulDataSize ); pBuffer += ulDataSize; GlobalUnlock( hGlobal); } } else { // Sending a handle only. // Reallocation problem doesn't apply to handle passing. if ( *pGlobal != hGlobal && *pGlobal ) GlobalFree( *pGlobal ); } *pGlobal = hGlobal; return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: HGLOBAL_UserUnmarshall // // Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer. // // Derivation: Conformant struct with a flag field: // align, size, null flag, size, data (bytes, if any) // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HGLOBAL_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, HGLOBAL * pGlobal) { return( WdtpGlobalUnmarshal( pFlags, pBuffer, pGlobal, TRUE ) ); // reallocation possible } //+------------------------------------------------------------------------- // // Function: HGLOBAL_UserFree // // Synopsis: Free an HGLOBAL. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- void __RPC_USER HGLOBAL_UserFree( unsigned long * pFlags, HGLOBAL * pGlobal) { if( pGlobal && *pGlobal ) { if ( HGLOBAL_DATA_PASSING(*pFlags) ) GlobalFree( *pGlobal); } } // ######################################################################### // // HMETAFILEPICT // See transmit.h for explanation of strict vs. lax data/handle passing. // // ######################################################################### //+------------------------------------------------------------------------- // // Function: HMETAFILEPICT_UserSize // // Synopsis: Get the wire size the HMETAFILEPICT handle and data. // // Derivation: Union of a long and the meta file pict handle. // Then struct with top layer (and a hmetafile handle). // The the representation of the metafile. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned long __RPC_USER HMETAFILEPICT_UserSize ( unsigned long * pFlags, unsigned long Offset, HMETAFILEPICT * pHMetaFilePict ) { if ( !pHMetaFilePict ) return Offset; LENGTH_ALIGN( Offset, 3 ); // Discriminant of the encapsulated union and the union arm. Offset += 8; if ( ! *pHMetaFilePict ) return Offset; if ( HGLOBAL_HANDLE_PASSING(*pFlags) ) return Offset; // Now, this is a two layer object with HGLOBAL on top. // Upper layer - hglobal part - needs to be sent as data. METAFILEPICT * pMFP = (METAFILEPICT*) GlobalLock( *(HANDLE *)pHMetaFilePict ); if ( pMFP == NULL ) RpcRaiseException( E_OUTOFMEMORY ); // Upper layer: 3 long fields + handle Offset += 3 * sizeof(long) + sizeof(void*); // The lower part is a metafile handle. if ( HGLOBAL_DATA_PASSING( *pFlags) ) { ulong ulDataSize = GetMetaFileBitsEx( pMFP->hMF, 0 , NULL ); Offset += 12 + ulDataSize; } GlobalUnlock( *(HANDLE *)pHMetaFilePict ); return( Offset ) ; } //+------------------------------------------------------------------------- // // Function: HMETAFILEPICT_UserMarshal // // Synopsis: Marshalls an HMETAFILEPICT object into the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HMETAFILEPICT_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, HMETAFILEPICT * pHMetaFilePict ) { if ( !pHMetaFilePict ) return pBuffer; UserNdrDebugOut((UNDR_OUT4, "HMETAFILEPICT_UserMarshal\n")); ALIGN( pBuffer, 3 ); if ( HGLOBAL_HANDLE_PASSING(*pFlags) ) { // Sending only the top level global handle. *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong)*(HANDLE*)pHMetaFilePict; return pBuffer; } // userHMETAFILEPICT // We need to send the data from the top (hglobal) layer. *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong)*pHMetaFilePict; if ( ! *pHMetaFilePict ) return pBuffer; // remoteHMETAFILEPICT METAFILEPICT * pMFP = (METAFILEPICT*) GlobalLock( *(HANDLE *)pHMetaFilePict ); if ( pMFP == NULL ) RpcRaiseException( E_OUTOFMEMORY ); *( PULONG_LV_CAST pBuffer)++ = pMFP->mm; *( PULONG_LV_CAST pBuffer)++ = pMFP->xExt; *( PULONG_LV_CAST pBuffer)++ = pMFP->yExt; *( PULONG_LV_CAST pBuffer)++ = (ulong) pMFP->hMF; // See if the HMETAFILE needs to be sent as data, too. if ( pMFP->hMF && HGLOBAL_DATA_PASSING(*pFlags) ) { ulong ulDataSize = GetMetaFileBitsEx( pMFP->hMF, 0 , NULL ); // conformant size then the size field *( PULONG_LV_CAST pBuffer)++ = ulDataSize; *( PULONG_LV_CAST pBuffer)++ = ulDataSize; GetMetaFileBitsEx( pMFP->hMF, ulDataSize , pBuffer ); pBuffer += ulDataSize; } GlobalUnlock( *(HANDLE *)pHMetaFilePict ); return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: HMETAFILEPICT_UserUnmarshal // // Synopsis: Unmarshalls an HMETAFILEPICT object from the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HMETAFILEPICT_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBufferStart, HMETAFILEPICT * pHMetaFilePict ) { unsigned long ulDataSize, fHandle; unsigned char * pBuffer; HMETAFILEPICT hMetaFilePict; UserNdrDebugOut((UNDR_OUT4, "HMETAFILEPICT_UserUnmarshal\n")); pBuffer = pBufferStart; ALIGN( pBuffer, 3 ); unsigned long UnionDisc = *( PULONG_LV_CAST pBuffer)++; hMetaFilePict = (HMETAFILEPICT) *( PULONG_LV_CAST pBuffer)++; if ( IS_DATA_MARKER( UnionDisc) && hMetaFilePict ) { HGLOBAL hGlobal = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) ); hMetaFilePict = (HMETAFILEPICT) hGlobal; if ( hMetaFilePict == NULL ) RpcRaiseException( E_OUTOFMEMORY ); METAFILEPICT * pMFP = (METAFILEPICT*) GlobalLock( (HANDLE) hMetaFilePict ); if ( pMFP == NULL ) RpcRaiseException( E_OUTOFMEMORY ); pMFP->mm = *( PULONG_LV_CAST pBuffer)++; pMFP->xExt = *( PULONG_LV_CAST pBuffer)++; pMFP->yExt = *( PULONG_LV_CAST pBuffer)++; pMFP->hMF = (HMETAFILE) *( PULONG_LV_CAST pBuffer)++; if ( pMFP->hMF && HGLOBAL_DATA_PASSING(*pFlags) ) { // conformant size then the size field ulong ulDataSize = *( PULONG_LV_CAST pBuffer)++; pBuffer += 4; pMFP->hMF = SetMetaFileBitsEx( ulDataSize, (uchar*)pBuffer ); pBuffer += ulDataSize; } GlobalUnlock( (HANDLE) hMetaFilePict ); } // no reusage, just release the previous one. if ( *pHMetaFilePict ) { // This may happen on the client only and doesn't depend on // how the other one was passed. METAFILEPICT * pMFP = (METAFILEPICT*) GlobalLock( *(HANDLE *)pHMetaFilePict ); if ( pMFP == NULL ) RpcRaiseException( E_OUTOFMEMORY ); if ( pMFP->hMF ) DeleteMetaFile( pMFP->hMF ); GlobalUnlock( *pHMetaFilePict ); GlobalFree( *pHMetaFilePict ); } *pHMetaFilePict = hMetaFilePict; return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: HMETAFILEPICT_UserFree // // Synopsis: Free an HMETAFILEPICT. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- void __RPC_USER HMETAFILEPICT_UserFree( unsigned long * pFlags, HMETAFILEPICT * pHMetaFilePict ) { UserNdrDebugOut((UNDR_FORCE, "HMETAFILEPICT_UserFree\n")); if( pHMetaFilePict && *pHMetaFilePict ) { if ( HGLOBAL_HANDLE_PASSING(*pFlags) ) return; // Need to free the upper hglobal part. METAFILEPICT * pMFP = (METAFILEPICT*) GlobalLock( *(HANDLE *)pHMetaFilePict ); if ( pMFP == NULL ) RpcRaiseException( E_OUTOFMEMORY ); // See if we need to free the hglobal, too. if ( pMFP->hMF && HGLOBAL_DATA_PASSING(*pFlags) ) DeleteMetaFile( pMFP->hMF ); GlobalUnlock( *pHMetaFilePict ); GlobalFree( *pHMetaFilePict ); } } // ######################################################################### // // HENHMETAFILE // See transmit.h for explanation of lax data/handle passing. // // ######################################################################### //+------------------------------------------------------------------------- // // Function: HENHMETAFILE_UserSize // // Synopsis: Get the wire size the HENHMETAFILE handle and data. // // Derivation: Union of a long and the meta file handle and then struct. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned long __RPC_USER HENHMETAFILE_UserSize ( unsigned long * pFlags, unsigned long Offset, HENHMETAFILE * pHEnhMetafile ) { if ( !pHEnhMetafile ) return Offset; LENGTH_ALIGN( Offset, 3 ); // The encapsulated union. // Discriminant and then handle or pointer from the union arm. Offset += sizeof(long) + sizeof(void*); if ( ! *pHEnhMetafile ) return Offset; if ( GDI_DATA_PASSING(*pFlags) ) { // Pointee of the union arm for the remote case. // Byte blob : conformant size, size field, data Offset += 2 * sizeof(long); ulong ulDataSize = GetEnhMetaFileBits( *pHEnhMetafile, 0, NULL ); Offset += ulDataSize; } return( Offset ); } //+------------------------------------------------------------------------- // // Function: HENHMETAFILE_UserMarshall // // Synopsis: Marshalls an HENHMETAFILE object into the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HENHMETAFILE_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, HENHMETAFILE * pHEnhMetafile ) { if ( !pHEnhMetafile ) return pBuffer; UserNdrDebugOut((UNDR_OUT4, "HENHMETAFILE_UserMarshal\n")); ALIGN( pBuffer, 3 ); // Discriminant of the encapsulated union and union arm. if ( GDI_DATA_PASSING(*pFlags) ) { // userHENHMETAFILE *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong) *pHEnhMetafile; if ( !*pHEnhMetafile ) return pBuffer; // BYTE_BLOB: conformant size, size field, data ulong ulDataSize = GetEnhMetaFileBits( *pHEnhMetafile, 0, NULL ); *( PULONG_LV_CAST pBuffer)++ = ulDataSize; *( PULONG_LV_CAST pBuffer)++ = ulDataSize; if ( 0 == GetEnhMetaFileBits( *pHEnhMetafile, ulDataSize, (uchar*)pBuffer ) ) RpcRaiseException( HRESULT_FROM_WIN32(GetLastError())); pBuffer += ulDataSize; } else { // Sending a handle. *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong) *(HANDLE *)pHEnhMetafile; } return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: HENHMETAFILE_UserUnmarshall // // Synopsis: Unmarshalls an HENHMETAFILE object from the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HENHMETAFILE_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, HENHMETAFILE * pHEnhMetafile ) { HENHMETAFILE hEnhMetafile; UserNdrDebugOut((UNDR_OUT4, "HENHMETAFILE_UserUnmarshal\n")); ALIGN( pBuffer, 3 ); unsigned long UnionDisc = *( PULONG_LV_CAST pBuffer)++; hEnhMetafile = (HENHMETAFILE) *( PULONG_LV_CAST pBuffer)++; if ( IS_DATA_MARKER( UnionDisc) ) { if ( hEnhMetafile ) { // Byte blob : conformant size, size field, data ulong ulDataSize = *(ulong*)pBuffer; pBuffer += 8; hEnhMetafile = SetEnhMetaFileBits( ulDataSize, (uchar*) pBuffer ); pBuffer += ulDataSize; } } // No reusage of the old object. if (*pHEnhMetafile) DeleteEnhMetaFile( *pHEnhMetafile ); *pHEnhMetafile = hEnhMetafile; return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: HENHMETAFILE_UserFree // // Synopsis: Free an HENHMETAFILE. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- void __RPC_USER HENHMETAFILE_UserFree( unsigned long * pFlags, HENHMETAFILE * pHEnhMetafile ) { UserNdrDebugOut((UNDR_FORCE, "HENHMETAFILE_UserFree\n")); if( pHEnhMetafile && *pHEnhMetafile ) { if ( GDI_DATA_PASSING(*pFlags) ) { DeleteEnhMetaFile( *pHEnhMetafile ); } } } // ######################################################################### // // HBITMAP // See transmit.h for explanation of lax data/handle passing. // // ######################################################################### //+------------------------------------------------------------------------- // // Function: HBITMAP_UserSize // // Synopsis: Get the wire size the HBITMAP handle and data. // // Derivation: Union of a long and the bitmap handle and then struct. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned long __RPC_USER HBITMAP_UserSize ( unsigned long * pFlags, unsigned long Offset, HBITMAP * pHBitmap ) { if ( !pHBitmap ) return Offset; BITMAP bm; HBITMAP hBitmap = *pHBitmap; LENGTH_ALIGN( Offset, 3 ); // The encapsulated union. // Discriminant and then handle or pointer from the union arm. Offset += sizeof(long) + sizeof(void*); if ( ! *pHBitmap ) return Offset; if ( GDI_DATA_PASSING(*pFlags) ) { // Pointee of the union arm for the remote case. // Conformat size, 6 fields, size, conf array. Offset += 4 + 4 * sizeof(LONG) + 2 * sizeof(WORD) + 4; // Get information about the bitmap #if defined(_CHICAGO_) if (FALSE == GetObjectA(hBitmap, sizeof(BITMAP), &bm)) #else if (FALSE == GetObject(hBitmap, sizeof(BITMAP), &bm)) #endif { RpcRaiseException(HRESULT_FROM_WIN32(GetLastError())); } ULONG ulDataSize = bm.bmPlanes * bm.bmHeight * bm.bmWidthBytes; Offset += ulDataSize; } return( Offset ) ; } //+------------------------------------------------------------------------- // // Function: HBITMAP_UserMarshall // // Synopsis: Marshalls an HBITMAP object into the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HBITMAP_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, HBITMAP * pHBitmap ) { if ( !pHBitmap ) return pBuffer; UserNdrDebugOut((UNDR_OUT4, "HBITMAP_UserMarshal\n")); ALIGN( pBuffer, 3 ); // Discriminant of the encapsulated union and union arm. if ( GDI_DATA_PASSING(*pFlags) ) { // userHBITMAP *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong) *pHBitmap; if ( ! *pHBitmap ) return pBuffer; // Get information about the bitmap BITMAP bm; HBITMAP hBitmap = *pHBitmap; #if defined(_CHICAGO_) if (FALSE == GetObjectA(hBitmap, sizeof(BITMAP), &bm)) #else if (FALSE == GetObject(hBitmap, sizeof(BITMAP), &bm)) #endif { RpcRaiseException(HRESULT_FROM_WIN32(GetLastError())); } DWORD dwCount = bm.bmPlanes * bm.bmHeight * bm.bmWidthBytes; *( PULONG_LV_CAST pBuffer)++ = dwCount; // Get the bm structure fields. ulong ulBmSize = 4 * sizeof(LONG) + 2 * sizeof( WORD ); memcpy( pBuffer, (void *) &bm, ulBmSize ); pBuffer += ulBmSize; // Get the raw bits. if (0 == GetBitmapBits( hBitmap, dwCount, pBuffer ) ) { RpcRaiseException(HRESULT_FROM_WIN32(GetLastError())); } pBuffer += dwCount; } else { // Sending a handle. *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong) *(HANDLE *)pHBitmap; } return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: HBITMAP_UserUnmarshall // // Synopsis: Unmarshalls an HBITMAP object from the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HBITMAP_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, HBITMAP * pHBitmap ) { HBITMAP hBitmap; UserNdrDebugOut((UNDR_OUT4, "HBITMAP_UserUnmarshal\n")); ALIGN( pBuffer, 3 ); unsigned long UnionDisc = *( PULONG_LV_CAST pBuffer)++; hBitmap = (HBITMAP) *( PULONG_LV_CAST pBuffer)++; if ( IS_DATA_MARKER( UnionDisc) ) { if ( hBitmap ) { DWORD dwCount = *( PULONG_LV_CAST pBuffer)++; BITMAP * pBm = (BITMAP *) pBuffer; ulong ulBmSize = 4 * sizeof(LONG) + 2 * sizeof( WORD ); pBuffer += ulBmSize; // Create a bitmap based on the BITMAP structure and the raw bits in // the transmission buffer hBitmap = CreateBitmap( pBm->bmWidth, pBm->bmHeight, pBm->bmPlanes, pBm->bmBitsPixel, pBuffer ); pBuffer += dwCount; } } // A new bitmap handle is ready, destroy the old one, if needed. if ( *pHBitmap ) DeleteObject( *pHBitmap ); *pHBitmap = hBitmap; return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: HBITMAP_UserFree // // Synopsis: Free an HBITMAP. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- void __RPC_USER HBITMAP_UserFree( unsigned long * pFlags, HBITMAP * pHBitmap ) { UserNdrDebugOut((UNDR_OUT4, "HBITMAP_UserFree\n")); if( pHBitmap && *pHBitmap ) { if ( GDI_DATA_PASSING(*pFlags) ) { DeleteObject( *pHBitmap ); } } } // ######################################################################### // // HPALETTE // See transmit.h for explanation of lax data/handle passing. // // ######################################################################### //+------------------------------------------------------------------------- // // Function: HPALETTE_UserSize // // Synopsis: Get the wire size the HPALETTE handle and data. // // Derivation: Union of a long and the hpalette handle. // Then the struct represents hpalette. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned long __RPC_USER HPALETTE_UserSize ( unsigned long * pFlags, unsigned long Offset, HPALETTE * pHPalette ) { if ( !pHPalette ) return Offset; BITMAP bm; LENGTH_ALIGN( Offset, 3 ); // The encapsulated union. // Discriminant and then handle or pointer from the union arm. Offset += sizeof(long) + sizeof(void*); if ( ! *pHPalette ) return Offset; if ( GDI_DATA_PASSING(*pFlags) ) { // Conformat struct with version and size and conf array of entries. Offset += sizeof(long) + 2 * sizeof(short); // Determine the number of color entries in the palette DWORD cEntries = GetPaletteEntries(*pHPalette, 0, 0, NULL); Offset += cEntries * sizeof(PALETTEENTRY); } return( Offset ) ; } //+------------------------------------------------------------------------- // // Function: HPALETTE_UserMarshall // // Synopsis: Marshalls an HPALETTE object into the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HPALETTE_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, HPALETTE * pHPalette ) { if ( !pHPalette ) return pBuffer; UserNdrDebugOut((UNDR_OUT4, "HPALETTE_UserMarshal\n")); ALIGN( pBuffer, 3 ); // Discriminant of the encapsulated union and union arm. if ( GDI_DATA_PASSING(*pFlags) ) { // userHPALETTE *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong) *pHPalette; if ( ! *pHPalette ) return pBuffer; // rpcLOGPALETTE // Logpalette is a conformant struct with a version field, // size filed and conformant array of palentries. // Determine the number of color entries in the palette DWORD cEntries = GetPaletteEntries(*pHPalette, 0, 0, NULL); // Conformant size *( PULONG_LV_CAST pBuffer)++ = cEntries; // Fields: both are short! // The old code was just setting the version number. // They say it has to be that way. *( PUSHORT_LV_CAST pBuffer)++ = (ushort) 0x300; *( PUSHORT_LV_CAST pBuffer)++ = (ushort) cEntries; // Entries: each entry is a struct with 4 bytes. // Calculate the resultant data size DWORD cbData = cEntries * sizeof(PALETTEENTRY); if (cbData) { if (0 == GetPaletteEntries( *pHPalette, 0, cEntries, (PALETTEENTRY *)pBuffer ) ) { RpcRaiseException(HRESULT_FROM_WIN32(GetLastError())); } pBuffer += cbData; } } else { // Sending a handle. *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong) *(HANDLE *)pHPalette; } return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: HPALETTE_UserUnmarshall // // Synopsis: Unmarshalls an HPALETTE object from the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER HPALETTE_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, HPALETTE * pHPalette ) { HPALETTE hPalette; UserNdrDebugOut((UNDR_OUT4, "HPALETTE_UserUnmarshal\n")); ALIGN( pBuffer, 3 ); unsigned long UnionDisc = *( PULONG_LV_CAST pBuffer)++; hPalette = (HPALETTE) *( PULONG_LV_CAST pBuffer)++; if ( IS_DATA_MARKER( UnionDisc) ) { if ( hPalette ) { // Get the conformant size. DWORD cEntries = *( PULONG_LV_CAST pBuffer)++; LOGPALETTE * pLogPal; // If there are 0 color entries, we need to allocate the LOGPALETTE // structure with the one dummy entry (it's a variably sized struct). // Otherwise, we need to allocate enough space for the extra n-1 // entries at the tail of the structure if (0 == cEntries) { pLogPal = (LOGPALETTE *) WdtpAllocate( pFlags, sizeof(LOGPALETTE)); } else { pLogPal = (LOGPALETTE *) WdtpAllocate( pFlags, sizeof(LOGPALETTE) + (cEntries - 1) * sizeof(PALETTEENTRY)); } pLogPal->palVersion = *( PUSHORT_LV_CAST pBuffer)++; pLogPal->palNumEntries = *( PUSHORT_LV_CAST pBuffer)++; // If there are entries, move them into out LOGPALETTE structure if (cEntries) { memcpy( &(pLogPal->palPalEntry[0]), pBuffer, cEntries * sizeof(PALETTEENTRY) ); pBuffer += cEntries * sizeof(PALETTEENTRY); } // Attempt to create the palette hPalette = CreatePalette(pLogPal); // Success or failure, we're done with the LOGPALETTE structure WdtpFree( pFlags, pLogPal ); // If the creation failed, raise an exception if (NULL == hPalette) { RpcRaiseException(HRESULT_FROM_WIN32(GetLastError())); } } } // A new palette is ready, destroy the old one, if needed. if ( *pHPalette ) DeleteObject( *pHPalette ); *pHPalette = hPalette; return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: HPALETTE_UserFree // // Synopsis: Free an HPALETTE. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- void __RPC_USER HPALETTE_UserFree( unsigned long * pFlags, HPALETTE * pHPalette ) { UserNdrDebugOut((UNDR_OUT4, "HPALETTE_UserFree\n")); if( pHPalette && *pHPalette ) { if ( GDI_DATA_PASSING(*pFlags) ) { DeleteObject( *pHPalette ); } } } // ######################################################################### // // NON REMOTABLE GDI and other HANDLES // // ######################################################################### //+------------------------------------------------------------------------- // // Function: WdtpNonRemotableHandle_UserSize // // Synopsis: Get the wire size for a non remotable GDI handle. // // Derivation: Union of a long and nothing. // It is union just in case some remoting is needed. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned long __RPC_USER WdtpNonRemotableHandle_UserSize ( unsigned long * pFlags, unsigned long Offset, HANDLE * pHandle ) { if ( !pHandle || *pHandle == NULL ) return Offset; if ( HGLOBAL_DATA_PASSING(*pFlags) ) RpcRaiseException(E_INVALIDARG ); LENGTH_ALIGN( Offset, 3 ); // The encapsulated union. // No remote case on any platform. return( Offset + 8 ) ; } //+------------------------------------------------------------------------- // // Function: WdtpNonRemotableHandle_UserMarshal // // Synopsis: Marshalls a non-remotable handle into the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER WdtpNonRemotableHandle_UserMarshal ( unsigned long * pFlags, unsigned char * pBuffer, HANDLE * pHandle ) { if ( !pHandle || *pHandle == NULL ) return pBuffer; ALIGN( pBuffer, 3 ); // Discriminant of the encapsulated union and union arm. if ( HGLOBAL_DATA_PASSING(*pFlags) ) { RpcRaiseException(E_INVALIDARG ); } else { // Sending a handle. *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER; *( PULONG_LV_CAST pBuffer)++ = (ulong) *(HANDLE *)pHandle; } return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: WdtpNonRemotableHandle_UserUnmarshal // // Synopsis: Unmarshalls a non-remotable handle from the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER WdtpNonRemotableHandle_UserUnmarshal ( unsigned long * pFlags, unsigned char * pBuffer, HANDLE * pHandle ) { ALIGN( pBuffer, 3 ); unsigned long UnionDisc = *( PULONG_LV_CAST pBuffer)++; if ( IS_DATA_MARKER( UnionDisc) ) { RpcRaiseException(E_INVALIDARG ); } else { // Sending a handle. *pHandle = (HANDLE) *( PULONG_LV_CAST pBuffer)++; } return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: WdtpNonRemotableHandle_UserFree // // Synopsis: Nothing to free. // //-------------------------------------------------------------------------- void __RPC_USER WdtpNonRemotableGdiHandle_UserFree( unsigned long * pFlags, HANDLE * pHandle ) { } // ######################################################################### // // Interface pointers. // // ######################################################################### //+------------------------------------------------------------------------- // // Function: WdtpInterfacePointer_UserSize // // Synopsis: Get the wire size for an interface pointer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned long __RPC_USER WdtpInterfacePointer_UserSize ( USER_MARSHAL_CB * pContext, unsigned long Flags, unsigned long Offset, IUnknown * pIf, const IID & IId ) { if ( pIf ) { LENGTH_ALIGN( Offset, 3 ); //Leave space for array bounds and length Offset += 2 * sizeof(long); HRESULT hr; unsigned long cbSize = 0; hr = CoGetMarshalSizeMax( &cbSize, IId, pIf, USER_CALL_CTXT_MASK( Flags ), pContext->pStubMsg->pvDestContext, MSHLFLAGS_NORMAL ); if ( FAILED(hr) ) RpcRaiseException( hr ); Offset += cbSize; } return( Offset ) ; } //+------------------------------------------------------------------------- // // Function: WdtpInterfacePointer_UserMarshal // // Synopsis: Marshalls an interface pointer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER WdtpInterfacePointer_UserMarshal ( USER_MARSHAL_CB * pContext, unsigned long Flags, unsigned char * pBuffer, IUnknown * pIf, const IID & IId ) { unsigned long * pMaxCount, *pSize; unsigned long cbData = 0; UserNdrDebugOut((UNDR_OUT1, "WdtpInterface_PointerMarshal\n")); if ( pIf ) { // Always marshaled because of the apartment model. CStreamOnMessage MemStream( (unsigned char **) &pBuffer ); ALIGN( pBuffer, 3 ); pMaxCount = (unsigned long *) pBuffer; pBuffer += 4; // Leave space for length pSize = (unsigned long *) pBuffer; pBuffer += 4; HRESULT hr; unsigned char * pBufferMark = pBuffer; hr = CoMarshalInterface( &MemStream, IId, pIf, USER_CALL_CTXT_MASK( Flags ), pContext->pStubMsg->pvDestContext, MSHLFLAGS_NORMAL ); if( FAILED(hr) ) { RpcRaiseException(hr); } // Calculate the size of the data written DWORD cbData = pBuffer - pBufferMark; // Update the array bounds. *pMaxCount = cbData; *pSize = cbData; } return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: WdtpInterfacePointer_UserUnmarshal // // Synopsis: Unmarshalls an interface pointer from the RPC buffer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER WdtpInterfacePointer_UserUnmarshal ( USER_MARSHAL_CB * pContext, unsigned char * pBuffer, IUnknown ** ppIf, const IID & IId ) { unsigned long *pMaxCount, *pSize; unsigned long cbData = 0; UserNdrDebugOut((UNDR_OUT1, "WdtpInterfacePointerUnmarshal\n")); // Always unmarshaled because of the apartment model. CStreamOnMessage MemStream((unsigned char **) &pBuffer); ALIGN( pBuffer, 3 ); pMaxCount = (unsigned long *) pBuffer; pBuffer += sizeof(long); //Unmarshal count pSize = (unsigned long *) pBuffer; pBuffer += sizeof(long); // Release the old pointer after unmarshalling the new one // to prevent object from getting released too early. // Then release the old one only when successful. IUnknown * punkTemp = 0; HRESULT hr = CoUnmarshalInterface( &MemStream, IId, (void **) &punkTemp ); if(FAILED(hr)) RpcRaiseException(hr); else { // On the client side, release the [in,out] interface pointer. // The pointer may be different from NULL only on the client side. if ( (IId == IID_IStorage || IId == IID_IStream ) && *ppIf ) { // This may happen only on the client side. // Throw away a new one when coming back to the client !! // This is a pecularity of DocFile custom marshalling: // pointer identity is broken. if ( punkTemp ) punkTemp->Release(); // keep the old one } else { // release the old one, keep the new one. if ( *ppIf ) (*ppIf)->Release(); *ppIf = punkTemp; } } return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: WdtpInterfacePointer_UserFree // // Synopsis: Releases an interface pointer. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- void __RPC_USER WdtpInterfacePointer_UserFree( IUnknown * pIf ) { UserNdrDebugOut((UNDR_OUT1, "WdtpInterfacePointer_UserFree\n")); if( pIf ) { pIf->Release(); } } //+------------------------------------------------------------------------- // // Function: STGMEDIUM_UserSize // // Synopsis: Sizes a stgmedium pbject for RPC marshalling. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned long __RPC_USER STGMEDIUM_UserSize( unsigned long * pFlags, unsigned long Offset, STGMEDIUM * pStgmed ) { if ( ! pStgmed ) return Offset; LENGTH_ALIGN( Offset, 3 ); if ( pStgmed->tymed == TYMED_NULL ) Offset += sizeof(void*) + sizeof(long); // pointer, switch only else Offset += sizeof(void*) + sizeof(long) + sizeof(void*); // same + handle // Pointee of the union arm. // Only if the handle/pointer field is non-null. if ( pStgmed->hGlobal ) { switch( pStgmed->tymed ) { case TYMED_NULL: break; case TYMED_MFPICT: Offset = HMETAFILEPICT_UserSize( pFlags, Offset, &pStgmed->hMetaFilePict ); break; case TYMED_ENHMF: Offset = HENHMETAFILE_UserSize( pFlags, Offset, &pStgmed->hEnhMetaFile ); break; case TYMED_GDI: // A GDI object is not necesarrily a BITMAP. Therefore, we handle // those types we know about based on the object type, and reject // those which we do not support. // switch for object type. Offset += sizeof(long); switch( GetObjectType( (HGDIOBJ)pStgmed->hBitmap ) ) { case OBJ_BITMAP: Offset = HBITMAP_UserSize( pFlags, Offset, &pStgmed->hBitmap ); break; case OBJ_PAL: Offset = HPALETTE_UserSize( pFlags, Offset, (HPALETTE *) & pStgmed->hBitmap ); break; default: RpcRaiseException(DV_E_TYMED); break; } break; case TYMED_HGLOBAL: Offset = HGLOBAL_UserSize( pFlags, Offset, &pStgmed->hGlobal ); break; case TYMED_FILE: { ulong ulDataSize = wcslen(pStgmed->lpszFileName) + 1; Offset += 3 * sizeof(long); // [string] Offset += ulDataSize * sizeof(wchar_t); } break; case TYMED_ISTREAM: case TYMED_ISTORAGE: // Note, that we have to set the local flag for backward // compatibility. Offset = WdtpInterfacePointer_UserSize( (USER_MARSHAL_CB *)pFlags, MSHCTX_LOCAL, Offset, pStgmed->pstg, ((pStgmed->tymed == TYMED_ISTREAM) ? IID_IStream : IID_IStorage)); break; default: break; } } // pUnkForRelease, if not null. if ( pStgmed->pUnkForRelease ) Offset = WdtpInterfacePointer_UserSize( (USER_MARSHAL_CB *)pFlags, *pFlags, Offset, pStgmed->pUnkForRelease, IID_IUnknown ); return( Offset ); } //+------------------------------------------------------------------------- // // Function: STGMEDIUM_UserMarshal // // Synopsis: Marshals a stgmedium pbject for RPC. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER STGMEDIUM_UserMarshal( unsigned long * pFlags, unsigned char * pBufferStart, STGMEDIUM * pStgmed ) { unsigned char * pBuffer; unsigned char * pUnionArmMark; if ( ! pStgmed ) return pBufferStart; UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserMarshal: %s\n", WdtpGetStgmedName(pStgmed))); pBuffer = pBufferStart; ALIGN( pBuffer, 3 ); // userSTGMEDIUM: if pointer, switch, union arm, . *( PULONG_LV_CAST pBuffer)++ = (ulong)pStgmed->pUnkForRelease; *( PULONG_LV_CAST pBuffer)++ = pStgmed->tymed; pUnionArmMark = pBuffer; if ( pStgmed->tymed != TYMED_NULL ) { // hGlobal stands for any of these handles. *( PULONG_LV_CAST pBuffer)++ = (ulong)pStgmed->hGlobal; } // Now the pointee of the union arm. // We need to marshal only if the handle/pointer field is non null. // Otherwise it is already in the buffer. if ( pStgmed->hGlobal ) { switch( pStgmed->tymed ) { case TYMED_NULL: break; case TYMED_MFPICT: pBuffer = HMETAFILEPICT_UserMarshal( pFlags, pBuffer, &pStgmed->hMetaFilePict ); break; case TYMED_ENHMF: pBuffer = HENHMETAFILE_UserMarshal( pFlags, pBuffer, &pStgmed->hEnhMetaFile ); break; case TYMED_GDI: { // A GDI object is not necesarrily a BITMAP. Therefore, we handle // those types we know about based on the object type, and reject // those which we do not support. ulong GdiObjectType = GetObjectType( (HGDIOBJ)pStgmed->hBitmap ); // GDI_OBJECT *( PULONG_LV_CAST pBuffer)++ = GdiObjectType; switch( GdiObjectType ) { case OBJ_BITMAP: pBuffer = HBITMAP_UserMarshal( pFlags, pBuffer, &pStgmed->hBitmap ); break; case OBJ_PAL: pBuffer = HPALETTE_UserMarshal( pFlags, pBuffer, (HPALETTE *) & pStgmed->hBitmap ); break; default: RpcRaiseException(DV_E_TYMED); } } break; case TYMED_HGLOBAL: pBuffer = HGLOBAL_UserMarshal( pFlags, pBuffer, & pStgmed->hGlobal ); break; case TYMED_FILE: { // We marshal it as a [string]. ulong Count = (pStgmed->lpszFileName) ? wcslen(pStgmed->lpszFileName) + 1 : 0; *( PULONG_LV_CAST pBuffer)++ = Count; *( PULONG_LV_CAST pBuffer)++ = 0; *( PULONG_LV_CAST pBuffer)++ = Count; memcpy( pBuffer, pStgmed->lpszFileName, Count * sizeof(wchar_t) ); pBuffer += Count * sizeof(wchar_t); } break; case TYMED_ISTREAM: case TYMED_ISTORAGE: // Note, that we have to set the local flag for backward compatibility. pBuffer = WdtpInterfacePointer_UserMarshal( ((USER_MARSHAL_CB *)pFlags), MSHCTX_LOCAL, pBuffer, pStgmed->pstg, ((pStgmed->tymed == TYMED_ISTREAM) ? IID_IStream : IID_IStorage)); break; default: break; } } // Marker for this pointer is already in the buffer. if ( pStgmed->pUnkForRelease ) pBuffer = WdtpInterfacePointer_UserMarshal( ((USER_MARSHAL_CB *)pFlags), *pFlags, pBuffer, pStgmed->pUnkForRelease, IID_IUnknown ); return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: STGMEDIUM_UserUnmarshal // // Synopsis: Unmarshals a stgmedium object for RPC. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER STGMEDIUM_UserUnmarshal( unsigned long * pFlags, unsigned char * pBuffer, STGMEDIUM * pStgmed ) { unsigned long fUnkForRelease; unsigned long Handle = 0; // if pointer, switch, union arm. ALIGN( pBuffer, 3 ); // pUnkForRelease pointer marker. fUnkForRelease = *( PULONG_LV_CAST pBuffer)++; pStgmed->tymed = *( PULONG_LV_CAST pBuffer)++; UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserUnmarshal: %s\n", WdtpGetStgmedName(pStgmed) )); if ( pStgmed->tymed != TYMED_NULL ) { // handle or interface pointer (marker) from the buffer Handle = *( PULONG_LV_CAST pBuffer)++; } // First pointee // Union arm pointee. // We need to unmarshal only if the handle/pointer field was not NULL. if ( Handle ) { switch( pStgmed->tymed ) { case TYMED_NULL: break; case TYMED_MFPICT: pBuffer = HMETAFILEPICT_UserUnmarshal( pFlags, pBuffer, &pStgmed->hMetaFilePict ); break; case TYMED_ENHMF: pBuffer = HENHMETAFILE_UserUnmarshal( pFlags, pBuffer, &pStgmed->hEnhMetaFile ); break; case TYMED_GDI: { // A GDI object is not necesarrily a BITMAP. Therefore, we handle // those types we know about based on the object type, and reject // those which we do not support. DWORD GdiObjectType = *( PULONG_LV_CAST pBuffer)++; switch( GdiObjectType ) { case OBJ_BITMAP: pBuffer = HBITMAP_UserUnmarshal( pFlags, pBuffer, &pStgmed->hBitmap ); break; case OBJ_PAL: pBuffer = HPALETTE_UserUnmarshal( pFlags, pBuffer, (HPALETTE *) & pStgmed->hBitmap ); break; default: RpcRaiseException(DV_E_TYMED); } } break; case TYMED_HGLOBAL: // reallocation is forbidden for [in-out] hglobal in STGMEDIUM. pBuffer = WdtpGlobalUnmarshal( pFlags, pBuffer, & pStgmed->hGlobal, FALSE ); // realloc flag break; case TYMED_FILE: { // We marshal it as a [string]. ulong Count = *( PULONG_LV_CAST pBuffer)++; pBuffer += 8; if ( ! pStgmed->lpszFileName ) pStgmed->lpszFileName = (LPOLESTR) WdtpAllocate( pFlags, Count * sizeof(wchar_t) ); memcpy( pStgmed->lpszFileName, pBuffer, Count * sizeof(wchar_t) ); pBuffer += Count * sizeof(wchar_t); } break; case TYMED_ISTREAM: case TYMED_ISTORAGE: // Non null pointer, retrieve the interface pointer pBuffer = WdtpInterfacePointer_UserUnmarshal( (USER_MARSHAL_CB *)pFlags, pBuffer, (IUnknown **) &pStgmed->pstm, ((pStgmed->tymed == TYMED_ISTREAM) ? IID_IStream : IID_IStorage)); break; default: break; } } else { // New handle/pointer field is null, so release the previous one // if it wasn't null. if ( pStgmed->hGlobal ) { // This should never happen for GetDataHere. // Note, that we release the handle field, not the stgmedium itself. // Accordingly, we don't follow punkForRelease. UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserUnmarshal: %s: NULL in, freeing old one\n", WdtpGetStgmedName(pStgmed))); STGMEDIUM TmpStg = *pStgmed; TmpStg.pUnkForRelease = NULL; if ( pStgmed->tymed == TYMED_HGLOBAL ) { // Cannot reallocate. RpcRaiseException(DV_E_TYMED); } else { ReleaseStgMedium( &TmpStg ); } } pStgmed->hGlobal = 0; } if ( fUnkForRelease ) { // There is an interface pointer on the wire. pBuffer = WdtpInterfacePointer_UserUnmarshal( (USER_MARSHAL_CB *)pFlags, pBuffer, &pStgmed->pUnkForRelease, IID_IUnknown ); } if ( pStgmed->pUnkForRelease ) { // Replace the app's punkForRelease with our custom release // handler for special situations. // The special situation is when a handle is remoted with data // and so we have to clean up a side effect of having a data copy // around. UserFree does it properly but we need that for the callee. // When the callee releases a stgmed, it would invoke // ReleaseStgMedium and this API doesn't do anything for handles // when the punkForRelease is not NULL. ULONG fHandleWithData = 0; ULONG fTopLevelOnly = 0; switch ( pStgmed->tymed ) { case TYMED_HGLOBAL: fHandleWithData = HGLOBAL_DATA_PASSING( *pFlags ); break; case TYMED_ENHMF: case TYMED_GDI: fHandleWithData = GDI_DATA_PASSING( *pFlags ); break; case TYMED_MFPICT: fHandleWithData = HGLOBAL_DATA_PASSING( *pFlags ); fTopLevelOnly = fHandleWithData && ! GDI_DATA_PASSING( *pFlags ); break; default: break; } if ( fHandleWithData ) { IUnknown * punkTmp = (IUnknown *) new CPunkForRelease( pStgmed, fTopLevelOnly ); if (!punkTmp) { RpcRaiseException(E_OUTOFMEMORY); } pStgmed->pUnkForRelease = punkTmp; } } return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: STGMEDIUM_UserFree // // Synopsis: Frees a stgmedium object for RPC. // // history: May-95 Ryszardk Created. // // Note: This routine is called from the freeing walk at server // or from the SetData *proxy*, when ownership has been passed. // //-------------------------------------------------------------------------- EXTERN_C void NukeHandleAndReleasePunk( STGMEDIUM * pStgmed ) { pStgmed->hGlobal = NULL; pStgmed->tymed = TYMED_NULL; if (pStgmed->pUnkForRelease) { pStgmed->pUnkForRelease->Release(); pStgmed->pUnkForRelease = 0; } } void __RPC_USER STGMEDIUM_UserFree( unsigned long * pFlags, STGMEDIUM * pStgmed ) { UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserFree: %s\n", WdtpGetStgmedName(pStgmed))); if( pStgmed ) { switch ( pStgmed->tymed ) { case TYMED_FILE: WdtpFree( pFlags, pStgmed->lpszFileName); NukeHandleAndReleasePunk( pStgmed ); break; case TYMED_NULL: case TYMED_ISTREAM: case TYMED_ISTORAGE: ReleaseStgMedium( pStgmed ); break; case TYMED_GDI: case TYMED_ENHMF: if ( GDI_HANDLE_PASSING(*pFlags) ) { NukeHandleAndReleasePunk( pStgmed ); } else { // Handle w/data: there is a side effect to clean up. // For punk !=0, this will go to our CPunk object. ReleaseStgMedium( pStgmed ); } break; case TYMED_HGLOBAL: if ( HGLOBAL_HANDLE_PASSING(*pFlags) ) { NukeHandleAndReleasePunk( pStgmed ); } else { // Handle w/data: there is a side effect to clean up. // For punk ==0, this will just release the data. // For punk !=0, this will go to our CPunk object, // release the data, and then call the original punk. ReleaseStgMedium( pStgmed ); } break; case TYMED_MFPICT: if ( HGLOBAL_HANDLE_PASSING(*pFlags) ) { NukeHandleAndReleasePunk( pStgmed ); } else if ( GDI_HANDLE_PASSING(*pFlags) ) { if ( pStgmed->hGlobal ) GlobalFree( pStgmed->hGlobal ); NukeHandleAndReleasePunk( pStgmed ); } else { // Handle w/data: there is a side effect to clean up. // For punk !=0, this will go to our CPunk object. ReleaseStgMedium( pStgmed ); } break; default: RpcRaiseException( E_INVALIDARG ); break; } } } //+------------------------------------------------------------------------- // // Function: FLAG_STGMEDIUM_UserSize // // Synopsis: Sizes a wrapper for stgmedium. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned long __RPC_USER FLAG_STGMEDIUM_UserSize( unsigned long * pFlags, unsigned long Offset, FLAG_STGMEDIUM* pFlagStgmed ) { if ( ! pFlagStgmed ) return Offset; LENGTH_ALIGN( Offset, 3 ); Offset += sizeof(long); Offset = STGMEDIUM_UserSize( pFlags, Offset, & pFlagStgmed->Stgmed ); return( Offset ); } //+------------------------------------------------------------------------- // // Function: FLAG_STGMEDIUM_UserMarshal // // Synopsis: Marshals a wrapper for stgmedium. Used in SetData. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER FLAG_STGMEDIUM_UserMarshal( unsigned long * pFlags, unsigned char * pBuffer, FLAG_STGMEDIUM* pFlagStgmed ) { if ( ! pFlagStgmed ) return pBuffer; ALIGN( pBuffer, 3 ); // Flags: we need them when freeing in the client call_as routine pFlagStgmed->ContextFlags = *pFlags; *( PULONG_LV_CAST pBuffer)++ = *pFlags; *( PULONG_LV_CAST pBuffer)++ = pFlagStgmed->fPassOwnership; pBuffer = STGMEDIUM_UserMarshal( pFlags, pBuffer, & pFlagStgmed->Stgmed ); return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: FLAG_STGMEDIUM_UserUnmarshal // // Synopsis: Unmarshals a wrapper for stgmedium. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- unsigned char __RPC_FAR * __RPC_USER FLAG_STGMEDIUM_UserUnmarshal( unsigned long * pFlags, unsigned char * pBuffer, FLAG_STGMEDIUM* pFlagStgmed ) { ALIGN( pBuffer, 3 ); // Flags and buffer marker pFlagStgmed->ContextFlags = *( PULONG_LV_CAST pBuffer)++; // We need that in the Proxy, when we call the user free routine. pFlagStgmed->fPassOwnership = *( PULONG_LV_CAST pBuffer)++; pFlagStgmed->ContextFlags = *pFlags; // We always unmarshal a FLAG_STGMEDIUM object. // The engine will always free the FLAG_STGMEDIUM object later. // Adjustments for passing the ownership are done within SetData_Stub. pBuffer = STGMEDIUM_UserUnmarshal( pFlags, pBuffer, & pFlagStgmed->Stgmed ); return( pBuffer ); } //+------------------------------------------------------------------------- // // Function: FLAG_STGMEDIUM_UserFree // // Synopsis: Freess a wrapper for stgmedium. // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- void __RPC_USER FLAG_STGMEDIUM_UserFree( unsigned long * pFlags, FLAG_STGMEDIUM* pFlagsStgmed ) { if ( ! pFlagsStgmed->fPassOwnership ) STGMEDIUM_UserFree( pFlags, & pFlagsStgmed->Stgmed ); // else the callee is supposed to release the stg medium. } #if (DBG==1) //+------------------------------------------------------------------------- // // Function: WdtpGetStgmedName // // Synopsis: Debug support // // history: May-95 Ryszardk Created. // //-------------------------------------------------------------------------- char * WdtpGetStgmedName( STGMEDIUM * pStgmed) { char * Name; if ( pStgmed ) { switch (pStgmed->tymed) { case TYMED_NULL: Name = "TYMED_NULL"; break; case TYMED_MFPICT: Name = "TYMED_MFPICT"; break; case TYMED_ENHMF: Name = "TYMED_ENHMF"; break; case TYMED_GDI: Name = "TYMED_GDI"; break; case TYMED_HGLOBAL: Name = "TYMED_HGLOBAL"; break; case TYMED_FILE: Name = "TYMED_FILE"; break; case TYMED_ISTREAM: Name = "TYMED_ISTREAM"; break; case TYMED_ISTORAGE: Name = "TYMED_ISTORAGE"; break; default: Name = "TYMED invalid"; break; } return Name; } else return "STGMED * is null"; } #endif