// psiimpl2.h: IPersistStreamInitImpl2 // Copyright (c) 1998, Chris Sells // All rights reserved. // NO WARRANTIES EXTENDED. Use at your own risk. // // IPersistStreamInitImpl2 provides an implementation of GetSizeMax // using the ATL property map. This is useful when implementing // Marshal-by-Value. // // History: // 6/29/99: // -Forget to use var.punkVal on 2nd QI in VT_UNKNOWN/VT_DISPATCH case. // Thanks to dcarlino@columbus.rr.com for pointing this out. // // 10/31/98: // -Tested by Dharma Shukla (v-dharsh@microsoft.com). Thanks! // // 10/27/98: // -Initial release. // -Only tested on longs and BSTRs. #pragma once #ifndef PSIIMPL2_H #define PSIIMPL2_H template class ATL_NO_VTABLE IPersistStreamInitImpl2 : public IPersistStreamInitImpl { public: STDMETHOD(GetSizeMax)(ULARGE_INTEGER* pcbSize) { long cbSize = 0; HRESULT hr = S_OK; T* pT = static_cast(this); CComPtr pUnk = pT->GetUnknown(); ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap(); ATLASSERT(pMap != NULL); CComPtr pDispatch; const IID* piidOld = NULL; for (int i = 0; pMap[i].pclsidPropPage != NULL; i++) { if (pMap[i].szDesc == NULL) continue; // check if raw data entry if (pMap[i].dwSizeData != 0) { cbSize += pMap[i].dwSizeData; continue; } CComVariant var; if (pMap[i].piidDispatch != piidOld) { pDispatch.Release(); if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch))) { ATLTRACE2(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i); hr = E_FAIL; break; } piidOld = pMap[i].piidDispatch; } if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var))) { ATLTRACE2(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid); hr = E_FAIL; break; } int cbWrite = 0; switch (var.vt) { case VT_UNKNOWN: case VT_DISPATCH: { CComQIPtr spStream = var.punkVal; if( !spStream && var.punkVal ) var.punkVal->QueryInterface(IID_IPersistStreamInit, (void**)&spStream); if( spStream ) { cbSize += sizeof(CLSID); ULARGE_INTEGER uiSize = { 0 }; hr = spStream->GetSizeMax(&uiSize); if (FAILED(hr)) return hr; cbSize += uiSize.LowPart; } } case VT_UI1: case VT_I1: cbWrite = sizeof(BYTE); break; case VT_I2: case VT_UI2: case VT_BOOL: cbWrite = sizeof(short); break; case VT_I4: case VT_UI4: case VT_R4: case VT_INT: case VT_UINT: case VT_ERROR: cbWrite = sizeof(long); break; case VT_R8: case VT_CY: case VT_DATE: cbWrite = sizeof(double); break; default: break; } if (cbWrite != 0) { cbSize += cbWrite; continue; } CComBSTR bstrWrite; CComVariant varBSTR; if (var.vt != VT_BSTR) { hr = VariantChangeType(&varBSTR, &var, VARIANT_NOVALUEPROP, VT_BSTR); if (FAILED(hr)) return hr; bstrWrite = varBSTR.bstrVal; } else bstrWrite = var.bstrVal; cbSize += 4 + (static_cast(bstrWrite) ? SysStringByteLen(bstrWrite) : 0) + 2; } if( SUCCEEDED(hr) ) { pcbSize->HighPart = 0; pcbSize->LowPart = cbSize; } return hr; } }; #endif // PSIIMPL2_H