/*++ Copyright (C) Microsoft Corporation Module Name: componet.cpp Abstract: This module implemets CComponent class Author: William Hsieh (williamh) created Revision History: --*/ #include "devmgr.h" #include "factory.h" #include // // ctor and dtor // CComponent::CComponent( CComponentData* pComponentData ) { m_pComponentData = pComponentData; m_pHeader = NULL; m_pConsole = NULL; m_pResult = NULL; m_pConsoleVerb = NULL; m_pCurFolder = NULL; m_pPropSheetProvider = NULL; m_pDisplayHelp = NULL; m_Dirty = FALSE; m_pControlbar = NULL; m_pToolbar = NULL; // // Increment object count(used by CanUnloadNow) // ::InterlockedIncrement(&CClassFactory::s_Objects); m_Ref = 1; } CComponent::~CComponent() { // // Decrement object count(used by CanUnloadNow) // ASSERT( 0 != CClassFactory::s_Objects ); ::InterlockedDecrement(&CClassFactory::s_Objects); } // // IUNKNOWN interface // ULONG CComponent::AddRef() { return ::InterlockedIncrement(&m_Ref); } ULONG CComponent::Release() { ASSERT( 0 != m_Ref ); ULONG cRef = ::InterlockedDecrement(&m_Ref); if ( 0 == cRef ) { delete this; } return cRef; } STDMETHODIMP CComponent::QueryInterface( REFIID riid, void** ppv ) { if (!ppv) { return E_INVALIDARG; } HRESULT hr = S_OK; if (IsEqualIID(riid, IID_IUnknown)) { *ppv = (IUnknown*)(IComponent*)this; } else if (IsEqualIID(riid, IID_IComponent)) { *ppv = (IComponent*)this; } else if (IsEqualIID(riid, IID_IResultDataCompare)) { *ppv = (IResultDataCompare*)this; } else if (IsEqualIID(riid, IID_IExtendContextMenu)) { *ppv = (IExtendContextMenu*)this; } else if (IsEqualIID(riid, IID_IExtendControlbar)) { *ppv = (IExtendControlbar*)this; } else if (IsEqualIID(riid, IID_IExtendPropertySheet)) { *ppv = (IExtendPropertySheet*)this; } else if (IsEqualIID(riid, IID_IPersistStream)) { *ppv = (IPersistStream*)this; } else if (IsEqualIID(riid, IID_ISnapinCallback)) { *ppv = (ISnapinCallback*)this; } else { *ppv = NULL; hr = E_NOINTERFACE; } if (SUCCEEDED(hr)) { AddRef(); } return hr; } // // IComponent interface implementation // STDMETHODIMP CComponent::GetResultViewType( MMC_COOKIE cookie, LPOLESTR* ppViewType, long* pViewOptions ) { if (!ppViewType || !pViewOptions) { return E_INVALIDARG; } try { CFolder* pFolder; pFolder = FindFolder(cookie); if (pFolder) { return pFolder->GetResultViewType(ppViewType, pViewOptions); } else { return S_OK; } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); return S_FALSE; } } STDMETHODIMP CComponent::Initialize( LPCONSOLE lpConsole ) { HRESULT hr; if (!lpConsole) { return E_INVALIDARG; } m_pConsole = lpConsole; lpConsole->AddRef(); hr = lpConsole->QueryInterface(IID_IHeaderCtrl, (void**)&m_pHeader); if (SUCCEEDED(hr)) { lpConsole->SetHeader(m_pHeader); hr = lpConsole->QueryInterface(IID_IResultData, (void**)&m_pResult); } if (SUCCEEDED(hr)) { hr = lpConsole->QueryConsoleVerb(&m_pConsoleVerb); } if (SUCCEEDED(hr)) { hr = lpConsole->QueryInterface(IID_IPropertySheetProvider, (void**)&m_pPropSheetProvider); } if (SUCCEEDED(hr)) { hr = lpConsole->QueryInterface(IID_IDisplayHelp, (void**)&m_pDisplayHelp); } if (FAILED(hr)) { TRACE((TEXT("CComponent::Initialize failed\n"))); } return hr; } #if DBG TCHAR *mmcNotifyStr[] = { TEXT("UNKNOWN"), TEXT("ACTIVATE"), TEXT("ADD_IMAGES"), TEXT("BTN_CLICK"), TEXT("CLICK"), TEXT("COLUMN_CLICK"), TEXT("CONTEXTMENU"), TEXT("CUTORMOVE"), TEXT("DBLCLICK"), TEXT("DELETE"), TEXT("DESELECT_ALL"), TEXT("EXPAND"), TEXT("HELP"), TEXT("MENU_BTNCLICK"), TEXT("MINIMIZED"), TEXT("PASTE"), TEXT("PROPERTY_CHANGE"), TEXT("QUERY_PASTE"), TEXT("REFRESH"), TEXT("REMOVE_CHILDREN"), TEXT("RENAME"), TEXT("SELECT"), TEXT("SHOW"), TEXT("VIEW_CHANGE"), TEXT("SNAPINHELP"), TEXT("CONTEXTHELP"), TEXT("INITOCX"), TEXT("FILTER_CHANGE"), TEXT("FILTERBTN_CLICK"), TEXT("RESTORE_VIEW"), TEXT("PRINT"), TEXT("PRELOAD"), TEXT("LISTPAD"), TEXT("EXPANDSYNC") }; #endif STDMETHODIMP CComponent::Notify( LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param ) { HRESULT hr; INTERNAL_DATA tID; #if DBG UINT i = event - MMCN_ACTIVATE + 1; if (event > MMCN_EXPANDSYNC || event < MMCN_ACTIVATE) { i = 0; } //TRACE((TEXT("Componet:Notify, event = %lx %s\n"), event, mmcNotifyStr[i])); #endif try { if (DOBJ_CUSTOMOCX == lpDataObject) { return OnOcxNotify(event, arg, param); } hr = ExtractData(lpDataObject, CDataObject::m_cfSnapinInternal, (PBYTE)&tID, sizeof(tID)); if (SUCCEEDED(hr)) { switch(event) { case MMCN_ACTIVATE: hr = OnActivate(tID.cookie, arg, param); break; case MMCN_VIEW_CHANGE: hr = OnViewChange(tID.cookie, arg, param); break; case MMCN_SHOW: hr = OnShow(tID.cookie, arg, param); break; case MMCN_CLICK: hr = OnResultItemClick(tID.cookie, arg, param); break; case MMCN_DBLCLICK: hr = OnResultItemDblClick(tID.cookie, arg, param); break; case MMCN_MINIMIZED: hr = OnMinimize(tID.cookie, arg, param); break; case MMCN_BTN_CLICK: hr = OnBtnClick(tID.cookie, arg, param); break; case MMCN_SELECT: hr = OnSelect(tID.cookie, arg, param); break; case MMCN_ADD_IMAGES: hr = OnAddImages(tID.cookie, (IImageList*)arg, param); break; case MMCN_RESTORE_VIEW: hr = OnRestoreView(tID.cookie, arg, param); break; case MMCN_CONTEXTHELP: hr = OnContextHelp(tID.cookie, arg, param); break; default: hr = S_OK; break; } } else { if (MMCN_ADD_IMAGES == event) { OnAddImages(0, (IImageList*)arg, (HSCOPEITEM)param); } else if (MMCN_PROPERTY_CHANGE == event) { CNotifyRebootRequest* pNRR = (CNotifyRebootRequest*)param; if (pNRR) { PromptForRestart(pNRR->m_hWnd ? pNRR->m_hWnd : m_pComponentData->m_hwndMain, pNRR->m_RestartFlags, pNRR->m_StringId); pNRR->Release(); } } } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); hr = E_OUTOFMEMORY; } return hr; } STDMETHODIMP CComponent::Destroy( MMC_COOKIE cookie ) { // // cookie must point to the static node // ASSERT(0 == cookie); try { DetachAllFoldersFromMachine(); DestroyFolderList(cookie); if (m_pToolbar) { m_pToolbar->Release(); } if (m_pControlbar) { m_pControlbar->Release(); } // // Release the interfaces that we QI'ed // if (m_pConsole != NULL) { // // Tell the console to release the header control interface // m_pConsole->SetHeader(NULL); m_pHeader->Release(); m_pResult->Release(); m_pConsoleVerb->Release(); m_pDisplayHelp->Release(); // // Release the IFrame interface last // m_pConsole->Release(); } if (m_pPropSheetProvider) { m_pPropSheetProvider->Release(); } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); } return S_OK; } STDMETHODIMP CComponent::QueryDataObject( MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject ) { try { ASSERT(m_pComponentData); // // Delegate to IComponentData // return m_pComponentData->QueryDataObject(cookie, type, ppDataObject); } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); return E_OUTOFMEMORY; } } STDMETHODIMP CComponent::GetDisplayInfo( LPRESULTDATAITEM pResultDataItem ) { try { CFolder* pFolder = FindFolder(pResultDataItem->lParam); if (pFolder) { return pFolder->GetDisplayInfo(pResultDataItem); } else { return S_OK; } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); return E_OUTOFMEMORY; } } STDMETHODIMP CComponent::CompareObjects( LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB ) { try { ASSERT(m_pComponentData); // // Delegate to ComponentData // return m_pComponentData->CompareObjects(lpDataObjectA, lpDataObjectB); } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); return E_OUTOFMEMORY; } } /////////////////////////////////////////////////////////////////////////// /// IResultDataCompare implementation /// // This compare is used to sort the item's in the listview. // lUserParam - user param passed in when IResultData::Sort() was called. // cookieA -- first item // cookieB -- second item // pnResult contains the column on entry. This function has the compared // result in the location pointed by this parameter. // the valid compare results are: // -1 if cookieA "<" cookieB // 0 if cookieA "==" cookieB // 1 if cookieA ">" cookieB // // STDMETHODIMP CComponent::Compare( LPARAM lUserParam, MMC_COOKIE cookieA, MMC_COOKIE cookieB, int* pnResult ) { if (!pnResult) { return E_INVALIDARG; } HRESULT hr; try { int nCol = *pnResult; CFolder* pFolder = (CFolder*)lUserParam; if (pFolder) { hr = pFolder->Compare(cookieA, cookieB, nCol, pnResult); } else { hr = m_pCurFolder->Compare(cookieA, cookieB, nCol, pnResult); } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); hr = E_OUTOFMEMORY; } return hr; } //////////////////////////////////////////////////////////////////////////// /// Snapin's IExtendContextMenu implementation -- delegate to IComponentData //// // Note that IComponentData also has its own IExtendContextMenu // interface implementation. The difference is that // IComponentData only deals with scope items while we only // deal with result item except for cutomer view menu. // // STDMETHODIMP CComponent::AddMenuItems( LPDATAOBJECT lpDataObject, LPCONTEXTMENUCALLBACK pCallback, long* pInsertionAllowed ) { HRESULT hr; INTERNAL_DATA tID; try { // // If lpDataObject is DOBJ_CUSTOMOCX then the user is viewing // the Action menu. // if (DOBJ_CUSTOMOCX == lpDataObject) { ASSERT(m_pCurFolder); hr = m_pCurFolder->m_pScopeItem->AddMenuItems(pCallback, pInsertionAllowed); } // // If we have a valid cookie then the user is using the context menu // or the View menu // else { hr = ExtractData(lpDataObject, CDataObject::m_cfSnapinInternal, reinterpret_cast(&tID), sizeof(tID) ); if (SUCCEEDED(hr)) { ASSERT(m_pCurFolder); hr = m_pCurFolder->AddMenuItems(GetActiveCookie(tID.cookie), pCallback, pInsertionAllowed ); } } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); hr = E_OUTOFMEMORY; } return hr; } STDMETHODIMP CComponent::Command( long nCommandID, LPDATAOBJECT lpDataObject ) { INTERNAL_DATA tID; HRESULT hr; try { // // Menu item from the Action menu // if (DOBJ_CUSTOMOCX == lpDataObject) { ASSERT(m_pCurFolder); hr = m_pCurFolder->m_pScopeItem->MenuCommand(nCommandID); } // // Context menu item or View menu item // else { hr = ExtractData(lpDataObject, CDataObject::m_cfSnapinInternal, (PBYTE)&tID, sizeof(tID)); if (SUCCEEDED(hr)) { ASSERT(m_pCurFolder); hr = m_pCurFolder->MenuCommand(GetActiveCookie(tID.cookie), nCommandID); } } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); hr = E_OUTOFMEMORY; } return hr; } /////////////////////////////////////////////////////////////////////////////// // IExtendControlbar implementation // MMCBUTTON g_SnapinButtons[] = { { 0, IDM_REFRESH, TBSTATE_ENABLED, TBSTYLE_BUTTON, (BSTR)IDS_BUTTON_REFRESH, (BSTR)IDS_TOOLTIP_REFRESH }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, NULL, NULL }, { 4, IDM_UPDATEDRIVER, TBSTATE_ENABLED, TBSTYLE_BUTTON, (BSTR)IDS_BUTTON_UPDATEDRIVER, (BSTR)IDS_TOOLTIP_UPDATEDRIVER }, { 2, IDM_REMOVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, (BSTR)IDS_BUTTON_REMOVE, (BSTR)IDS_TOOLTIP_REMOVE }, { 1, IDM_ENABLE, TBSTATE_ENABLED, TBSTYLE_BUTTON, (BSTR)IDS_BUTTON_ENABLE, (BSTR)IDS_TOOLTIP_ENABLE }, { 3, IDM_DISABLE, TBSTATE_ENABLED, TBSTYLE_BUTTON, (BSTR)IDS_BUTTON_DISABLE, (BSTR)IDS_TOOLTIP_DISABLE }, }; #define CBUTTONS_ARRAY ARRAYLEN(g_SnapinButtons) String* g_astrButtonStrings = NULL; // dynamic array of Strings BOOL g_bLoadedStrings = FALSE; STDMETHODIMP CComponent::SetControlbar( LPCONTROLBAR pControlbar ) { if (pControlbar != NULL) { // // Hold on to the controlbar interface. // if (m_pControlbar) { m_pControlbar->Release(); } m_pControlbar = pControlbar; m_pControlbar->AddRef(); HRESULT hr = S_FALSE; if (!m_pToolbar) { // // Create the Toolbar // hr = m_pControlbar->Create(TOOLBAR, this, reinterpret_cast(&m_pToolbar)); ASSERT(SUCCEEDED(hr)); // // Add the bitmap // HBITMAP hBitmap = ::LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_TOOLBAR)); hr = m_pToolbar->AddBitmap(4, hBitmap, 16, 16, RGB(255, 0, 255)); ASSERT(SUCCEEDED(hr)); if (!g_bLoadedStrings) { // // Load strings // g_astrButtonStrings = new String[2*CBUTTONS_ARRAY]; for (UINT i = 0; i < CBUTTONS_ARRAY; i++) { if (g_astrButtonStrings && g_SnapinButtons[i].lpButtonText && g_astrButtonStrings[i*2].LoadString(g_hInstance, (UINT)((ULONG_PTR)g_SnapinButtons[i].lpButtonText))) { g_SnapinButtons[i].lpButtonText = const_cast((LPCTSTR)(g_astrButtonStrings[i*2])); } else { g_SnapinButtons[i].lpButtonText = NULL; } if (g_astrButtonStrings && g_SnapinButtons[i].lpTooltipText && g_astrButtonStrings[(i*2)+1].LoadString(g_hInstance, (UINT)((ULONG_PTR)g_SnapinButtons[i].lpTooltipText))) { g_SnapinButtons[i].lpTooltipText = const_cast((LPCTSTR)(g_astrButtonStrings[(i*2)+1])); } else { g_SnapinButtons[i].lpTooltipText = NULL; } } g_bLoadedStrings = TRUE; } // // Add the buttons to the toolbar // hr = m_pToolbar->AddButtons(CBUTTONS_ARRAY, g_SnapinButtons); ASSERT(SUCCEEDED(hr)); } } return S_OK; } STDMETHODIMP CComponent::ControlbarNotify( MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param ) { switch (event) { case MMCN_BTN_CLICK: // // arg - Data object of the currently selected scope or result pane item. // param - CmdID of the button. // switch (param) { case IDM_REFRESH: case IDM_ENABLE: case IDM_REMOVE: case IDM_DISABLE: case IDM_UPDATEDRIVER: // // The arg parameter is supposed to be the data object of the // currently selected scope or result pane item, but it seems // to always passes 0xFFFFFFFF. So the ScopeItem MenuCommand is // used because it uses the selected cookie instead. // // Handle toolbar button requests. // return m_pCurFolder->m_pScopeItem->MenuCommand((LONG)param); default: break; } break; case MMCN_SELECT: // // param - Data object of the item being selected. // For select, if the cookie has toolbar items attach the toolbar. // Otherwise detach the toolbar. // HRESULT hr; if (LOWORD(arg)) { // // LOWORD(arg) being set indicated this is for the scope pane item. // if (HIWORD(arg)) { // // Detach the Controlbar. // hr = m_pControlbar->Detach(reinterpret_cast(m_pToolbar)); ASSERT(SUCCEEDED(hr)); } else { // // Attach the Controlbar. // hr = m_pControlbar->Attach(TOOLBAR, reinterpret_cast(m_pToolbar)); ASSERT(SUCCEEDED(hr)); } } break; default: break; } return S_OK; } // // This function updates the toolbar buttons based on the selected cookie type. // HRESULT CComponent::UpdateToolbar( CCookie* pCookie ) { if (!m_pToolbar) { return S_OK; } // // Everything is hidden by default // BOOL fRemoveHidden = TRUE; BOOL fRefreshHidden = TRUE; BOOL fUpdateHidden = TRUE; BOOL fDisableHidden = TRUE; BOOL fEnableHidden = TRUE; switch (pCookie->GetType()) { case COOKIE_TYPE_RESULTITEM_DEVICE: case COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ: case COOKIE_TYPE_RESULTITEM_RESOURCE_DMA: case COOKIE_TYPE_RESULTITEM_RESOURCE_IO: case COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY: if(m_pComponentData->m_pMachine->IsLocal() && g_IsAdmin) { CDevice* pDevice = NULL; CClass* pClass; if (COOKIE_TYPE_RESULTITEM_DEVICE == pCookie->GetType()) { pDevice = (CDevice*)pCookie->GetResultItem(); } else { // // This is a resource item, get the pointer for the device // object from the resource object. // CResource* pResource = (CResource*) pCookie->GetResultItem(); if (pResource) { pDevice = pResource->GetDevice(); } } if (pDevice) { pClass = pDevice->GetClass(); // // Device can be disabled // if (pDevice->IsDisableable()) { if (pDevice->IsStateDisabled()) { fEnableHidden = FALSE; } else { fDisableHidden = FALSE; } } // // Device cannot be disabled // else { // // Hide both the enable and disable buttons in case the // previously selected node was a device. // m_pToolbar->SetButtonState(IDM_ENABLE, HIDDEN, TRUE); m_pToolbar->SetButtonState(IDM_DISABLE, HIDDEN, TRUE); } // // Only show the uninstall button if the device can be uninstalled. // if (pDevice->IsUninstallable()) { fRemoveHidden = FALSE; } // // Display Update Driver button for everything except legacy drivers. // fUpdateHidden = IsEqualGUID(*pClass, GUID_DEVCLASS_LEGACYDRIVER) ? TRUE : FALSE; // // Display refresh (Scan...) button. // fRefreshHidden = FALSE; } break; } else { // // Must be an admin and on the local machine to remove or // enable/disable a device. // // // Fall through to hide the remove and enable/disable buttons. // } case COOKIE_TYPE_RESULTITEM_COMPUTER: case COOKIE_TYPE_RESULTITEM_CLASS: case COOKIE_TYPE_RESULTITEM_RESTYPE: // // Display refresh (enumerate) button if the user is an Administrator // if (g_IsAdmin) { fRefreshHidden = FALSE; } break; default: break; } // // Hide or show the buttons // m_pToolbar->SetButtonState(IDM_REMOVE, HIDDEN, fRemoveHidden); m_pToolbar->SetButtonState(IDM_REFRESH, HIDDEN, fRefreshHidden); m_pToolbar->SetButtonState(IDM_UPDATEDRIVER, HIDDEN, fUpdateHidden); m_pToolbar->SetButtonState(IDM_DISABLE, HIDDEN, fDisableHidden); m_pToolbar->SetButtonState(IDM_ENABLE, HIDDEN, fEnableHidden); return S_OK; } //////////////////////////////////////////////////////////////////////////// //// Snapin's IExtendPropertySheet implementation //// STDMETHODIMP CComponent::QueryPagesFor( LPDATAOBJECT lpDataObject ) { HRESULT hr; if (!lpDataObject) { return E_INVALIDARG; } INTERNAL_DATA tID; try { hr = ExtractData(lpDataObject, CDataObject::m_cfSnapinInternal, reinterpret_cast(&tID), sizeof(tID) ); if (SUCCEEDED(hr)) { ASSERT(m_pCurFolder); hr = m_pCurFolder->QueryPagesFor(GetActiveCookie(tID.cookie)); } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); hr = S_FALSE; } return hr; } STDMETHODIMP CComponent::CreatePropertyPages( LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, LPDATAOBJECT lpDataObject ) { HRESULT hr; if (!lpProvider || !lpDataObject) { return E_INVALIDARG; } INTERNAL_DATA tID; try { hr = ExtractData(lpDataObject, CDataObject::m_cfSnapinInternal, reinterpret_cast(&tID), sizeof(tID) ); if (SUCCEEDED(hr)) { ASSERT(m_pCurFolder); hr = m_pCurFolder->CreatePropertyPages(GetActiveCookie(tID.cookie), lpProvider, handle ); } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); hr = E_OUTOFMEMORY; } return hr; } ///////////////////////////////////////////////////////////////////////////// // Snapin's IPersistStream implementation STDMETHODIMP CComponent::GetClassID( CLSID* pClassID ) { if(!pClassID) { return E_POINTER; } *pClassID = m_pComponentData->GetCoClassID(); return S_OK; } STDMETHODIMP CComponent::IsDirty() { return m_Dirty ? S_OK : S_FALSE; } STDMETHODIMP CComponent::GetSizeMax( ULARGE_INTEGER* pcbSize ) { if (!pcbSize) { return E_INVALIDARG; } // total folders folder signature int Size = sizeof(int) + m_listFolder.GetCount() * sizeof(FOLDER_SIGNATURE) + sizeof(CLSID); CFolder* pFolder; POSITION pos = m_listFolder.GetHeadPosition(); while (NULL != pos) { pFolder = m_listFolder.GetNext(pos); ASSERT(pFolder); Size += pFolder->GetPersistDataSize(); } ULISet32(*pcbSize, Size); return S_OK; } // save data format STDMETHODIMP CComponent::Save( IStream* pStm, BOOL fClearDirty ) { HRESULT hr = S_OK; SafeInterfacePtr StmPtr(pStm); int Count; POSITION pos; try { // // write out CLSID // hr = pStm->Write(&CLSID_DEVMGR, sizeof(CLSID), NULL); if (SUCCEEDED(hr)) { Count = m_listFolder.GetCount(); CFolder* pFolder; // // write out folder count // hr = pStm->Write(&Count, sizeof(Count), NULL); if (SUCCEEDED(hr) && Count) { pos = m_listFolder.GetHeadPosition(); while (NULL != pos) { pFolder = m_listFolder.GetNext(pos); // // write folder signature // FOLDER_SIGNATURE Signature = pFolder->GetSignature(); hr = pStm->Write(&Signature, sizeof(Signature), NULL); if (SUCCEEDED(hr)) { hr = SaveFolderPersistData(pFolder, pStm, fClearDirty); } if (FAILED(hr)) { break; } } } } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); hr = E_OUTOFMEMORY; } if (fClearDirty) { m_Dirty = FALSE; } return hr; } STDMETHODIMP CComponent::Load( IStream* pStm ) { HRESULT hr = S_OK; CLSID clsid; SafeInterfacePtr StmPtr(pStm); ASSERT(pStm); // // Read the clsid // try { hr = pStm->Read(&clsid, sizeof(clsid), NULL); if (SUCCEEDED(hr) && clsid == CLSID_DEVMGR) { CFolder* pFolder; int FolderCount; // // Folder list must be create before Load. // DO NOT rely on that IComponent::Initialize comes before IStream::Load // ASSERT(m_listFolder.GetCount()); // // Load folder count // hr = pStm->Read(&FolderCount, sizeof(FolderCount), NULL); if (SUCCEEDED(hr)) { ASSERT(m_listFolder.GetCount() == FolderCount); // // Get folder signature // go through every folder // for (int i = 0; i < FolderCount; i++) { FOLDER_SIGNATURE Signature; hr = pStm->Read(&Signature, sizeof(Signature), NULL); if (SUCCEEDED(hr)) { POSITION pos; pos = m_listFolder.GetHeadPosition(); while (NULL != pos) { pFolder = m_listFolder.GetNext(pos); if (pFolder->GetSignature() == Signature) { hr = LoadFolderPersistData(pFolder, pStm); break; } } } } } } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); hr = E_OUTOFMEMORY; } m_Dirty = FALSE; return hr; } HRESULT CComponent::SaveFolderPersistData( CFolder* pFolder, IStream* pStm, BOOL fClearDirty ) { HRESULT hr = S_OK; int Size; SafeInterfacePtr StmPtr(pStm); UNREFERENCED_PARAMETER(fClearDirty); try { Size = pFolder->GetPersistDataSize(); // // Always write the length even though it can be 0. // hr = pStm->Write(&Size, sizeof(Size), NULL); if (SUCCEEDED(hr) && Size) { BufferPtr Buffer(Size); pFolder->GetPersistData(Buffer, Size); hr = pStm->Write(Buffer, Size, NULL); } } catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_pComponentData->m_hwndMain, 0, 0, 0); hr = E_OUTOFMEMORY; } return hr; } HRESULT CComponent::LoadFolderPersistData( CFolder* pFolder, IStream* pStm ) { HRESULT hr = S_OK; SafeInterfacePtr StmPtr(pStm); int Size = 0; hr = pStm->Read(&Size, sizeof(Size), NULL); if (SUCCEEDED(hr) && Size) { BufferPtr Buffer(Size); hr = pStm->Read(Buffer, Size, NULL); if (SUCCEEDED(hr)) { hr = pFolder->SetPersistData(Buffer, Size); } } return hr; } // // This function attaches the given folder the the machine created // by the component data. The machine notifies every attached folder // when there are state changes in the machine. // // INPUT: // pFolder -- the folder to be attached // ppMachind -- to receive a pointer to the machine // OUTPUT: // TRUE if the folder is attached successfully. // FALSE if the attachment failed. // // BOOL CComponent::AttachFolderToMachine( CFolder* pFolder, CMachine** ppMachine ) { if (!pFolder) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } // Initialize the machine. if (m_pComponentData->InitializeMachine()) { *ppMachine = m_pComponentData->m_pMachine; (*ppMachine)->AttachFolder(pFolder); return TRUE; } return FALSE; } // // This function detaches all the component's folders from the machine // void CComponent::DetachAllFoldersFromMachine() { if (m_pComponentData->m_pMachine) { CMachine* pMachine = m_pComponentData->m_pMachine; CFolder* pFolder; POSITION pos = m_listFolder.GetHeadPosition(); while (NULL != pos) { pFolder = m_listFolder.GetNext(pos); pMachine->DetachFolder(pFolder); } } } HRESULT CComponent::CreateFolderList( CCookie* pCookie ) { CCookie* pCookieChild; CScopeItem* pScopeItem; CFolder* pFolder; ASSERT(pCookie); HRESULT hr = S_OK; do { pScopeItem = pCookie->GetScopeItem(); ASSERT(pScopeItem); pFolder = pScopeItem->CreateFolder(this); if (pFolder) { m_listFolder.AddTail(pFolder); pFolder->AddRef(); pCookieChild = pCookie->GetChild(); if (pCookieChild) { hr = CreateFolderList(pCookieChild); } pCookie = pCookie->GetSibling(); } else { hr = E_OUTOFMEMORY; } } while (SUCCEEDED(hr) && pCookie); return hr; } BOOL CComponent::DestroyFolderList( MMC_COOKIE cookie ) { UNREFERENCED_PARAMETER(cookie); if (!m_listFolder.IsEmpty()) { POSITION pos = m_listFolder.GetHeadPosition(); while (NULL != pos) { CFolder* pFolder = m_listFolder.GetNext(pos); // // DONOT delete it!!!!!!! // pFolder->Release(); } m_listFolder.RemoveAll(); } return TRUE; } CFolder* CComponent::FindFolder( MMC_COOKIE cookie ) { CCookie* pCookie = GetActiveCookie(cookie); CFolder* pFolder; POSITION pos = m_listFolder.GetHeadPosition(); while (NULL != pos) { pFolder = m_listFolder.GetNext(pos); if (pCookie->GetScopeItem() == pFolder->m_pScopeItem) { return pFolder; } } return NULL; } int CComponent::MessageBox( LPCTSTR Msg, LPCTSTR Caption, DWORD Flags ) { int Result; ASSERT(m_pConsole); if (SUCCEEDED(m_pConsole->MessageBox(Msg, Caption, Flags, &Result))) { return Result; } else { return IDCANCEL; } }