/*++ Copyright (c) 1994-1999 Microsoft Corporation Module Name : inetmgr.cpp Abstract: Main MMC snap-in code Author: Ronald Meijer (ronaldm) Project: Internet Services Manager Revision History: --*/ #include "stdafx.h" #include "common.h" #include "InetMgrApp.h" #include "iisobj.h" #include "toolbar.h" #include "util.h" #include "tracker.h" #include "guids.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW //const GUID * CCompMgrExtData::m_NODETYPE = &cCompMgmtService; //const OLECHAR * CCompMgrExtData::m_SZNODETYPE = OLESTR("476e6446-aaff-11d0-b944-00c04fd8d5b0"); //const OLECHAR * CCompMgrExtData::m_SZDISPLAY_NAME = OLESTR("CMSnapin"); //const CLSID * CCompMgrExtData::m_SNAPIN_CLASSID = &CLSID_InetMgr; extern CInetmgrApp theApp; extern CPropertySheetTracker g_OpenPropertySheetTracker; extern CWNetConnectionTrackerGlobal g_GlobalConnections; #if defined(_DEBUG) || DBG extern CDebug_IISObject g_Debug_IISObject; #endif int g_IISMMCComLoaded = 0; int g_IISMMCInstanceCount = 0; int g_IISMMCInstanceCountExtensionMode = 0; HRESULT GetHelpTopic(LPOLESTR *lpCompiledHelpFile) { if (lpCompiledHelpFile == NULL) return E_INVALIDARG; CString strFilePath, strWindowsPath, strBuffer; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Use system API to get windows directory. UINT uiResult = GetWindowsDirectory(strWindowsPath.GetBuffer(MAX_PATH), MAX_PATH); strWindowsPath.ReleaseBuffer(); if (uiResult <= 0 || uiResult > MAX_PATH) { return E_FAIL; } if (!strFilePath.LoadString(IDS_HELPFILE)) { return E_FAIL; } strBuffer = strWindowsPath; strBuffer += _T('\\'); strBuffer += strFilePath; *lpCompiledHelpFile = reinterpret_cast(CoTaskMemAlloc((strBuffer.GetLength() + 1) * sizeof(_TCHAR))); if (*lpCompiledHelpFile == NULL) return E_OUTOFMEMORY; USES_CONVERSION; _tcscpy(*lpCompiledHelpFile, T2OLE((LPTSTR)(LPCTSTR)strBuffer)); return S_OK; } // // CInetMgrComponent Implementation // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CInetMgrComponent::CInetMgrComponent() /*++ Routine Description: Constructor Arguments: None Return Value: N/A --*/ { _lpControlBar = NULL; _lpToolBar = NULL; g_IISMMCInstanceCount++; TRACEEOLID("CInetMgrComponent::CInetMgrComponent:g_IISMMCInstanceCount=" << g_IISMMCInstanceCount); } CInetMgrComponent::~CInetMgrComponent() { TRACEEOLID("CInetMgrComponent::~CInetMgrComponent:g_IISMMCInstanceCount=" << g_IISMMCInstanceCount); } HRESULT CInetMgrComponent::Destroy(LONG cookie) { g_IISMMCInstanceCount--; TRACEEOLID("CInetMgrComponent::Destroy:g_IISMMCInstanceCount=" << g_IISMMCInstanceCount); return S_OK; } HRESULT CInetMgrComponent::Notify( IN LPDATAOBJECT lpDataObject, IN MMC_NOTIFY_TYPE event, IN LPARAM arg, IN LPARAM param ) /*++ Routine Description: Notification handler. Arguments: LPDATAOBJECT lpDataObject : Data object MMC_NOTIFY_TYPE event : Notification event long arg : Event specific argument long param : Event specific parameter Return Value: HRESULT --*/ { HRESULT hr = E_NOTIMPL; if (lpDataObject == NULL) { switch (event) { case MMCN_PROPERTY_CHANGE: { TRACEEOLID("CInetMgrComponent::Notify:MMCN_PROPERTY_CHANGE"); hr = S_OK; if (m_spConsole != NULL) { CSnapInItem * pNode = (CSnapInItem *)param; LPDATAOBJECT pDataObject = NULL; if (pNode) { if (IsValidAddress( (const void*) pNode,sizeof(void*),FALSE)) { pNode->GetDataObject(&pDataObject, CCT_SCOPE); } } hr = m_spConsole->UpdateAllViews(pDataObject, param, 0); } } break; case MMCN_SNAPINHELP: break; default: break; } } else if (lpDataObject != DOBJ_CUSTOMWEB && lpDataObject != DOBJ_CUSTOMOCX) { // // Pass it on to IComponentImpl // hr = IComponentImpl::Notify(lpDataObject, event, arg, param); } else { hr = S_OK; } return hr; } HRESULT CInetMgrComponent::GetProperty( LPDATAOBJECT pDataObject, BSTR szPropertyName, BSTR* pbstrProperty) { HRESULT hr = S_OK; CSnapInItem * pItem = NULL; DATA_OBJECT_TYPES type; IDataObject * p = (IDataObject *)pDataObject; if (p == DOBJ_CUSTOMWEB || p == DOBJ_CUSTOMOCX) { return S_OK; } hr = m_pComponentData->GetDataClass((IDataObject *)pDataObject, &pItem, &type); // Find out CIISObject this belongs to and pass on the message CIISObject * pObject = (CIISObject *)pItem; if (SUCCEEDED(hr) && pObject != NULL) { hr = pObject->GetProperty(pDataObject,szPropertyName,pbstrProperty); } return hr; } HRESULT CInetMgrComponent::GetClassID( OUT CLSID * pClassID ) /*++ Routine Description: Get class ID for storage stream. Arguments: CLSID * pClassID : Returns class ID information Return Value: HRESULT --*/ { *pClassID = CLSID_InetMgr; return S_OK; } STDMETHODIMP CInetMgrComponent::GetHelpTopic(LPOLESTR *lpCompiledHelpFile) { return ::GetHelpTopic(lpCompiledHelpFile); } STDMETHODIMP CInetMgrComponent::GetLinkedTopics(LPOLESTR *lpCompiledHelpFile) { return S_FALSE; } HRESULT CInetMgrComponent::IsDirty() /*++ Routine Description: Check to see if we need to write to the cache. Arguments: None Return Value: S_OK if dirty, S_FALSE if not --*/ { TRACEEOLID("CInetMgrComponent::IsDirty"); return S_FALSE; } HRESULT CInetMgrComponent::InitNew( IN OUT IStorage * pStg ) /*++ Routine Description: Initialize storage stream. Arguments: IStorage * pStg : Storage stream Return Value: HRESULT --*/ { TRACEEOLID("CInetMgrComponent::InitNew"); return S_OK; } HRESULT CInetMgrComponent::Load( IN OUT IStorage * pStg ) /*++ Routine Description: Load from the storage stream Arguments: IStorage * pStg : Storage stream Return Value: HRESULT --*/ { TRACEEOLID("CInetMgrComponent::Load"); return S_OK; } /* virtual */ HRESULT STDMETHODCALLTYPE CInetMgrComponent::Save( IN OUT IStorage * pStgSave, IN BOOL fSameAsLoad ) /*++ Routine Description: Save to to the storage stream. Arguments: IStorage * pStgSave : Storage stream BOOL fSameAsLoad : TRUE if same as load Return Value: HRESULT --*/ { TRACEEOLID("CInetMgrComponent::Save"); return S_OK; } /* virtual */ HRESULT STDMETHODCALLTYPE CInetMgrComponent::SaveCompleted(IStorage * pStgNew) /*++ Routine Description: Save completed. Arguments: IStorage * pStgNew : Storage stream Return Value: HRESULT --*/ { TRACEEOLID("CInetMgrComponent::SaveCompleted"); return S_OK; } /* virtual */ HRESULT STDMETHODCALLTYPE CInetMgrComponent::HandsOffStorage() /*++ Routine Description: Hands off storage. Arguments: None Return Value: HRESULT --*/ { TRACEEOLID("CInetMgrComponent::HandsOffStorage"); return S_OK; } /* virtual */ HRESULT CInetMgrComponent::SetControlbar( IN LPCONTROLBAR lpControlBar ) /*++ Routine Description: Set/Reset the control bar Arguments: LPCONTROLBAR lpControlBar : Control bar pointer or NULL Return Value: HRESULT --*/ { HRESULT hr = S_OK; if (lpControlBar) { if (_lpControlBar){_lpControlBar.Release();_lpControlBar=NULL;} _lpControlBar = lpControlBar; // BUG:680625 if (_lpToolBar){_lpToolBar.Release();_lpToolBar=NULL;} if (_lpToolBar == NULL) { hr = ToolBar_Create(lpControlBar,this,(IToolbar **) &_lpToolBar); } } else { if (_lpControlBar != NULL && _lpToolBar != NULL) { _lpControlBar->Detach(_lpToolBar); } // // Release existing controlbar // if (_lpControlBar){_lpControlBar.Release();_lpControlBar=NULL;} } return hr; } /* virtual */ HRESULT CInetMgrComponent::ControlbarNotify( IN MMC_NOTIFY_TYPE event, IN LPARAM arg, IN LPARAM param ) /*++ Routine Description: Handle control bar notification message. Figure out the CIISObject selected, and pass the notification message off to it. Arguments: MMC_NOTIFY_TYPE event : Notification message long arg : Message specific argument long param : Message specific parameter Return Value: HRESULT --*/ { HRESULT hr = S_OK; CSnapInItem * pItem = NULL; DATA_OBJECT_TYPES type; BOOL fSelect = (BOOL)HIWORD(arg); BOOL fScope = (BOOL)LOWORD(arg); // // Special casing this is annoying... // // CODEWORK: Handle MMCN_HELP and others // if (event == MMCN_BTN_CLICK) { hr = m_pComponentData->GetDataClass((IDataObject *)arg, &pItem, &type); } else if (event == MMCN_SELECT) { IDataObject * p = (IDataObject *)param; if (p == DOBJ_CUSTOMWEB || p == DOBJ_CUSTOMOCX) { return S_OK; } hr = m_pComponentData->GetDataClass((IDataObject *)param, &pItem, &type); } // // Find out CIISObject this belongs to and pass on // the message // CIISObject * pObject = (CIISObject *)pItem; if (SUCCEEDED(hr) && pObject != NULL) { if (MMCN_SELECT == event) { arg = (LPARAM)(LPUNKNOWN *) &_lpControlBar; param = (LPARAM)(LPUNKNOWN *) &_lpToolBar; if (_lpControlBar) { if (_lpToolBar) { hr = _lpControlBar->Attach(TOOLBAR, _lpToolBar); } } } if (fSelect) { if (SUCCEEDED(hr)) { hr = pObject->ControlbarNotify(event, arg, param); } } } return hr; } /* virtual */ HRESULT CInetMgrComponent::Compare( IN RDCOMPARE * prdc, OUT int * pnResult ) /*++ Routine Description: Compare method used for sorting the result and scope panes. Arguments: RDCOMPARE * prdc : Compare structure int * pnResult : Returns result Return Value: HRESULT --*/ { if (!pnResult || !prdc || !prdc->prdch1->cookie || !prdc->prdch2->cookie) { ASSERT_MSG("Invalid parameter(s)"); return E_POINTER; } CIISObject * pObjectA = (CIISObject *)prdc->prdch1->cookie; CIISObject * pObjectB = (CIISObject *)prdc->prdch2->cookie; *pnResult = pObjectA->CompareResultPaneItem(pObjectB, prdc->nColumn); return S_OK; } /* virtual */ HRESULT CInetMgrComponent::CompareObjects( IN LPDATAOBJECT lpDataObjectA, IN LPDATAOBJECT lpDataObjectB ) /*++ Routine Description: Compare two data objects. This method is used to see if a property sheet for the given data object is already open Arguments: LPDATAOBJECT lpDataObjectA : A data object LPDATAOBJECT lpDataObjectB : B data object Return Value: S_OK if they match, S_FALSE otherwise --*/ { // // Pass it on to IComponentImpl // return IComponentImpl::CompareObjects(lpDataObjectA, lpDataObjectB); } // // CInetMgr Implementation // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /* static */ DWORD CInetMgr::_dwSignature = 0x3517; /* static */ LPCTSTR CInetMgr::_szStream = _T("CInetMgr"); HRESULT CInetMgr::GetProperty( LPDATAOBJECT pDataObject, BSTR szPropertyName, BSTR* pbstrProperty) { HRESULT hr = S_OK; CSnapInItem * pItem = NULL; DATA_OBJECT_TYPES type; IDataObject * p = (IDataObject *)pDataObject; if (p == DOBJ_CUSTOMWEB || p == DOBJ_CUSTOMOCX) { return S_OK; } hr = m_pComponentData->GetDataClass((IDataObject *)pDataObject, &pItem, &type); // Find out CIISObject this belongs to and pass on the message CIISObject * pObject = (CIISObject *)pItem; if (SUCCEEDED(hr) && pObject != NULL) { hr = pObject->GetProperty(pDataObject,szPropertyName,pbstrProperty); } return hr; } /* static */ void WINAPI CInetMgr::ObjectMain( IN bool bStarting ) /*++ Routine Description: CInetMgr main entry point Arguments: bool bStarting : TRUE if starting Return Value: None --*/ { TRACEEOLID("CInetMgr::ObjectMain:g_IISMMCInstanceCount=" << g_IISMMCInstanceCount); if (bStarting) { g_IISMMCComLoaded++; // Check regkey if debugging is okay to be turned on.. GetOutputDebugFlag(); // Get Special parameters used by the snapin... GetInetmgrParamFlag(); // // Register clipboard formats // CSnapInItem::Init(); CIISObject::Init(); ToolBar_Init(); g_OpenPropertySheetTracker.Init(); #if defined(_DEBUG) || DBG g_Debug_IISObject.Init(); #endif } else { g_OpenPropertySheetTracker.Clear(); #if defined(_DEBUG) || DBG g_GlobalConnections.Dump(); #endif g_GlobalConnections.Clear(); ToolBar_Destroy(); g_IISMMCComLoaded--; } } CInetMgr::CInetMgr() : m_pConsoleNameSpace(NULL),m_pConsole(NULL) { TRACEEOLID("CInetMgr::CInetMgr"); // // Initialize strings we will be using // for the lifetime of the snapin // m_pNode = new CIISRoot; ASSERT_PTR(m_pNode); m_pComponentData = this; CIISObject * pNode = dynamic_cast(m_pNode); if (pNode) { pNode->AddRef(); } } CInetMgr::~CInetMgr() { TRACEEOLID("CInetMgr::~CInetMgr:g_IISMMCInstanceCount=" << g_IISMMCInstanceCount); // // Clean up the root node // CIISObject * pNode = dynamic_cast(m_pNode); if (pNode) { pNode->Release(); } m_pNode = NULL; } HRESULT CInetMgr::Destroy() { TRACEEOLID("CInetMgr::Destroy:g_IISMMCInstanceCount=" << g_IISMMCInstanceCount); #if defined(_DEBUG) || DBG // check if we leaked anything. g_Debug_IISObject.Dump(1); #endif return S_OK; } HRESULT CInetMgr::Initialize( IN LPUNKNOWN lpUnknown ) /*++ Routine Description: Initialize the snap-in Arguments: LPUNKNOWN lpUnknown : IUnknown Return Value: HRESULT --*/ { TRACEEOLID("CInetMgr::Initialize"); AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = IComponentDataImpl::Initialize(lpUnknown); if (FAILED(hr)) { return hr; } // // Query the interfaces for console name space and console // CComQIPtr lpConsoleNameSpace(lpUnknown); if (!lpConsoleNameSpace) { TRACEEOLID("failed to query console name space interface"); return hr; } m_pConsoleNameSpace = lpConsoleNameSpace; CComQIPtr lpConsole(lpConsoleNameSpace); if (!lpConsole) { TRACEEOLID("failed to query console interface"); return hr; } m_pConsole = lpConsole; CIISObject * pNode = dynamic_cast(m_pNode); if (pNode) { pNode->SetConsoleData(m_pConsoleNameSpace,m_pConsole); } CComPtr lpImageList; hr = m_spConsole->QueryScopeImageList(&lpImageList); if (FAILED(hr) || lpImageList == NULL) { TRACEEOLID("IConsole::QueryScopeImageList failed"); return E_UNEXPECTED; } return CIISObject::SetImageList(lpImageList); } HRESULT CInetMgr::OnPropertyChange(LPARAM arg, LPARAM param) { HRESULT hr = S_OK; if (param != 0) { CSnapInItem * pNode = (CSnapInItem *)param; LPDATAOBJECT pDataObject = NULL; if (IsValidAddress( (const void*) pNode,sizeof(void*),FALSE)) { pNode->GetDataObject(&pDataObject, CCT_SCOPE); CIISObject * pObj = dynamic_cast(pNode); ASSERT(pNode != NULL); hr = m_spConsole->UpdateAllViews(pDataObject, param, pObj->m_UpdateFlag); } } return hr; } HRESULT CInetMgr::Notify( LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param ) { HRESULT hr = S_OK; if (lpDataObject == NULL) { switch (event) { case MMCN_PROPERTY_CHANGE: TRACEEOLID("CInetMgr::Notify:MMCN_PROPERTY_CHANGE"); hr = OnPropertyChange(arg, param); break; case MMCN_SNAPINHELP: break; default: break; } } else { hr = IComponentDataImpl::Notify( lpDataObject, event, arg, param); } return hr; } HRESULT CInetMgr::GetClassID(CLSID * pClassID) /*++ Routine Description: Get class ID for storage stream Arguments: CLSID * pClassID : Returns class ID information Return Value: HRESULT --*/ { *pClassID = CLSID_InetMgr; return S_OK; } STDMETHODIMP CInetMgr::GetHelpTopic(LPOLESTR *lpCompiledHelpFile) { return ::GetHelpTopic(lpCompiledHelpFile); } STDMETHODIMP CInetMgr::GetLinkedTopics(LPOLESTR *lpCompiledHelpFile) { return S_FALSE; } HRESULT CInetMgr::IsDirty() /*++ Routine Description: Check to see if we need to write to the cache. Arguments: None Return Value: S_OK if dirty, S_FALSE if not --*/ { TRACEEOLID("CInetMgr::IsDirty"); ASSERT_PTR(m_pNode); if (IsExtension()) { return FALSE; } else { return ((CIISRoot *)m_pNode)->m_scServers.IsDirty() ? S_OK : S_FALSE; } } HRESULT CInetMgr::InitNew(IStorage * pStg) /*++ Routine Description: Initialize new storage stream (newly created console file) Arguments: IStorage * pStg : Storage stream Return Value: HRESULT --*/ { TRACEEOLID("CInetMgr::InitNew"); // // We could create the stream here, but it's just as easy to // create it inside Save(). // return S_OK; } HRESULT CInetMgr::Load(IStorage * pStg) /*++ Routine Description: Load machine cache from the storage stream. Arguments: IStorage * pStg : Storage stream Return Value: HRESULT --*/ { AFX_MANAGE_STATE(AfxGetStaticModuleState()); TRACEEOLID("CInetMgr::Load"); if (IsExtension()) { return S_OK; } ASSERT_READ_WRITE_PTR(pStg); DWORD cBytesRead; DWORD dw; HRESULT hr = S_OK; CIISServerCache & cache = ((CIISRoot *)m_pNode)->m_scServers; IStream * pStream = NULL; ASSERT(cache.IsEmpty()); do { hr = pStg->OpenStream( _szStream, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0L, &pStream ); if (FAILED(hr)) { break; } // // Read and verify the signature // hr = pStream->Read(&dw, sizeof(dw), &cBytesRead); ASSERT(SUCCEEDED(hr) && cBytesRead == sizeof(dw)); if (FAILED(hr)) { break; } if (dw != _dwSignature) { hr = HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT); break; } // // Read number of machines in the cache // DWORD cMachines; hr = pStream->Read(&cMachines, sizeof(cMachines), &cBytesRead); ASSERT(SUCCEEDED(hr) && cBytesRead == sizeof(cMachines)); if (FAILED(hr)) { break; } TRACEEOLID("Reading " << cMachines << " machines from cache"); CIISMachine * pMachine; // // Read each machine from the cache // for (dw = 0; dw < cMachines; ++dw) { hr = CIISMachine::ReadFromStream(pStream, &pMachine,m_pConsoleNameSpace,m_pConsole); if (FAILED(hr)) { break; } pMachine->AddRef(); if (!cache.Add(pMachine)) { pMachine->Release(); } } } while(FALSE); if (pStream) { pStream->Release(); } if (hr == STG_E_FILENOTFOUND) { // // Stream was not initialized. This is acceptable. // hr = S_OK; } // // Mark cache as clean // cache.SetDirty(FALSE); return hr; } /* virtual */ HRESULT STDMETHODCALLTYPE CInetMgr::Save(IStorage * pStgSave, BOOL fSameAsLoad) /*++ Routine Description: Save computer cache to to the storage stream. Arguments: IStorage * pStgSave : Storage stream BOOL fSameAsLoad : TRUE if same as load Return Value: HRESULT --*/ { AFX_MANAGE_STATE(AfxGetStaticModuleState()); TRACEEOLID("CInetMgr::Save"); if (IsExtension()) { return S_OK; } // // Write the computer names to the cache // ASSERT_READ_WRITE_PTR(pStgSave); DWORD cBytesWritten; HRESULT hr = STG_E_CANTSAVE; IStream * pStream = NULL; CIISServerCache & cache = ((CIISRoot *)m_pNode)->m_scServers; do { hr = pStgSave->CreateStream( _szStream, STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0L, 0L, &pStream ); if (FAILED(hr)) { break; } // // Write the signature // hr = pStream->Write(&_dwSignature, sizeof(_dwSignature), &cBytesWritten); ASSERT(SUCCEEDED(hr) && cBytesWritten == sizeof(_dwSignature)); if (FAILED(hr)) { break; } // // Write number of entries. // INT_PTR dw = cache.GetCount(); hr = pStream->Write(&dw, sizeof(dw), &cBytesWritten); ASSERT(SUCCEEDED(hr) && cBytesWritten == sizeof(dw)); if (FAILED(hr)) { break; } // // Write each string -- but write them in reverse // order to improve our sort performance when we load // the cache. // CIISMachine * pMachine = cache.GetLast(); while(pMachine) { hr = pMachine->WriteToStream(pStream); if (FAILED(hr)) { break; } pMachine = cache.GetPrev(); } } while(FALSE); if (pStream) { pStream->Release(); } if (SUCCEEDED(hr)) { // // Mark cache as clean // cache.SetDirty(FALSE); } return hr; } /* virtual */ HRESULT STDMETHODCALLTYPE CInetMgr::SaveCompleted(IStorage * pStgNew) /*++ Routine Description: Save completed notification. Arguments: IStorage * pStgNew : Storage stream Return Value: HRESULT --*/ { TRACEEOLID("CInetMgr::SaveCompleted"); // // Nothing to do // return S_OK; } /* virtual */ HRESULT STDMETHODCALLTYPE CInetMgr::HandsOffStorage() /*++ Routine Description: Hands off storage. Arguments: None Return Value: HRESULT --*/ { TRACEEOLID("CInetMgr::HandsOffStorage"); // // Nothing to do // return S_OK; } /* virtual */ HRESULT CInetMgr::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB) /*++ Routine Description: Compare two data objects. This method is used by MMC to see if a property sheet for the given data object is already open. Arguments: LPDATAOBJECT lpDataObjectA : A data object LPDATAOBJECT lpDataObjectB : B data object Return Value: S_OK if they match, S_FALSE otherwise --*/ { HRESULT hr = E_POINTER; do { if (!lpDataObjectA || !lpDataObjectB) { TRACEEOLID("CInetMgr:IComponentData::CompareObjects called with NULL ptr"); break; } CSnapInItem * pItemA; CSnapInItem * pItemB; DATA_OBJECT_TYPES type; hr = m_pComponentData->GetDataClass(lpDataObjectA, &pItemA, &type); if (SUCCEEDED(hr)) { hr = m_pComponentData->GetDataClass(lpDataObjectB, &pItemB, &type); } if (FAILED(hr)) { break; } if (!pItemA || !pItemB) { hr = E_POINTER; break; } if (pItemA == pItemB) { // // Literally the same object // hr = S_OK; break; } CIISObject * pObjectA = (CIISObject *)pItemA; CIISObject * pObjectB = (CIISObject *)pItemB; hr = !pObjectA->CompareScopeItem(pObjectB) ? S_OK : S_FALSE; } while(FALSE); return hr; } HRESULT CInetMgr::GetDataClass( IDataObject * pDataObject, CSnapInItem ** ppItem, DATA_OBJECT_TYPES * pType) { if (ppItem == NULL) return E_POINTER; if (pType == NULL) return E_POINTER; *ppItem = NULL; *pType = CCT_UNINITIALIZED; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; FORMATETC formatetc = { CSnapInItem::m_CCF_NODETYPE, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; stgmedium.hGlobal = GlobalAlloc(0, sizeof(GUID)); if (stgmedium.hGlobal == NULL) return E_OUTOFMEMORY; HRESULT hr = pDataObject->GetDataHere(&formatetc, &stgmedium); if (FAILED(hr)) { GlobalFree(stgmedium.hGlobal); return hr; } GUID guid; memcpy(&guid, stgmedium.hGlobal, sizeof(GUID)); GlobalFree(stgmedium.hGlobal); hr = S_OK; if (IsEqualGUID(guid, cCompMgmtService)) { if (!IsExtension()) { CIISRoot * pRootExt = new CIISRoot; if (pRootExt == NULL) { return E_OUTOFMEMORY; } hr = pRootExt->InitAsExtension(pDataObject); if (FAILED(hr)) { return hr; } pRootExt->SetConsoleData(m_pConsoleNameSpace,m_pConsole); if (m_pNode != NULL) { CIISObject * pNode = dynamic_cast(m_pNode); if (pNode->GetConsoleNameSpace()) { pRootExt->SetConsoleData(pNode->GetConsoleNameSpace(),pNode->GetConsole()); } pNode->Release(); } g_IISMMCInstanceCountExtensionMode++; m_pNode = pRootExt; } *ppItem = m_pNode; return hr; } return CSnapInItem::GetDataClass(pDataObject, ppItem, pType); }; BOOL CInetMgr::IsExtension() { ASSERT(m_pNode != NULL); CIISRoot * pRoot = (CIISRoot *)m_pNode; return pRoot->IsExtension(); } // // CInetMrgAbout Class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HRESULT CInetMgrAbout::GetStringHelper(UINT nStringID, LPOLESTR * lpString) /*++ Routine Description: Get resource string helper function. Called from inline string fetcher methods. Arguments: UINT nStringID : String ID from local resource segment LPOLESTR * lpString : Returns the string Return Value: HRESULT --*/ { USES_CONVERSION; TCHAR szBuf[256]; if (::LoadString( _Module.GetResourceInstance(), nStringID, szBuf, 256) == 0) { return E_FAIL; } *lpString = (LPOLESTR)::CoTaskMemAlloc( (lstrlen(szBuf) + 1) * sizeof(OLECHAR) ); if (*lpString == NULL) { return E_OUTOFMEMORY; } ::ocscpy(*lpString, T2OLE(szBuf)); return S_OK; } HRESULT CInetMgrAbout::GetSnapinImage(HICON * hAppIcon) /*++ Routine Description: Get the icon for this snapin. Arguments: HICON * hAppIcon : Return handle to the icon Return Value: HRESULT --*/ { if (hAppIcon == NULL) { return E_POINTER; } m_hSnapinIcon = ::LoadIcon( _Module.GetModuleInstance(), MAKEINTRESOURCE(IDI_INETMGR) ); *hAppIcon = m_hSnapinIcon; ASSERT(*hAppIcon != NULL); return (*hAppIcon != NULL) ? S_OK : E_FAIL; } HRESULT CInetMgrAbout::GetStaticFolderImage( HBITMAP * phSmallImage, HBITMAP * phSmallImageOpen, HBITMAP * phLargeImage, COLORREF * prgbMask ) /*++ Routine Description: Get the static folder images. Arguments: HBITMAP * phSmallImage : Small folder HBITMAP * phSmallImageOpen : Small open folder HBITMAP * phLargeImage : Large image COLORREF * prgbMask : Mask Return Value: HRESULT --*/ { if (!phSmallImage || !phSmallImageOpen || !phLargeImage || !prgbMask) { return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); } m_hSmallImage = (HBITMAP)::LoadImage( _Module.GetModuleInstance(), MAKEINTRESOURCE(IDB_SMALL_ROOT), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR ); m_hLargeImage = (HBITMAP)::LoadImage( _Module.GetModuleInstance(), MAKEINTRESOURCE(IDB_LARGE_ROOT), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR ); *phSmallImage = m_hSmallImage; *phSmallImageOpen = m_hSmallImage; *phLargeImage = m_hLargeImage; *prgbMask = RGB_BK_IMAGES; return *phSmallImage && *phLargeImage ? S_OK : E_FAIL; } CInetMgrAbout::~CInetMgrAbout() { if (m_hSmallImage != NULL) { ::DeleteObject(m_hSmallImage); } if (m_hLargeImage != NULL) { ::DeleteObject(m_hLargeImage); } if (m_hSnapinIcon != NULL) { ::DestroyIcon(m_hSnapinIcon); } } #if 0 HRESULT ExtractComputerNameExt(IDataObject * pDataObject, CString& strComputer) { // // Find the computer name from the ComputerManagement snapin // CLIPFORMAT CCF_MyComputMachineName = (CLIPFORMAT)RegisterClipboardFormat(MYCOMPUT_MACHINE_NAME); STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; FORMATETC formatetc = { CCF_MyComputMachineName, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; // // Allocate memory for the stream // int len = MAX_PATH; stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, len); if(stgmedium.hGlobal == NULL) return ERROR_NOT_ENOUGH_MEMORY; HRESULT hr = pDataObject->GetDataHere(&formatetc, &stgmedium); ASSERT(SUCCEEDED(hr)); // // Get the computer name // strComputer = (LPTSTR)stgmedium.hGlobal; GlobalFree(stgmedium.hGlobal); return hr; } HRESULT CCompMgrExtData::Init(IDataObject * pDataObject) { TRACEEOLID("CCompMgrExtData::Init:g_IISMMCInstanceCount=" << g_IISMMCInstanceCount); return ExtractComputerNameExt(pDataObject, m_ExtMachineName); } HRESULT STDMETHODCALLTYPE CCompMgrExtData::Notify( MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param, IComponentData* pComponentData, IComponent* pComponent, DATA_OBJECT_TYPES type) { TRACEEOLID("CCompMgrExtData::Notify"); CError err; CComPtr pConsole; CComQIPtr pHeader; CComQIPtr pResultData; if (pComponentData != NULL) { pConsole = ((CInetMgr *)pComponentData)->m_spConsole; } else { pConsole = ((CInetMgrComponent *)pComponent)->m_spConsole; } CComQIPtr pScope = pConsole; switch (event) { case MMCN_EXPAND: err = EnumerateScopePane((HSCOPEITEM)param, pScope); break; default: err = CSnapInItemImpl::Notify(event, arg, param, pComponentData, pComponent, type); break; } return err; } HRESULT CCompMgrExtData::EnumerateScopePane(HSCOPEITEM hParent, IConsoleNameSpace2 * pScope) { TRACEEOLID("CCompMgrExtData::EnumerateScopePane"); CError err; ASSERT_PTR(pScope); DWORD dwMask = SDI_PARENT; SCOPEDATAITEM scopeDataItem; ::ZeroMemory(&scopeDataItem, sizeof(SCOPEDATAITEM)); scopeDataItem.mask = SDI_STR | SDI_IMAGE | SDI_CHILDREN | SDI_OPENIMAGE | SDI_PARAM | dwMask; scopeDataItem.displayname = MMC_CALLBACK; scopeDataItem.nImage = scopeDataItem.nOpenImage = MMC_IMAGECALLBACK;//QueryImage(); scopeDataItem.lParam = (LPARAM)this; scopeDataItem.relativeID = hParent; scopeDataItem.cChildren = 1; err = pScope->InsertItem(&scopeDataItem); if (err.Succeeded()) { // // Cache the scope item handle // ASSERT(m_hScopeItem == NULL); m_hScopeItem = scopeDataItem.ID; // MMC_IMAGECALLBACK doesn't work in InsertItem. Update it here. scopeDataItem.mask = SDI_IMAGE | SDI_OPENIMAGE; err = pScope->SetItem(&scopeDataItem); } return err; } #endif