/*++ Microsoft Windows Copyright (c) 1997 - 1999 Microsoft Corporation. All rights reserved. File: udt.cxx Abstract: Marshalling support for user defined data types. Author: ShannonC 21-Apr-1997 Environment: Windows NT and Windows 95. We do not support DOS and Win16. Revision History: --*/ #include #include #include #include extern USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[3]; class CTypeFactory : public ITypeFactory, public IClassFactory { public: HRESULT STDMETHODCALLTYPE QueryInterface( IN REFIID riid, OUT void **ppv); ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); HRESULT STDMETHODCALLTYPE CreateFromTypeInfo( IN ITypeInfo *pTypeInfo, IN REFIID riid, OUT IUnknown **ppv); HRESULT STDMETHODCALLTYPE CreateInstance( IN IUnknown * pUnkOuter, IN REFIID riid, OUT void ** ppv); HRESULT STDMETHODCALLTYPE LockServer( IN BOOL fLock); CTypeFactory(); private: long _cRefs; }; CLSID CLSID_TypeFactory = { /* b5866878-bd99-11d0-b04b-00c04fd91550 */ 0xb5866878, 0xbd99, 0x11d0, {0xb0, 0x4b, 0x00, 0xc0, 0x4f, 0xd9, 0x15, 0x50} }; class CTypeMarshal : public ITypeMarshal, public IMarshal { public: // IUnknown methods HRESULT STDMETHODCALLTYPE QueryInterface( IN REFIID riid, OUT void **ppvObject); ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); // ITypeMarshal methods HRESULT STDMETHODCALLTYPE Size( IN void * pType, IN DWORD dwDestContext, IN void * pvDestContext, OUT ULONG * pSize); HRESULT STDMETHODCALLTYPE Marshal( IN void * pType, IN DWORD dwDestContext, IN void * pvDestContext, IN ULONG cbBufferLength, OUT BYTE * pBuffer, OUT ULONG * pcbWritten); HRESULT STDMETHODCALLTYPE Unmarshal( IN void * pType, IN DWORD dwFlags, IN ULONG cbBufferLength, IN BYTE * pBuffer, OUT ULONG * pcbRead); HRESULT STDMETHODCALLTYPE Free( IN void * pType); // IMarshal methods. HRESULT STDMETHODCALLTYPE GetUnmarshalClass ( IN REFIID riid, IN void *pv, IN DWORD dwDestContext, IN void *pvDestContext, IN DWORD mshlflags, OUT CLSID *pCid ); HRESULT STDMETHODCALLTYPE GetMarshalSizeMax ( IN REFIID riid, IN void *pv, IN DWORD dwDestContext, IN void *pvDestContext, IN DWORD mshlflags, OUT DWORD *pSize ); HRESULT STDMETHODCALLTYPE MarshalInterface ( IN IStream *pStm, IN REFIID riid, IN void *pv, IN DWORD dwDestContext, IN void *pvDestContext, IN DWORD mshlflags ); HRESULT STDMETHODCALLTYPE UnmarshalInterface ( IN IStream *pStm, IN REFIID riid, OUT void **ppv ); HRESULT STDMETHODCALLTYPE ReleaseMarshalData ( IN IStream *pStm ); HRESULT STDMETHODCALLTYPE DisconnectObject ( IN DWORD dwReserved ); CTypeMarshal( IN PFORMAT_STRING pFormatString, IN ULONG length, IN ULONG offset); private: ~CTypeMarshal(); long _cRefs; ULONG _offset; ULONG _length; PFORMAT_STRING _pFormatString; MIDL_STUB_DESC _StubDesc; }; //+--------------------------------------------------------------------------- // // Function: DllGetClassObject // // Synopsis: Gets an interface pointer to the specified class object. // // Arguments: rclsid - CLSID for the class object. // riid - IID for the requested interface // [ppv] - Returns the interface pointer to the class object. // // Returns: S_OK // CLASS_E_CLASSNOTAVAILABLE // E_INVALIDARG // E_NOINTERFACE // E_OUTOFMEMORY // //---------------------------------------------------------------------------- STDAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, void ** ppv) { HRESULT hr; RPC_STATUS rc; __try { *ppv = NULL; //Initialize the RPC heap. rc = NdrpPerformRpcInitialization(); if (rc == RPC_S_OK) { if(rclsid == CLSID_TypeFactory) { CTypeFactory * pTypeFactory; pTypeFactory = new CTypeFactory; if(pTypeFactory != NULL) { hr = pTypeFactory->QueryInterface(riid, ppv); pTypeFactory->Release(); } else { hr = E_OUTOFMEMORY; } } else { hr = CLASS_E_CLASSNOTAVAILABLE; } } else hr = HRESULT_FROM_WIN32(rc); } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_INVALIDARG; } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeFactory::CTypeFactory // // Synopsis: Constructor for CTypeFactory // //---------------------------------------------------------------------------- CTypeFactory::CTypeFactory() : _cRefs(1) { } //+--------------------------------------------------------------------------- // // Method: CTypeFactory::QueryInterface // // Synopsis: Gets a pointer to the specified interface. // // Arguments: riid - IID of the requested interface. // ppv - Returns the interface pointer. // // Returns: S_OK // E_INVALIDARG // E_NOINTERFACE // //---------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CTypeFactory::QueryInterface( REFIID riid, void **ppv) { HRESULT hr; __try { *ppv = NULL; if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITypeFactory)) { AddRef(); *ppv = (ITypeFactory *) this; hr = S_OK; } else if(IsEqualIID(riid, IID_IClassFactory)) { AddRef(); *ppv = (IClassFactory *) this; hr = S_OK; } else { hr = E_NOINTERFACE; } } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_INVALIDARG; } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeFactory::AddRef // // Synopsis: Increment the reference count. // // Arguments: void // // Returns: ULONG -- the new reference count // // Notes: Use InterlockedIncrement to make it multi-thread safe. // //---------------------------------------------------------------------------- ULONG STDMETHODCALLTYPE CTypeFactory::AddRef(void) { InterlockedIncrement(&_cRefs); return _cRefs; } //+--------------------------------------------------------------------------- // // Method: CTypeFactory::Release // // Synopsis: Decrement the reference count. // // Arguments: void // // Returns: ULONG -- the remaining reference count // // Notes: Use InterlockedDecrement to make it multi-thread safe. // We use a local variable so that we don't access // a data member after decrementing the reference count. // //---------------------------------------------------------------------------- ULONG STDMETHODCALLTYPE CTypeFactory::Release(void) { ULONG count = _cRefs - 1; if(0 == InterlockedDecrement(&_cRefs)) { delete this; count = 0; } return count; } //+------------------------------------------------------------------------- // // Member: CTypeFactory::LockServer // // Synopsis: Lock the server. Does nothing. // // Arguments: fLock // // Returns: S_OK // //-------------------------------------------------------------------------- STDMETHODIMP CTypeFactory::LockServer(BOOL fLock) { return S_OK; } //+------------------------------------------------------------------------- // // Member: CTypeFactory::CreateInstance // // Synopsis: Creates a CTypeMarshal. // // Arguments: [pUnkOuter] - The controlling unknown (for aggregation) // [iid] - The requested interface ID. // [ppv] - Returns the pointer to the new object // // Returns: S_OK // CLASS_E_NOAGGREGATION // E_NOINTERFACE // E_OUTOFMEMORY // E_INVALIDARG // //-------------------------------------------------------------------------- STDMETHODIMP CTypeFactory::CreateInstance( IUnknown * pUnkOuter, REFIID riid, void ** ppv) { HRESULT hr; IID iid; __try { //Parameter validation. *ppv = NULL; iid = riid; if(NULL == pUnkOuter) { CTypeMarshal *pTypeMarshal = new CTypeMarshal(NULL, 0, 0); if(pTypeMarshal != NULL) { hr = pTypeMarshal->QueryInterface(iid, ppv); pTypeMarshal->Release(); } else { hr = E_OUTOFMEMORY; } } else { //CTypeMarshal does not support aggregation. hr = CLASS_E_NOAGGREGATION; } } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_INVALIDARG; } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeFactory::CreateFromTypeInfo // // Synopsis: Create a type marshaller from the typeinfo. // // Arguments: void // // Returns: S_OK // DISP_E_BADVARTYPE // E_INVALIDARG // E_NOINTERFACE // E_OUTOFMEMORY // //---------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CTypeFactory::CreateFromTypeInfo( IN ITypeInfo * pTypeInfo, IN REFIID riid, OUT IUnknown ** ppv) { HRESULT hr; CTypeMarshal * pTypeMarshal; PFORMAT_STRING pFormatString; USHORT length; USHORT offset; PARAMINFO paramInfo; CTypeGen *ptypeGen = new CTypeGen; DWORD structInfo = 0; if (NULL == ptypeGen) return E_OUTOFMEMORY; __try { *ppv = NULL; //Build a type format string from the typeinfo. paramInfo.vt = VT_USERDEFINED; paramInfo.pTypeInfo = pTypeInfo; pTypeInfo->AddRef(); hr = ptypeGen->RegisterType(¶mInfo, &offset, &structInfo); if (SUCCEEDED(hr) && (0 == offset)) { ASSERT( !(paramInfo.vt & VT_BYREF)); switch (paramInfo.vt) { case VT_I1: case VT_UI1: offset = 734; break; case VT_I2: case VT_UI2: case VT_BOOL: offset = 738; break; case VT_I4: case VT_UI4: case VT_INT: case VT_UINT: case VT_ERROR: case VT_HRESULT: offset = 742; break; case VT_I8: case VT_UI8: case VT_CY: offset = 310; break; case VT_R4: offset = 746; break; case VT_R8: case VT_DATE: offset = 750; break; } } if(SUCCEEDED(hr)) { hr = ptypeGen->GetTypeFormatString(&pFormatString, &length); if(SUCCEEDED(hr)) { pTypeMarshal = new CTypeMarshal(pFormatString, length, offset); if(pTypeMarshal != NULL) { hr = pTypeMarshal->QueryInterface(riid, (void **) ppv); pTypeMarshal->Release(); } else { hr = E_OUTOFMEMORY; ReleaseTypeFormatString(pFormatString); } } } delete ptypeGen; // fix compile warning } __except(EXCEPTION_EXECUTE_HANDLER) { delete ptypeGen; // fix compile warning hr = E_INVALIDARG; } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::CTypeMarshal // // Synopsis: Constructor for CTypeMarshal // //---------------------------------------------------------------------------- CTypeMarshal::CTypeMarshal( IN PFORMAT_STRING pFormatString, IN ULONG length, IN ULONG offset) : _pFormatString(pFormatString), _length(length), _offset(offset), _cRefs(1) { //Initialize the MIDL_STUB_DESC. MIDL_memset(&_StubDesc, 0, sizeof(_StubDesc)); _StubDesc.pfnAllocate = NdrOleAllocate; _StubDesc.pfnFree = NdrOleFree; _StubDesc.pFormatTypes = pFormatString; #if !defined(__RPC_WIN64__) _StubDesc.Version = 0x20000; /* Ndr library version */ _StubDesc.MIDLVersion = MIDL_VERSION_3_0_44; #else _StubDesc.Version = 0x50002; /* Ndr library version */ _StubDesc.MIDLVersion = MIDL_VERSION_5_2_202; #endif _StubDesc.aUserMarshalQuadruple = UserMarshalRoutines; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::~CTypeMarshal // // Synopsis: Destructor for CTypeMarshal // //---------------------------------------------------------------------------- CTypeMarshal::~CTypeMarshal() { ReleaseTypeFormatString(_pFormatString); } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::QueryInterface // // Synopsis: Gets a pointer to the specified interface. // // Arguments: riid - IID of the requested interface. // ppv - Returns the interface pointer. // // Returns: S_OK // E_INVALIDARG // E_NOINTERFACE // //---------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CTypeMarshal::QueryInterface( REFIID riid, void **ppv) { HRESULT hr; __try { *ppv = NULL; if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITypeMarshal)) { AddRef(); *ppv = (ITypeMarshal *) this; hr = S_OK; } else if (IsEqualIID(riid, IID_IMarshal)) { AddRef(); *ppv = (IMarshal *) this; hr = S_OK; } else { hr = E_NOINTERFACE; } } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_INVALIDARG; } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::AddRef // // Synopsis: Increment the reference count. // // Arguments: void // // Returns: ULONG -- the new reference count // // Notes: Use InterlockedIncrement to make it multi-thread safe. // //---------------------------------------------------------------------------- ULONG STDMETHODCALLTYPE CTypeMarshal::AddRef(void) { InterlockedIncrement(&_cRefs); return _cRefs; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::Release // // Synopsis: Decrement the reference count. // // Arguments: void // // Returns: ULONG -- the remaining reference count // // Notes: Use InterlockedDecrement to make it multi-thread safe. // We use a local variable so that we don't access // a data member after decrementing the reference count. // //---------------------------------------------------------------------------- ULONG STDMETHODCALLTYPE CTypeMarshal::Release(void) { ULONG count = _cRefs - 1; if(0 == InterlockedDecrement(&_cRefs)) { delete this; count = 0; } return count; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::Size // // Synopsis: Computes the size of the marshalled data type. // // Returns: S_OK // E_INVALIDARG // //---------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CTypeMarshal::Size( IN void * pType, IN DWORD dwDestContext, IN void * pvDestContext, OUT ULONG * pSize) { HRESULT hr = S_OK; MIDL_STUB_MESSAGE StubMsg; PFORMAT_STRING pTypeFormat; __try { if(!_pFormatString) return E_UNEXPECTED; pTypeFormat = _pFormatString + _offset; MIDL_memset(&StubMsg, 0, sizeof(StubMsg)); StubMsg.StubDesc = &_StubDesc; StubMsg.pfnFree = NdrOleFree; StubMsg.pfnAllocate = NdrOleAllocate; StubMsg.IsClient = 1; StubMsg.BufferLength = 1; //Reserve space for an alignment gap. StubMsg.dwDestContext = dwDestContext; StubMsg.pvDestContext = pvDestContext; (*pfnSizeRoutines[ROUTINE_INDEX(*pTypeFormat)])( &StubMsg, (unsigned char *)pType, pTypeFormat); *pSize = StubMsg.BufferLength - 1; } __except(EXCEPTION_EXECUTE_HANDLER) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::Marshal // // Synopsis: Marshals the user-defined type into a buffer. // // Returns: S_OK // E_INVALIDARG // //---------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CTypeMarshal::Marshal( IN void * pType, IN DWORD dwDestContext, IN void * pvDestContext, IN ULONG cbBufferLength, OUT BYTE * pBuffer, OUT ULONG * pcbWritten) { HRESULT hr = S_OK; MIDL_STUB_MESSAGE StubMsg; RPC_MESSAGE RpcMsg; PFORMAT_STRING pTypeFormat; __try { if(!_pFormatString) return E_UNEXPECTED; pTypeFormat = _pFormatString + _offset; MIDL_memset(&StubMsg, 0, sizeof(StubMsg)); StubMsg.StubDesc = &_StubDesc; StubMsg.pfnFree = NdrOleFree; StubMsg.pfnAllocate = NdrOleAllocate; StubMsg.IsClient = 1; StubMsg.dwDestContext = dwDestContext; StubMsg.pvDestContext = pvDestContext; StubMsg.Buffer = pBuffer; MIDL_memset(&RpcMsg, 0, sizeof(RpcMsg)); RpcMsg.DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; RpcMsg.Buffer = pBuffer; RpcMsg.BufferLength = cbBufferLength; StubMsg.RpcMsg = &RpcMsg; (*pfnMarshallRoutines[ROUTINE_INDEX(*pTypeFormat)])( &StubMsg, (unsigned char *)pType, pTypeFormat); *pcbWritten = (ULONG)(StubMsg.Buffer - pBuffer); } __except(EXCEPTION_EXECUTE_HANDLER) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::Unmarshal // // Synopsis: Unmarshals a user-defined type from a buffer. // // Returns: S_OK // E_INVALIDARG // //---------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CTypeMarshal::Unmarshal( OUT void * pType, IN DWORD dwFlags, IN ULONG cbBufferLength, IN BYTE * pBuffer, OUT ULONG * pcbRead) { HRESULT hr = S_OK; MIDL_STUB_MESSAGE StubMsg; RPC_MESSAGE RpcMsg; PFORMAT_STRING pTypeFormat; __try { if(pcbRead) *pcbRead = 0; if(!_pFormatString) return E_UNEXPECTED; pTypeFormat = _pFormatString + _offset; // HACK! OA might pass in 0xffffffff, which // will break the attack checking in ndr engine. // what we do now is mask off the highest byte. // This will lead to a 64M limit buffer, but that // should be good enough for now. cbBufferLength &= 0xffffff; MIDL_memset(&StubMsg, 0, sizeof(StubMsg)); StubMsg.StubDesc = &_StubDesc; StubMsg.pfnFree = NdrOleFree; StubMsg.pfnAllocate = NdrOleAllocate; StubMsg.IsClient = 1; StubMsg.dwDestContext = dwFlags & 0x0000FFFF; StubMsg.Buffer = pBuffer; StubMsg.BufferStart = pBuffer; StubMsg.BufferLength = cbBufferLength; StubMsg.BufferEnd = pBuffer + cbBufferLength; MIDL_memset(&RpcMsg, 0, sizeof(RpcMsg)); RpcMsg.DataRepresentation = dwFlags >> 16; RpcMsg.Buffer = pBuffer; RpcMsg.BufferLength = cbBufferLength; StubMsg.RpcMsg = &RpcMsg; NdrClientZeroOut(&StubMsg, pTypeFormat, (uchar *) pType); //Endianness if(RpcMsg.DataRepresentation != NDR_LOCAL_DATA_REPRESENTATION) { (*pfnConvertRoutines[ROUTINE_INDEX(*pTypeFormat)])(&StubMsg, pTypeFormat, FALSE); StubMsg.Buffer = pBuffer; } //Unmarshal (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pTypeFormat)])( &StubMsg, (unsigned char **)&pType, pTypeFormat, FALSE); if(pcbRead) *pcbRead = (ULONG)(StubMsg.Buffer - pBuffer); } __except(EXCEPTION_EXECUTE_HANDLER) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::Free // // Synopsis: Frees a user-defined type. // // Returns: S_OK // E_INVALIDARG // //---------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CTypeMarshal::Free( void * pType) { HRESULT hr = S_OK; MIDL_STUB_MESSAGE StubMsg; PFORMAT_STRING pTypeFormat; __try { if(pType != NULL) { if(!_pFormatString) return E_UNEXPECTED; pTypeFormat = _pFormatString + _offset; MIDL_memset(&StubMsg, 0, sizeof(StubMsg)); StubMsg.StubDesc = &_StubDesc; StubMsg.pfnFree = NdrOleFree; StubMsg.pfnAllocate = NdrOleAllocate; StubMsg.IsClient = 1; (*pfnFreeRoutines[ROUTINE_INDEX(*pTypeFormat)])( &StubMsg, (unsigned char *)pType, pTypeFormat); } } __except(EXCEPTION_EXECUTE_HANDLER) { hr = HRESULT_FROM_WIN32(GetExceptionCode()); } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::GetUnmarshalClass // // Synopsis: Get the class ID. // //---------------------------------------------------------------------------- STDMETHODIMP CTypeMarshal::GetUnmarshalClass( REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, CLSID * pClassID) { HRESULT hr = S_OK; __try { *pClassID = CLSID_TypeFactory; } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_INVALIDARG; } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::GetMarshalSizeMax // // Synopsis: Get maximum size of marshalled moniker. // //---------------------------------------------------------------------------- STDMETHODIMP CTypeMarshal::GetMarshalSizeMax( REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, DWORD *pSize) { HRESULT hr; __try { *pSize = sizeof(_offset) + sizeof(_length) + _length; hr = S_OK; } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_INVALIDARG; } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::MarshalInterface // // Synopsis: Marshal moniker into a stream. // //---------------------------------------------------------------------------- STDMETHODIMP CTypeMarshal::MarshalInterface( IStream * pStream, REFIID riid, void * pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags) { HRESULT hr; ULONG cb; hr = pStream->Write(&_offset, sizeof(_offset), &cb); if(SUCCEEDED(hr)) { hr = pStream->Write(&_length, sizeof(_length), &cb); if(SUCCEEDED(hr)) { hr = pStream->Write(_pFormatString, _length, &cb); } } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::UnmarshalInterface // // Synopsis: Unmarshal moniker from a stream. // //---------------------------------------------------------------------------- STDMETHODIMP CTypeMarshal::UnmarshalInterface( IStream * pStream, REFIID riid, void ** ppv) { HRESULT hr; ULONG cb; __try { //Validate parameters. *ppv = NULL; hr = pStream->Read(&_offset, sizeof(_offset), &cb); if(SUCCEEDED(hr) && (sizeof(_offset) == cb)) { hr = pStream->Read(&_length, sizeof(_length), &cb); if(SUCCEEDED(hr) && (sizeof(_length) == cb)) { _pFormatString = (PFORMAT_STRING) I_RpcAllocate(_length); if(_pFormatString != NULL) { hr = pStream->Read((void *) _pFormatString, _length, &_length); if(SUCCEEDED(hr)) { hr = QueryInterface(riid, ppv); } } else { hr = E_OUTOFMEMORY; } } } } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_INVALIDARG; } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::ReleaseMarshalData // // Synopsis: Release a marshalled class moniker. // Just seek to the end of the marshalled class moniker. // //---------------------------------------------------------------------------- STDMETHODIMP CTypeMarshal::ReleaseMarshalData( IStream * pStream) { HRESULT hr; ULONG cb; hr = pStream->Read(&_offset, sizeof(_offset), &cb); if(SUCCEEDED(hr) && (sizeof(_offset) == cb)) { hr = pStream->Read(&_length, sizeof(_length), &cb); if(SUCCEEDED(hr) && (sizeof(_length) == cb)) { LARGE_INTEGER liSize; liSize.LowPart = _length; liSize.HighPart = 0; hr = pStream->Seek(liSize, STREAM_SEEK_CUR, NULL); } } return hr; } //+--------------------------------------------------------------------------- // // Method: CTypeMarshal::DisconnectObject // // Synopsis: Disconnect the object. // //---------------------------------------------------------------------------- STDMETHODIMP CTypeMarshal::DisconnectObject( DWORD dwReserved) { return S_OK; }