// Util.cpp #include "stdafx.h" #include "util.h" #if LoadSaveHelpers BOOL IsPersistable(IUnknown *punk) // returns TRUE if object supports one of the supported peristence interfaces { CComQIPtr ppersiststream(punk); if (ppersiststream == NULL) { CComQIPtr ppersiststorage(punk); if (ppersiststorage == NULL) { CComQIPtr ppersistpropbag(punk); if (ppersistpropbag == NULL) return false; } } return true; } HRESULT SaveToStream(IUnknown *punk, IStorage *pstore, TCHAR *szPrefix, int n) { HRESULT hr; CComQIPtr ppersiststream(punk); if (ppersiststream == NULL) return E_INVALIDARG; CComPtr pstream; const TCHAR szFormat[] = _T("%s Stream %d"); TCHAR szName[100 + sizeof(szFormat)/sizeof(TCHAR) + 10]; if (wcslen(szPrefix) > 100) return E_INVALIDARG; wsprintf(szName, szFormat, szPrefix, n); CComBSTR bstrName(szName); hr = pstore->CreateStream(bstrName, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0,&pstream); if (SUCCEEDED(hr)) { hr = OleSaveToStream(ppersiststream, pstream); } return hr; } HRESULT LoadFromStream(IStorage *pstore, TCHAR *szPrefix, int n, IUnknown **ppunk) { HRESULT hr; CComPtr pstream; const TCHAR szFormat[] = _T("%s Stream %d"); TCHAR szName[100 + sizeof(szFormat)/sizeof(TCHAR) + 10]; if (wcslen(szPrefix) > 100) return E_INVALIDARG; wsprintf(szName, szFormat, szPrefix, n); CComBSTR bstrName(szName); hr = pstore->OpenStream(bstrName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pstream); if (FAILED(hr)) return S_FALSE; hr = OleLoadFromStream(pstream, IID_IUnknown, (void **)ppunk); return hr; } HRESULT SaveToStorage(IUnknown *punk, IStorage *pstore, TCHAR *szPrefix, int n) { HRESULT hr; CComQIPtr ppersiststore(punk); if (ppersiststore == NULL) return E_INVALIDARG; CComPtr pstore2; const TCHAR szFormat[] = _T("%s Store %d"); TCHAR szName[100 + sizeof(szFormat)/sizeof(TCHAR) + 10]; if (wcslen(szPrefix) > 100) return E_INVALIDARG; wsprintf(szName, szFormat, szPrefix, n); CComBSTR bstrName(szName); hr = pstore->CreateStorage(bstrName, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pstore2); if (SUCCEEDED(hr)) { hr = OleSave(ppersiststore, pstore2, FALSE); } return hr; } HRESULT LoadFromStorage(IStorage *pstore, TCHAR *szPrefix, int n, IUnknown **ppunk) { HRESULT hr; CComPtr pstore2; const TCHAR szFormat[] = _T("%s Store %d"); TCHAR szName[100 + sizeof(szFormat)/sizeof(TCHAR) + 10]; if (wcslen(szPrefix) > 100) return E_INVALIDARG; wsprintf(szName, szFormat, szPrefix, n); CComBSTR bstrName(szName); hr = pstore->OpenStorage(bstrName, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &pstore2); if (FAILED(hr)) return S_FALSE; hr = OleLoad(pstore2, IID_IUnknown, NULL, (void **) ppunk); CComQIPtr ppersist(*ppunk); CLSID clsid; hr = ppersist->GetClassID(&clsid); return hr; } #endif #if PropBagInStream HRESULT SaveToPropBagInStream(IPersistPropertyBag *ppersistpropbag, IStream *pstream) { HRESULT hr; if (ppersistpropbag == NULL) return E_INVALIDARG; CLSID clsid; hr = ppersistpropbag->GetClassID(&clsid); if (FAILED(hr)) return hr; hr = WriteClassStm(pstream, clsid); if (FAILED(hr)) return hr; CComPtr ppropbag = NewComObject(PropertyBag); if (ppropbag == NULL) hr = E_OUTOFMEMORY; hr = ppersistpropbag->Save(ppropbag, TRUE, TRUE); if (SUCCEEDED(hr)) hr = ppropbag->WriteToStream(pstream); return hr; } HRESULT LoadFromPropBagInStream(IStream *pstream, IUnknown **ppunk) { HRESULT hr; CComPtr ppropbag; CLSID clsid; ReadClassStm(pstream, &clsid); CComPtr punk; hr = punk.CoCreateInstance(clsid); if (FAILED(hr)) return hr; CComQIPtr ppersistpropbag(punk); if (ppersistpropbag == NULL) return STG_E_DOCFILECORRUPT; ppropbag = NewComObject(PropertyBag); if (ppropbag == NULL) return E_OUTOFMEMORY; ppropbag->ReadFromStream(pstream); ppersistpropbag->Load(ppropbag, NULL); *ppunk = punk.Detach(); return hr; } PropertyBag::~PropertyBag() { for (t_map::iterator iter = m_mapProps.begin(); iter != m_mapProps.end(); iter++) { BSTR bstrName = (*iter).first; if (bstrName != NULL) SysFreeString(bstrName); ::VariantClear(&(*iter).second); } } HRESULT PropertyBag::ReadFromStream(IStream *pstream) { HRESULT hr; long lCount; ULONG cb = sizeof(lCount); hr = pstream->Read(&lCount, cb, &cb); if (FAILED(hr)) return STG_E_DOCFILECORRUPT; for (long i=0; i < lCount; i++) { CComBSTR bstrName; bstrName.ReadFromStream(pstream); CComVariant varVal; char ch; cb = sizeof(ch); hr = pstream->Read(&ch, cb, &cb); if (FAILED(hr)) return STG_E_DOCFILECORRUPT; switch (ch) { case t_NULL: varVal = (IUnknown *) NULL; break; case t_Blob: { CComBSTR bstr; bstr.ReadFromStream(pstream); varVal = bstr; varVal.vt = VT_BSTR_BLOB; } break; case t_Variant: varVal.ReadFromStream(pstream); break; case t_PropertyBag: { varVal.vt = VT_UNKNOWN; hr = LoadFromPropBagInStream(pstream, &varVal.punkVal); } break; default: return STG_E_DOCFILECORRUPT; } VARIANT &var = m_mapProps[bstrName.Detach()]; ::VariantInit(&var); varVal.Detach(&var); } return S_OK; } HRESULT PropertyBag::WriteToStream(IStream *pstream) { HRESULT hr; long lCount = (long) m_mapProps.size(); ULONG cb = sizeof(lCount); pstream->Write(&lCount, cb, &cb); for (t_map::iterator iter = m_mapProps.begin(); iter != m_mapProps.end(); iter++) { CComBSTR bstrName((*iter).first); bstrName.WriteToStream(pstream); VARIANT & var = (*iter).second; switch (var.vt) { case VT_BSTR_BLOB: { char ch = t_Blob; cb = sizeof(ch); hr = pstream->Write(&ch, cb, &cb); CComBSTR bstr; bstr.Attach(var.bstrVal); bstr.WriteToStream(pstream); bstr.Detach(); } break; case VT_UNKNOWN: case VT_DISPATCH: { if (var.punkVal == NULL) { DoNull: char ch = t_NULL; cb = sizeof(ch); hr = pstream->Write(&ch, cb, &cb); break; } CComQIPtr ppersiststream(var.punkVal); if (ppersiststream != NULL) goto defaultCase; CComQIPtr ppersistpropbag(var.punkVal); if (ppersistpropbag == NULL) goto DoNull; char ch = t_PropertyBag; cb = sizeof(ch); hr = pstream->Write(&ch, cb, &cb); hr = SaveToPropBagInStream(ppersistpropbag, pstream); if (FAILED(hr)) return hr; } break; defaultCase: default: { char ch = t_Variant; cb = sizeof(ch); hr = pstream->Write(&ch, cb, &cb); CComVariant varT; varT.Attach(&var); varT.WriteToStream(pstream); varT.Detach(&var); } break; } } return S_OK; } STDMETHODIMP PropertyBag::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog) { ENTER_API { if ((pszPropName == NULL) || (pVar == NULL)) return E_POINTER; CComBSTR bstrName(pszPropName); t_map::iterator iter = m_mapProps.find(bstrName); if (iter == m_mapProps.end()) return E_INVALIDARG; return ::VariantCopy(pVar, &(*iter).second); } LEAVE_API } STDMETHODIMP PropertyBag::Write(LPCOLESTR pszPropName, VARIANT *pvar) { ENTER_API { HRESULT hr; if ((pszPropName == NULL) || (pvar == NULL)) return E_POINTER; if ((pvar->vt & ~VT_TYPEMASK) && (pvar->vt != VT_BSTR_BLOB)) return E_INVALIDARG; CComBSTR bstrName(pszPropName); VARIANT &var = m_mapProps[bstrName.Detach()]; ::VariantInit(&var); hr = ::VariantCopy(&var, pvar); return hr; } LEAVE_API } #endif