/*--------------------------------------------------------------------------* * * Microsoft Windows * Copyright (C) Microsoft Corporation, 1999 - 1999 * * File: fldrsnap.cpp * * Contents: Implementation file for built-in snapins that implement * the Folder, ActiveX Control, and Web Link nodes. * These replace earlier code that had special "built-in" * nodetypes. * * History: 23-Jul-98 vivekj Created * *--------------------------------------------------------------------------*/ #include "stdafx.h" #include "tstring.h" #include "fldrsnap.h" #include "imageid.h" #include // COM Component Categoories Manager #include "compcat.h" #include "guids.h" #include "regutil.h" #include "newnode.h" // These must now be the same - CMTNode::ScConvertLegacyNode depends on it. #define SZ_OCXSTREAM (L"ocx_streamorstorage") #define SZ_OCXSTORAGE (L"ocx_streamorstorage") /*+-------------------------------------------------------------------------* * * ScLoadAndAllocateString * * PURPOSE: Loads the string specified by the string ID and returns a string * whose storage has been allocated by CoTaskMemAlloc. * * PARAMETERS: * UINT ids : * LPOLESTR * lpstrOut : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC ScLoadAndAllocateString(UINT ids, LPOLESTR *lpstrOut) { DECLARE_SC(sc, TEXT("ScLoadAndAllocateString")); sc = ScCheckPointers(lpstrOut); if(sc) return sc.ToHr(); USES_CONVERSION; CStr str; str.LoadString(GetStringModule(), ids); *lpstrOut = (LPOLESTR) CoTaskMemAlloc( (str.GetLength() +1) *sizeof(OLECHAR) ); if(*lpstrOut) wcscpy(*lpstrOut, T2CW(str)); else sc = E_OUTOFMEMORY; return sc.ToHr(); } //############################################################################ //############################################################################ // // Implementation of class CSnapinDescriptor // //############################################################################ //############################################################################ /*+-------------------------------------------------------------------------* * * CSnapinDescriptor::CSnapinDescriptor * * PURPOSE: Constructor * *+-------------------------------------------------------------------------*/ CSnapinDescriptor::CSnapinDescriptor() : m_idsName(0), m_idsDescription(0), m_idiSnapinImage(0), m_idbSmallImage(0), m_idbSmallImageOpen(0), m_idbLargeImage(0), m_clsidSnapin(GUID_NULL), m_szClsidSnapin(TEXT("")), m_guidNodetype(GUID_NULL), m_szGuidNodetype(TEXT("")), m_szClassName(TEXT("")), m_szProgID(TEXT("")), m_szVersionIndependentProgID(TEXT("")), m_viewOptions(0) { } CSnapinDescriptor::CSnapinDescriptor(UINT idsName, UINT idsDescription, UINT idiSnapinImage, UINT idbSmallImage,UINT idbSmallImageOpen, UINT idbLargeImage, const CLSID &clsidSnapin, LPCTSTR szClsidSnapin, const GUID &guidNodetype, LPCTSTR szGuidNodetype, LPCTSTR szClassName, LPCTSTR szProgID, LPCTSTR szVersionIndependentProgID, long viewOptions) : m_idsName(idsName), m_idsDescription(idsDescription), m_idiSnapinImage(idiSnapinImage), m_idbSmallImage(idbSmallImage), m_idbSmallImageOpen(idbSmallImageOpen), m_idbLargeImage(idbLargeImage), m_clsidSnapin(clsidSnapin), m_szClsidSnapin(szClsidSnapin), m_guidNodetype(guidNodetype), m_szGuidNodetype(szGuidNodetype), m_szClassName(szClassName), m_szProgID(szProgID), m_szVersionIndependentProgID(szVersionIndependentProgID), m_viewOptions(viewOptions) { } /*+-------------------------------------------------------------------------* * ScFormatIndirectSnapInName * * Returns the name of the snap-in in the indirect form supported by * SHLoadRegUIString: * * @,- *--------------------------------------------------------------------------*/ SC ScFormatIndirectSnapInName ( HINSTANCE hInst, /* I:module containing the resource */ int idNameString, /* I:ID of name's string resource */ CStr& strName) /* O:formatted indirect name string */ { DECLARE_SC (sc, _T("ScFormatIndirectSnapInName")); /* * allocate a buffer for GetModuleFileName */ const int cbBuffer = MAX_PATH; WTL::CString strStringModule; LPTSTR pBuffer = strStringModule.GetBuffer (cbBuffer); /* * if we couldn't allocate a buffer, return an error */ if (pBuffer == NULL) return (sc = E_OUTOFMEMORY); /* * get the name of the module that provides strings */ const DWORD cbCopied = GetModuleFileName (hInst, pBuffer, cbBuffer); strStringModule.ReleaseBuffer(); /* * if GetModuleFileName failed, return its failure code */ if (cbCopied == 0) { sc.FromLastError(); /* * just in case GetModuleFileName didn't set the last error, make * sure the SC contains some kind of failure code */ if (!sc.IsError()) sc = E_FAIL; return (sc); } /* * if a path is present, SHLoadRegUIString won't search for the DLL * based on the current UI language; remove the path portion of the * module name so it will */ int nLastPathSep = strStringModule.ReverseFind (_T('\\')); if (nLastPathSep != -1) strStringModule = strStringModule.Mid (nLastPathSep + 1); /* * format the name the way SHLoadRegUIString expects it */ strStringModule.MakeLower(); strName.Format (_T("@%s,-%d"), (LPCTSTR) strStringModule, idNameString); return (sc); } /*+-------------------------------------------------------------------------* * CSnapinDescriptor::GetRegisteredIndirectName * * Returns the name of the snap-in in the indirect form supported by * SHLoadRegUIString: * * @,- *--------------------------------------------------------------------------*/ void CSnapinDescriptor::GetRegisteredIndirectName(CStr &strIndirectName) { DECLARE_SC (sc, _T("CSnapinDescriptor::GetRegisteredIndirectName")); sc = ScFormatIndirectSnapInName (GetStringModule(), m_idsName, strIndirectName); if (sc) sc.TraceAndClear(); } /*+-------------------------------------------------------------------------* * CSnapinDescriptor::GetRegisteredDefaultName * * Returns the name of the snap-in in the indirect form supported by * SHLoadRegUIString: * * @,- *--------------------------------------------------------------------------*/ void CSnapinDescriptor::GetRegisteredDefaultName(CStr &str) { str.LoadString (GetStringModule(), m_idsName); } /*+-------------------------------------------------------------------------* * CSnapinDescriptor::GetName * * Returns the human-readable name of the snap-in. *--------------------------------------------------------------------------*/ void CSnapinDescriptor::GetName(CStr &str) { DECLARE_SC (sc, _T("CSnapinDescriptor::GetName")); /* * get the name from the registry */ sc = ScGetSnapinNameFromRegistry (m_szClsidSnapin, str); if (sc) sc.TraceAndClear(); } HBITMAP CSnapinDescriptor::GetSmallImage() { WTL::CBitmap bmp; bmp.LoadBitmap(MAKEINTRESOURCE(m_idbSmallImage)); return (bmp.Detach()); } HBITMAP CSnapinDescriptor::GetSmallImageOpen() { WTL::CBitmap bmp; bmp.LoadBitmap(MAKEINTRESOURCE(m_idbSmallImageOpen)); return (bmp.Detach()); } HBITMAP CSnapinDescriptor::GetLargeImage() { WTL::CBitmap bmp; bmp.LoadBitmap(MAKEINTRESOURCE(m_idbLargeImage)); return (bmp.Detach()); } HICON CSnapinDescriptor::GetSnapinImage() { return LoadIcon( _Module.GetModuleInstance(), MAKEINTRESOURCE(m_idiSnapinImage)); } long CSnapinDescriptor::GetViewOptions() { return m_viewOptions; } //############################################################################ //############################################################################ // // Implementation of class CSnapinComponentDataImpl // //############################################################################ //############################################################################ /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::CSnapinComponentDataImpl * * PURPOSE: Constructor * *+-------------------------------------------------------------------------*/ CSnapinComponentDataImpl::CSnapinComponentDataImpl() : m_bDirty(false) { } void CSnapinComponentDataImpl::SetName(LPCTSTR sz) { m_strName = sz; } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::SetView * * PURPOSE: Sets the view. * * PARAMETERS: * LPCTSTR sz : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CSnapinComponentDataImpl::SetView(LPCTSTR sz) { m_strView = sz; } STDMETHODIMP CSnapinComponentDataImpl::Initialize(LPUNKNOWN pUnknown) { m_spConsole2 = pUnknown; m_spConsoleNameSpace2 = pUnknown; return S_OK; } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::Notify * * PURPOSE: Notification handler for the IComponentData implementation. * * PARAMETERS: * LPDATAOBJECT lpDataObject : As per MMC docs. * MMC_NOTIFY_TYPE event : * LPARAM arg : * LPARAM param : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { USES_CONVERSION; switch(event) { case MMCN_RENAME: // the root node is being renamed m_strName = OLE2T((LPOLESTR)param); SetDirty(); return S_OK; case MMCN_PRELOAD: return OnPreload((HSCOPEITEM) arg); } return S_FALSE; } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::OnPreload * * PURPOSE: sets the icon of the root node (which is the only node.) * * PARAMETERS: * HSCOPEITEM scopeItem : * * RETURNS: * HRESULT * *+-------------------------------------------------------------------------*/ HRESULT CSnapinComponentDataImpl::OnPreload(HSCOPEITEM scopeItem) { SCOPEDATAITEM item; ZeroMemory (&item, sizeof(SCOPEDATAITEM)); item.mask = SDI_CHILDREN; item.ID = scopeItem; item.cChildren = 0; // make sure no "+" sign is displayed. m_spConsoleNameSpace2->SetItem (&item); return S_OK; } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::Destroy * * PURPOSE: Gives up all references to MMC. * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::Destroy() { m_spConsole2 = NULL; m_spConsoleNameSpace2 = NULL; return S_OK; } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::QueryDataObject * * PURPOSE: Returns a data object for the specified node. * * PARAMETERS: * MMC_COOKIE cookie : NULL for the root node. * DATA_OBJECT_TYPES type : * LPDATAOBJECT* ppDataObject : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { ASSERT(cookie == NULL); if(cookie != NULL) return E_UNEXPECTED; CComObject * pDataObject; CComObject::CreateInstance(&pDataObject); if(pDataObject == NULL) return E_UNEXPECTED; pDataObject->Initialize(this, type); return pDataObject->QueryInterface(IID_IDataObject, (void**)ppDataObject); } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::GetDisplayInfo * * PURPOSE: Gets the display info for the root (the only) node. * * PARAMETERS: * SCOPEDATAITEM* pScopeDataItem : [IN/OUT]: The structure to fill in * based on the mask value. * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::GetDisplayInfo( SCOPEDATAITEM* pScopeDataItem) { SCOPEDATAITEM &sdi = *pScopeDataItem; DWORD mask = sdi.mask; if(mask & SDI_STR) { sdi.displayname = (LPOLESTR) GetName(); } if(mask & SDI_IMAGE) { sdi.nImage = m_iImage; } if(mask & SDI_OPENIMAGE) { sdi.nImage = m_iOpenImage; } if(mask & SDI_STATE) { } if(mask & SDI_CHILDREN) { sdi.cChildren =0; } return S_OK; } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::CompareObjects * * PURPOSE: Determines whether two data objects correspond to the same * underlying object. * * PARAMETERS: * LPDATAOBJECT lpDataObjectA : * LPDATAOBJECT lpDataObjectB : * * RETURNS: * STDMETHODIMP : S_OK if they correspond to the same object, else S_FALSE. * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB) { return (lpDataObjectA == lpDataObjectB) ? S_OK : S_FALSE; } // IPersistStream /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::GetClassID * * PURPOSE: * * PARAMETERS: * CLSID * pClassID : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::GetClassID(CLSID *pClassID) { return E_NOTIMPL; } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::IsDirty * * PURPOSE: * * PARAMETERS: * voi d : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::IsDirty(void) { TraceDirtyFlag(TEXT("CSnapinComponentDataImpl (MMC Built-in snapin)"), m_bDirty); return m_bDirty ? S_OK : S_FALSE; } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::Load * * PURPOSE: * * PARAMETERS: * LPSTREAM pStm : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::Load(LPSTREAM pStm) { return CSerialObject::Read(*pStm); } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::Save * * PURPOSE: * * PARAMETERS: * LPSTREAM pStm : * BOOL fClearDirty : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::Save(LPSTREAM pStm , BOOL fClearDirty) { HRESULT hr = CSerialObjectRW::Write(*pStm); if (SUCCEEDED(hr) && fClearDirty) SetDirty(FALSE); return hr; } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::GetSizeMax * * PURPOSE: * * PARAMETERS: * ULARGE_INTEGER* pcbSize : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::GetSizeMax(ULARGE_INTEGER* pcbSize ) { return E_NOTIMPL; } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::GetWatermarks * * PURPOSE: Sets the header for the wizard * * PARAMETERS: * LPDATAOBJECT lpIDataObject : * HBITMAP * lphWatermark : * HBITMAP * lphHeader : * HPALETTE * lphPalette : * BOOL* bStretch : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::GetWatermarks(LPDATAOBJECT lpIDataObject, HBITMAP * lphWatermark, HBITMAP * lphHeader, HPALETTE * lphPalette, BOOL* bStretch) { DECLARE_SC(sc, TEXT("COCXSnapinData::ScGetWatermarks")); // validate inputs sc = ScCheckPointers(lpIDataObject, lphWatermark, lphHeader, lphPalette); if(sc) return sc.ToHr(); // initialize outputs *lphWatermark = GetWatermark() ? ::LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(GetWatermark())) : NULL; // if there is a header, use it. *lphHeader = GetHeaderBitmap() ? ::LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(GetHeaderBitmap())) : NULL; *lphPalette = NULL; return sc.ToHr(); } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::QueryPagesFor * * PURPOSE: * * PARAMETERS: * LPDATAOBJECT lpDataObject : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::QueryPagesFor(LPDATAOBJECT lpDataObject) { CSnapinDataObject *pDataObject = dynamic_cast(lpDataObject); if(pDataObject == NULL) return E_UNEXPECTED; if(pDataObject->GetType() != CCT_SNAPIN_MANAGER) return S_FALSE; return S_OK; // properties exist only in the snap-in manager. } /*+-------------------------------------------------------------------------* * CSnapinComponentDataImpl::GetHelpTopic * * Default implementation of ISnapinHelp::GetHelpTopic for built-in snap- * ins (folder, OCX, web page). * * We need to implement ISnapinHelp in the built-ins to avoid getting * "Help for " on the Help menu (bug 453700). They don't really * have help info, so we simply return S_FALSE so the help engine doesn't * complain. *--------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentDataImpl::GetHelpTopic ( LPOLESTR* /*ppszCompiledHelpTopic*/) { return (S_FALSE); // no help topic } // CSerialObject methods /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::ReadSerialObject * * PURPOSE: * * PARAMETERS: * IStream & stm : * UINT nVersion : * * RETURNS: * HRESULT * *+-------------------------------------------------------------------------*/ HRESULT CSnapinComponentDataImpl::ReadSerialObject (IStream &stm, UINT nVersion) { if(nVersion==1) { stm >> m_strName; stm >> m_strView; return S_OK; } else return S_FALSE; //unknown version, skip. } /*+-------------------------------------------------------------------------* * * CSnapinComponentDataImpl::WriteSerialObject * * PURPOSE: * * PARAMETERS: * IStream & stm : * * RETURNS: * HRESULT * *+-------------------------------------------------------------------------*/ HRESULT CSnapinComponentDataImpl::WriteSerialObject(IStream &stm) { stm << m_strName; stm << m_strView; return S_OK; } //############################################################################ //############################################################################ // // Implementation of class CSnapinComponentImpl // //############################################################################ //############################################################################ /*+-------------------------------------------------------------------------* * * CSnapinComponentImpl::Init * * PURPOSE: * * PARAMETERS: * IComponentData * pComponentData : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CSnapinComponentImpl::Init(IComponentData *pComponentData) { m_spComponentData = pComponentData; } // IComponent /*+-------------------------------------------------------------------------* * * CSnapinComponentImpl::Initialize * * PURPOSE: * * PARAMETERS: * LPCONSOLE lpConsole : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentImpl::Initialize(LPCONSOLE lpConsole) { m_spConsole2 = lpConsole; return S_OK; } /*+-------------------------------------------------------------------------* * * CSnapinComponentImpl::Notify * * PURPOSE: * * PARAMETERS: * LPDATAOBJECT lpDataObject : * MMC_NOTIFY_TYPE event : * LPARAM arg : * LPARAM param : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentImpl::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { switch(event) { case MMCN_SELECT: { BOOL bScope = (BOOL) LOWORD(arg); BOOL bSelect = (BOOL) HIWORD(arg); SC sc = ScOnSelect(bScope, bSelect); if(sc) return sc.ToHr(); } return S_OK; break; default: break; } return S_FALSE; } /*+-------------------------------------------------------------------------* * * CSnapinComponentImpl::ScOnSelect * * PURPOSE: * * PARAMETERS: * BOOL bScope : * BOOL bSelect : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CSnapinComponentImpl::ScOnSelect(BOOL bScope, BOOL bSelect) { DECLARE_SC(sc, TEXT("CSnapinComponentImpl::ScOnSelect")); IConsoleVerbPtr spConsoleVerb; sc = m_spConsole2->QueryConsoleVerb(&spConsoleVerb); if(sc) return sc; sc = spConsoleVerb->SetVerbState(MMC_VERB_RENAME, ENABLED, (bSelect && bScope)); if(sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CSnapinComponentImpl::Destroy * * PURPOSE: * * PARAMETERS: * MMC_COOKIE cookie : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentImpl::Destroy(MMC_COOKIE cookie) { m_spConsole2 = NULL; m_spComponentData = NULL; return S_OK; } /*+-------------------------------------------------------------------------* * * CSnapinComponentImpl::QueryDataObject * * PURPOSE: * * PARAMETERS: * MMC_COOKIE cookie : * DATA_OBJECT_TYPES type : * LPDATAOBJECT* ppDataObject : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentImpl::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { return E_NOTIMPL; } /*+-------------------------------------------------------------------------* * * CSnapinComponentImpl::GetComponentData * * PURPOSE: * * RETURNS: * CSnapinComponentDataImpl * * *+-------------------------------------------------------------------------*/ CSnapinComponentDataImpl * CSnapinComponentImpl::GetComponentData() { CSnapinComponentDataImpl *pCD = dynamic_cast(m_spComponentData.GetInterfacePtr()); ASSERT(pCD != NULL); return pCD; } /*+-------------------------------------------------------------------------* * * CSnapinComponentImpl::GetResultViewType * * PURPOSE: * * PARAMETERS: * MMC_COOKIE cookie : * LPOLESTR* ppViewType : * long* pViewOptions : Set to MMC_VIEW_OPTIONS_NOLISTVIEWS for the HTML and OCX snapins, * 0 for the folder snapin. * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentImpl::GetResultViewType(MMC_COOKIE cookie, LPOLESTR* ppViewType, long* pViewOptions) { // check parameters if(!ppViewType || !pViewOptions) return E_UNEXPECTED; if(!GetComponentData()) return E_UNEXPECTED; USES_CONVERSION; *ppViewType = (LPOLESTR)CoTaskMemAlloc( (_tcslen(GetComponentData()->GetView())+1) * sizeof(OLECHAR) ); *pViewOptions = GetComponentData()->GetDescriptor().GetViewOptions(); wcscpy(*ppViewType, T2OLE((LPTSTR)GetComponentData()->GetView())); return S_OK; } /*+-------------------------------------------------------------------------* * * CSnapinComponentImpl::GetDisplayInfo * * PURPOSE: * * PARAMETERS: * RESULTDATAITEM* pResultDataItem : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentImpl::GetDisplayInfo( RESULTDATAITEM* pResultDataItem) { RESULTDATAITEM &rdi = *pResultDataItem; DWORD mask = rdi.mask; if(mask & RDI_STR) { rdi.str = (LPOLESTR) GetComponentData()->GetName(); } if(mask & RDI_IMAGE) { rdi.nImage = GetComponentData()->m_iImage; } return S_OK; } /*+-------------------------------------------------------------------------* * * CSnapinComponentImpl::CompareObjects * * PURPOSE: * * PARAMETERS: * LPDATAOBJECT lpDataObjectA : * LPDATAOBJECT lpDataObjectB : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinComponentImpl::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB) { return E_NOTIMPL; } //############################################################################ //############################################################################ // // Implementation of class CSnapinDataObject // //############################################################################ //############################################################################ // Clipboard formats that are required by the console UINT CSnapinDataObject::s_cfNodeType; UINT CSnapinDataObject::s_cfNodeTypeString; UINT CSnapinDataObject::s_cfDisplayName; UINT CSnapinDataObject::s_cfCoClass; UINT CSnapinDataObject::s_cfSnapinPreloads; /*+-------------------------------------------------------------------------* * * CSnapinDataObject::RegisterClipboardFormats * * PURPOSE: * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CSnapinDataObject::RegisterClipboardFormats() { static bool bRegistered = false; if(!bRegistered) { USES_CONVERSION; CSnapinDataObject::s_cfNodeType = RegisterClipboardFormat(OLE2T(CCF_NODETYPE)); CSnapinDataObject::s_cfNodeTypeString = RegisterClipboardFormat(OLE2T(CCF_SZNODETYPE)); CSnapinDataObject::s_cfDisplayName = RegisterClipboardFormat(OLE2T(CCF_DISPLAY_NAME)); CSnapinDataObject::s_cfCoClass = RegisterClipboardFormat(OLE2T(CCF_SNAPIN_CLASSID)); CSnapinDataObject::s_cfSnapinPreloads = RegisterClipboardFormat(OLE2T(CCF_SNAPIN_PRELOADS)); bRegistered = true; } } CSnapinDataObject::CSnapinDataObject() : m_bInitialized(false) { } /*+-------------------------------------------------------------------------* * * CSnapinDataObject::GetDataHere * * PURPOSE: * * PARAMETERS: * FORMATETC * pformatetc : * STGMEDIUM * pmedium : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CSnapinDataObject::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) { DECLARE_SC(sc, TEXT("CSnapinDataObject::GetDataHere")); // validate inputs sc = ScCheckPointers(pformatetc, pmedium); if(sc) return sc.ToHr(); USES_CONVERSION; RegisterClipboardFormats(); // Based on the CLIPFORMAT write data to the stream const CLIPFORMAT cf = pformatetc->cfFormat; // ensure the medium is an HGLOBAL if(pformatetc->tymed != TYMED_HGLOBAL) return (sc = DV_E_TYMED).ToHr(); IStreamPtr spStream; HGLOBAL hGlobal = pmedium->hGlobal; pmedium->pUnkForRelease = NULL; // by OLE spec sc = CreateStreamOnHGlobal( hGlobal, FALSE, &spStream ); if(sc) return sc.ToHr(); CSnapinComponentDataImpl *pComponentDataImpl = dynamic_cast(m_spComponentData.GetInterfacePtr()); ASSERT(pComponentDataImpl != NULL); if (cf == s_cfNodeType) { spStream<GetDescriptor().m_guidNodetype; } else if (cf == s_cfCoClass) { spStream<GetDescriptor().m_clsidSnapin; } else if(cf == s_cfNodeTypeString) { WriteString(spStream, T2OLE((LPTSTR)pComponentDataImpl->GetDescriptor().m_szGuidNodetype)); } else if (cf == s_cfDisplayName) { WriteString(spStream, T2OLE((LPTSTR)pComponentDataImpl->GetName())); } else if (cf == s_cfSnapinPreloads) { BOOL bPreload = true; spStream->Write ((void *)&bPreload, sizeof(BOOL), NULL); } else { return (sc = DV_E_CLIPFORMAT).ToHr(); // invalid format. } return sc.ToHr(); } /*+-------------------------------------------------------------------------* * * CSnapinDataObject::WriteString * * PURPOSE: * * PARAMETERS: * IStream * pStream : * LPCOLESTR sz : * * RETURNS: * HRESULT * *+-------------------------------------------------------------------------*/ HRESULT CSnapinDataObject::WriteString(IStream *pStream, LPCOLESTR sz) { HRESULT hr = S_OK; ASSERT(pStream != NULL); if(pStream == NULL) { //TraceError(TEXT("CSnapinDataObject::WriteString")); return E_UNEXPECTED; } UINT cbToWrite = wcslen(sz)*sizeof(WCHAR); ULONG cbActuallyWritten=0; hr = pStream->Write (sz, cbToWrite, &cbActuallyWritten); ASSERT(cbToWrite==cbActuallyWritten); return hr; } /*+-------------------------------------------------------------------------* * * CSnapinDataObject::Initialize * * PURPOSE: * * PARAMETERS: * IComponentData * pComponentData : * DATA_OBJECT_TYPES type : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CSnapinDataObject::Initialize(IComponentData *pComponentData, DATA_OBJECT_TYPES type) { ASSERT(pComponentData != NULL); m_spComponentData = pComponentData; m_type = type; m_bInitialized = true; } //############################################################################ //############################################################################ // // Implementation of class CFolderSnapinData // //############################################################################ //############################################################################ STDMETHODIMP CFolderSnapinData::CreateComponent(LPCOMPONENT* ppComponent) { typedef CComObject CComponent; CComponent * pComponent = NULL; CComObject::CreateInstance(&pComponent); ASSERT(pComponent != NULL); if(pComponent == NULL) { //TraceError(TEXT("CFolderSnapinData::CreateComponent")); return E_UNEXPECTED; } pComponent->Init(this); return pComponent->QueryInterface(IID_IComponent, (void **)ppComponent); // does the Addref. } CFolderSnapinData::CFolderSnapinData() { m_iImage = eStockImage_Folder; m_iOpenImage = eStockImage_OpenFolder; } const CLSID CLSID_FolderSnapin = {0xC96401CC, 0x0E17,0x11D3, {0x88,0x5B,0x00,0xC0,0x4F,0x72,0xC7,0x17}}; static const GUID GUID_FolderSnapinNodetype = {0xc96401ce, 0xe17, 0x11d3, { 0x88, 0x5b, 0x0, 0xc0, 0x4f, 0x72, 0xc7, 0x17 } }; static LPCTSTR szClsid_FolderSnapin = TEXT("{C96401CC-0E17-11D3-885B-00C04F72C717}"); static LPCTSTR szGuidFolderSnapinNodetype = TEXT("{C96401CE-0E17-11D3-885B-00C04F72C717}"); CSnapinDescriptor & CFolderSnapinData::GetSnapinDescriptor() { static CSnapinDescriptor snapinDescription(IDS_FOLDER, IDS_FOLDERSNAPIN_DESC, IDI_FOLDER, IDB_FOLDER_16, IDB_FOLDEROPEN_16, IDB_FOLDER_32, CLSID_FolderSnapin, szClsid_FolderSnapin, GUID_FolderSnapinNodetype, szGuidFolderSnapinNodetype, TEXT("Folder"), TEXT("Snapins.FolderSnapin"), TEXT("Snapins.FolderSnapin.1"), 0 /*viewOptions*/ ); return snapinDescription; } // IExtendPropertySheet2 STDMETHODIMP CFolderSnapinData::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, LPDATAOBJECT lpIDataObject) { return S_FALSE; } //############################################################################ //############################################################################ // // Implementation of class CHTMLSnapinData // //############################################################################ //############################################################################ STDMETHODIMP CHTMLSnapinData::CreateComponent(LPCOMPONENT* ppComponent) { typedef CComObject CComponent; CComponent * pComponent = NULL; CComObject::CreateInstance(&pComponent); ASSERT(pComponent != NULL); if(pComponent == NULL) { //TraceError(TEXT("CHTMLSnapinData::CreateComponent")); return E_UNEXPECTED; } pComponent->Init(this); return pComponent->QueryInterface(IID_IComponent, (void **)ppComponent); // does the Addref. } CHTMLSnapinData::CHTMLSnapinData() { m_pHtmlPage1 = NULL; m_pHtmlPage2 = NULL; m_iImage = eStockImage_HTML; m_iOpenImage = eStockImage_HTML; } CHTMLSnapinData::~CHTMLSnapinData() { } STDMETHODIMP CHTMLSnapinData::Destroy() { if(m_pHtmlPage1 != NULL) { delete m_pHtmlPage1; m_pHtmlPage1 = NULL; } if(m_pHtmlPage2 != NULL) { delete m_pHtmlPage2; m_pHtmlPage2 = NULL; } return BC::Destroy(); } const CLSID CLSID_HTMLSnapin = {0xC96401D1, 0x0E17,0x11D3, {0x88,0x5B,0x00,0xC0,0x4F,0x72,0xC7,0x17}}; static const GUID GUID_HTMLSnapinNodetype = {0xc96401d2, 0xe17, 0x11d3, { 0x88, 0x5b, 0x0, 0xc0, 0x4f, 0x72, 0xc7, 0x17 } }; static LPCTSTR szClsid_HTMLSnapin = TEXT("{C96401D1-0E17-11D3-885B-00C04F72C717}"); static LPCTSTR szGuidHTMLSnapinNodetype = TEXT("{C96401D2-0E17-11D3-885B-00C04F72C717}"); CSnapinDescriptor & CHTMLSnapinData::GetSnapinDescriptor() { static CSnapinDescriptor snapinDescription(IDS_HTML, IDS_HTMLSNAPIN_DESC, IDI_HTML, IDB_HTML_16, IDB_HTML_16, IDB_HTML_32, CLSID_HTMLSnapin, szClsid_HTMLSnapin, GUID_HTMLSnapinNodetype, szGuidHTMLSnapinNodetype, TEXT("HTML"), TEXT("Snapins.HTMLSnapin"), TEXT("Snapins.HTMLSnapin.1"), MMC_VIEW_OPTIONS_NOLISTVIEWS /*viewOptions*/ ); return snapinDescription; } // IExtendPropertySheet2 /*+-------------------------------------------------------------------------* * * CHTMLSnapinData::CreatePropertyPages * * PURPOSE: * * PARAMETERS: * LPPROPERTYSHEETCALLBACK lpProvider : * LONG_PTR handle : * LPDATAOBJECT lpIDataObject : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CHTMLSnapinData::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, LPDATAOBJECT lpIDataObject) { HPROPSHEETPAGE hPage; ASSERT(lpProvider != NULL); if(lpProvider == NULL) { //TraceError(TEXT("CHTMLSnapinData::CreatePropertyPages")); return E_UNEXPECTED; } ASSERT(m_pHtmlPage1 == NULL); ASSERT(m_pHtmlPage2 == NULL); // create property pages m_pHtmlPage1 = new CHTMLPage1; m_pHtmlPage2 = new CHTMLPage2; // pass in pointer to data structure m_pHtmlPage1->Initialize(this); m_pHtmlPage2->Initialize(this); // Add Pages to property sheet hPage=CreatePropertySheetPage(&m_pHtmlPage1->m_psp); lpProvider->AddPage(hPage); hPage=CreatePropertySheetPage(&m_pHtmlPage2->m_psp); lpProvider->AddPage(hPage); return S_OK; } //############################################################################ //############################################################################ // // Implementation of class CHTMLSnapinComponent // //############################################################################ //############################################################################ /*+-------------------------------------------------------------------------* * * CHTMLSnapinComponent::ScOnSelect * * PURPOSE: Handles the MMCN_SELECT notification. Enables the Refresh verb, * which uses the default MMC handler to refresh the page. * * PARAMETERS: * BOOL bScope : * BOOL bSelect : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CHTMLSnapinComponent::ScOnSelect(BOOL bScope, BOOL bSelect) { DECLARE_SC(sc, TEXT("CHTMLSnapinComponent::ScOnSelect")); // call the base class method sc = BC::ScOnSelect(bScope, bSelect); if(sc) return sc; IConsoleVerbPtr spConsoleVerb; sc = ScCheckPointers(m_spConsole2, E_UNEXPECTED); if(sc) return sc; sc = m_spConsole2->QueryConsoleVerb(&spConsoleVerb); if(sc) return sc; sc = ScCheckPointers(spConsoleVerb, E_UNEXPECTED); if(sc) return sc; // enable the Refresh verb - the default MMC handler is adequate to refresh the page. sc = spConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, (bSelect && bScope)); if(sc) return sc; //NOTE: (vivekj): I'm intentionally not setting the HIDDEN state to false here, because // we have an explicit test in our verb code for MMC1.0 snapins that wrote code like this, // and this provides a useful compatibility test. return sc; } /*+-------------------------------------------------------------------------* * * CHTMLSnapinComponent::GetResultViewType * * PURPOSE: Performs parameter substitution on the URL for the environment variables * %windir% and %systemroot% (only) and returns the expanded URL. * * NOTE: We don't expand ALL variables using ExpandEnvironmentString. Doing so could * break compatibility with URL's that have %var% but DON'T want to be * expanded. * * PARAMETERS: * MMC_COOKIE cookie : * LPOLESTR* ppViewType : * long* pViewOptions : * * RETURNS: * STDMETHODIMP * *+-------------------------------------------------------------------------*/ STDMETHODIMP CHTMLSnapinComponent::GetResultViewType(MMC_COOKIE cookie, LPOLESTR* ppViewType, long* pViewOptions) { DECLARE_SC(sc, TEXT("CHTMLSnapinComponent::GetResultViewType")); // check parameters if(!ppViewType || !pViewOptions) return (sc = E_UNEXPECTED).ToHr(); if(!GetComponentData()) return (sc = E_UNEXPECTED).ToHr(); // add support for expanding the environment variables %WINDIR% and %SYSTEMROOT% to maintain compatibility with MMC1.2 CStr strTarget = GetComponentData()->GetView(); CStr strRet = strTarget; // the return value CStr strTemp = strTarget; // both initialized to the same value. strTemp.MakeLower(); // NOTE: this lowercase conversion is used only for comparison. The original case is preserved in the output. // Find out if %windir% or %systemroot% is in the target string int nWndDir = strTemp.Find(MMC_WINDIR_VARIABLE_PERC); int nSysDir = strTemp.Find(MMC_SYSTEMROOT_VARIABLE_PERC); if (nWndDir != -1 || nSysDir != -1) { const UINT BUFFERLEN = 4096; // Get start pos and length of replacement string int nStpos = (nWndDir != -1) ? nWndDir : nSysDir; int nLen = (nWndDir != -1) ? _tcslen(MMC_WINDIR_VARIABLE_PERC) : _tcslen(MMC_SYSTEMROOT_VARIABLE_PERC); // Setup temp variable to hold BUFFERLEN chars CStr strRoot; LPTSTR lpsz = strRoot.GetBuffer(BUFFERLEN); if (lpsz != NULL) { int iReturn = -1; if (nWndDir != -1) iReturn = GetWindowsDirectory(lpsz, BUFFERLEN); else iReturn = GetEnvironmentVariable(MMC_SYSTEMROOT_VARIABLE, lpsz, BUFFERLEN); // release string buffer strRoot.ReleaseBuffer(); // Build up new target string based on environemnt variable. if (iReturn != 0) { strRet = strTarget.Left(nStpos); strRet += strRoot; strRet += strTarget.Mid(nStpos + nLen, strTarget.GetLength() - (nStpos + nLen)); } } } USES_CONVERSION; *ppViewType = (LPOLESTR)CoTaskMemAlloc( (_tcslen(strRet)+1) * sizeof(OLECHAR) ); *pViewOptions = GetComponentData()->GetDescriptor().GetViewOptions(); wcscpy(*ppViewType, T2COLE(strRet)); return sc.ToHr(); } //############################################################################ //############################################################################ // // Implementation of class COCXSnapinData // //############################################################################ //############################################################################ STDMETHODIMP COCXSnapinData::CreateComponent(LPCOMPONENT* ppComponent) { typedef CComObject CComponent; CComponent * pComponent = NULL; CComObject::CreateInstance(&pComponent); ASSERT(pComponent != NULL); if(pComponent == NULL) { //TraceError(TEXT("COCXSnapinData::CreateComponent")); return E_UNEXPECTED; } pComponent->Init(this); return pComponent->QueryInterface(IID_IComponent, (void **)ppComponent); // does the Addref. } COCXSnapinData::COCXSnapinData() { m_pActiveXPage0 = NULL; m_pActiveXPage1 = NULL; m_pActiveXPage2 = NULL; m_iImage = eStockImage_OCX; m_iOpenImage = eStockImage_OCX; } COCXSnapinData::~COCXSnapinData() { } STDMETHODIMP COCXSnapinData::Destroy() { if(m_pActiveXPage0 != NULL) { delete m_pActiveXPage0; m_pActiveXPage0 = NULL; } if(m_pActiveXPage1 != NULL) { delete m_pActiveXPage1; m_pActiveXPage1 = NULL; } if(m_pActiveXPage2 != NULL) { delete m_pActiveXPage2; m_pActiveXPage2 = NULL; } return BC::Destroy(); } const CLSID CLSID_OCXSnapin = {0xC96401CF, 0x0E17,0x11D3, {0x88,0x5B,0x00,0xC0,0x4F,0x72,0xC7,0x17}}; static const GUID GUID_OCXSnapinNodetype = {0xc96401d0, 0xe17, 0x11d3, { 0x88, 0x5b, 0x0, 0xc0, 0x4f, 0x72, 0xc7, 0x17 } }; static LPCTSTR szClsid_OCXSnapin = TEXT("{C96401CF-0E17-11D3-885B-00C04F72C717}"); static LPCTSTR szGuidOCXSnapinNodetype = TEXT("{C96401D0-0E17-11D3-885B-00C04F72C717}"); CSnapinDescriptor & COCXSnapinData::GetSnapinDescriptor() { static CSnapinDescriptor snapinDescription(IDS_ACTIVEXCONTROL, IDS_OCXSNAPIN_DESC, IDI_OCX, IDB_OCX_16, IDB_OCX_16, IDB_OCX_32, CLSID_OCXSnapin, szClsid_OCXSnapin, GUID_OCXSnapinNodetype, szGuidOCXSnapinNodetype, TEXT("OCX"), TEXT("Snapins.OCXSnapin"), TEXT("Snapins.OCXSnapin.1"), MMC_VIEW_OPTIONS_NOLISTVIEWS /*viewOptions*/ ); return snapinDescription; } // IExtendPropertySheet2 STDMETHODIMP COCXSnapinData::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, LPDATAOBJECT lpIDataObject) { HPROPSHEETPAGE hPage; ASSERT(lpProvider != NULL); if(lpProvider == NULL) { //TraceError(TEXT("CHTMLSnapinData::CreatePropertyPages")); return E_UNEXPECTED; } ASSERT(m_pActiveXPage0 == NULL); ASSERT(m_pActiveXPage1 == NULL); ASSERT(m_pActiveXPage2 == NULL); // create property pages m_pActiveXPage0 = new CActiveXPage0; m_pActiveXPage1 = new CActiveXPage1; m_pActiveXPage2 = new CActiveXPage2; // pass in pointer to data structure m_pActiveXPage0->Initialize(this); m_pActiveXPage1->Initialize(this); m_pActiveXPage2->Initialize(this); // Add Pages to property sheet hPage=CreatePropertySheetPage(&m_pActiveXPage0->m_psp); lpProvider->AddPage(hPage); hPage=CreatePropertySheetPage(&m_pActiveXPage1->m_psp); lpProvider->AddPage(hPage); hPage=CreatePropertySheetPage(&m_pActiveXPage2->m_psp); lpProvider->AddPage(hPage); return S_OK; } //############################################################################ //############################################################################ // // Implementation of class COCXSnapinComponent // //############################################################################ //############################################################################ /*+-------------------------------------------------------------------------* * * COCXSnapinComponent::Notify * * PURPOSE: Implements the CComponent::Notify method * * PARAMETERS: * LPDATAOBJECT lpDataObject : * MMC_NOTIFY_TYPE event : * LPARAM arg : * LPARAM param : * * RETURNS: * HRESULT * *+-------------------------------------------------------------------------*/ HRESULT COCXSnapinComponent::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { HRESULT hr = S_OK; switch(event) { // Handle just the OCX initialization notify case MMCN_INITOCX: return OnInitOCX(lpDataObject, arg, param); break; default: // Pass other notifications on to base class return CSnapinComponentImpl::Notify(lpDataObject, event, arg, param); break; } return hr; } /*+-------------------------------------------------------------------------* * * COCXSnapinComponent::OnInitOCX * * PURPOSE: Handles the MMCN_INITOCX message. * * PARAMETERS: * LPDATAOBJECT lpDataObject : * LPARAM arg : * LPARAM param : * * RETURNS: * HRESULT * *+-------------------------------------------------------------------------*/ HRESULT COCXSnapinComponent::OnInitOCX(LPDATAOBJECT lpDataObject, LPARAM arg, LPARAM param) { HRESULT hr = S_OK; ASSERT(param != NULL); IUnknown* pUnknown = reinterpret_cast(param); ASSERT(m_bLoaded || m_bInitialized); // Load or initialze the OCX if (m_bLoaded || m_bInitialized) { IPersistStreamInitPtr spIPStmInit; // Query for stream support m_spIPStm = pUnknown; // if none, try streamInit if (m_spIPStm == NULL) { spIPStmInit = pUnknown; // if streamInit found, cast to normal stream pointer // so common methods can be called from single pointer if (spIPStmInit != NULL) m_spIPStm = (IPersistStream*)spIPStmInit.GetInterfacePtr(); } // if either type of stream persistance supported if (m_spIPStm != NULL) { // if load method was called, then ask OCX to load from inner stream // Note that inner stream will not exist if OCX was never created if (m_bLoaded) { IStreamPtr spStm; HRESULT hr2 = m_spStg->OpenStream(SZ_OCXSTREAM, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, NULL, &spStm); if (SUCCEEDED(hr2)) hr = m_spIPStm->Load(spStm); else m_bLoaded = FALSE; } // if no load was done and OCX requires an InitNew, give it one now if (!m_bLoaded && spIPStmInit != NULL) hr = spIPStmInit->InitNew(); } else { // Query for storage support m_spIPStg = pUnknown; // if storage supported, ask OCX to load from inner storage // Note that inner storage will not exist if OCX was never created if (m_spIPStg != NULL) { if (m_bLoaded) { ASSERT(m_spStgInner == NULL); HRESULT hr2 = m_spStg->OpenStorage(SZ_OCXSTORAGE, NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, NULL, &m_spStgInner); if (SUCCEEDED(hr2)) hr = m_spIPStg->Load(m_spStgInner); else m_bLoaded = FALSE; } // if no load done, create an inner storage and init from it if (!m_bLoaded) { ASSERT(m_spStgInner == NULL); hr = m_spStg->CreateStorage(SZ_OCXSTORAGE, STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, NULL, &m_spStgInner); if (SUCCEEDED(hr)) hr = m_spIPStg->InitNew(m_spStgInner); } } } } return hr; } STDMETHODIMP COCXSnapinComponent::InitNew(IStorage* pStg) { if (pStg == NULL) return E_POINTER; if (m_bInitialized) return CO_E_ALREADYINITIALIZED; // Hold onto storage m_spStg = pStg; m_bInitialized = TRUE; return S_OK; } HRESULT COCXSnapinComponent::Load(IStorage* pStg) { if (pStg == NULL) return E_POINTER; if (m_bInitialized) return CO_E_ALREADYINITIALIZED; // Hold onto storage m_spStg = pStg; m_bLoaded = TRUE; m_bInitialized = TRUE; return S_OK; } HRESULT COCXSnapinComponent::IsDirty() { HRESULT hr = S_FALSE; if (m_spIPStm != NULL) { hr = m_spIPStm->IsDirty(); } else if (m_spIPStg != NULL) { hr = m_spIPStg->IsDirty(); } return hr; } HRESULT COCXSnapinComponent::Save(IStorage* pStg, BOOL fSameAsLoad) { DECLARE_SC(sc, TEXT("COCXSnapinComponent::Save")); // parameter check sc = ScCheckPointers( pStg ); if (sc) return sc.ToHr(); // to be able to save we need to be initialized sc = ScCheckPointers( m_spStg, E_UNEXPECTED ); if (sc) return sc.ToHr(); // if need to use the new storage - make a copy if (!fSameAsLoad) { sc = m_spStg->CopyTo(0, NULL, NULL, pStg); if (sc) return sc.ToHr(); // release cached storage (in case we have it) - it must change m_spStgInner = NULL; // hold onto the new storage m_spStg = pStg; // assignment uses QI - recheck! sc = ScCheckPointers( m_spStg, E_UNEXPECTED ); if (sc) return sc.ToHr(); } // if storage support, ask OCX to save to inner storage if (m_spIPStg) { bool bSameStorageForSnapin = true; // if saving to different storage, create new inner storage on it and pass to OCX if ( m_spStgInner == NULL ) { sc = pStg->CreateStorage(SZ_OCXSTORAGE, STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE, NULL, NULL, &m_spStgInner); if (sc) return sc.ToHr(); bSameStorageForSnapin = false; } // recheck the pointer sc = ScCheckPointers( m_spStgInner, E_UNEXPECTED ); if (sc) return sc.ToHr(); // save to the storage sc = m_spIPStg->Save( m_spStgInner, (fSameAsLoad && bSameStorageForSnapin) ); if (sc) return sc.ToHr(); } // else if stream support, create/open stream and save to it else if (m_spIPStm) { // if stream support, create internal stream and pass to OCX IStreamPtr spStm; sc = m_spStg->CreateStream(SZ_OCXSTREAM, STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE, NULL, NULL, &spStm); if (sc) return sc.ToHr(); sc = m_spIPStm->Save(spStm, TRUE); if (sc) return sc.ToHr(); } else { // we are here if the OCX was never created (i.e., this component never owned the result pane) // if node was loaded and has to save to a new file, just copy the current storage to the new one } return sc.ToHr(); } HRESULT COCXSnapinComponent::HandsOffStorage() { // Release storage if holding ref // if ocx is holding storage, forward call to it if (m_spIPStg != NULL && m_spStgInner != NULL) m_spIPStg->HandsOffStorage(); // Free our own refs m_spStgInner = NULL; m_spStg = NULL; return S_OK; } HRESULT COCXSnapinComponent::SaveCompleted(IStorage* pStgNew) { HRESULT hr = S_OK; if (m_spIPStg != NULL) { // if new storage provided if (pStgNew != NULL && pStgNew != m_spStg) { // Create new inner storage and give to OCX IStoragePtr spStgInner; hr = pStgNew->CreateStorage(SZ_OCXSTORAGE, STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE, NULL, NULL, &spStgInner); if (SUCCEEDED(hr)) hr = m_spIPStg->SaveCompleted(spStgInner); // Free current inner storage and hold onto new one m_spStgInner = spStgInner; } else { m_spIPStg->SaveCompleted(NULL); } } if (pStgNew != NULL) m_spStg = pStgNew; return hr; } HRESULT COCXSnapinComponent::GetClassID(CLSID *pClassID) { return E_NOTIMPL; }