3626 lines
107 KiB
C++
3626 lines
107 KiB
C++
/*++
|
|
|
|
Copyright (C) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cfolder.cpp
|
|
|
|
Abstract:
|
|
|
|
This module implements CFolder and its releated classes.
|
|
|
|
Author:
|
|
|
|
William Hsieh (williamh) created
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
#include "devmgr.h"
|
|
#include "clsgenpg.h"
|
|
#include "devgenpg.h"
|
|
#include "devdrvpg.h"
|
|
#include "devpopg.h"
|
|
#include "devdetpg.h"
|
|
#include "hwprof.h"
|
|
#include "devrmdlg.h"
|
|
#include "printer.h"
|
|
#include <devguid.h>
|
|
#include <initguid.h>
|
|
#include <oleacc.h>
|
|
|
|
|
|
const TCHAR* OCX_TREEVIEW = TEXT("{CD6C7868-5864-11D0-ABF0-0020AF6B0B7A}");
|
|
|
|
const MMCMENUITEM ViewDevicesMenuItems[TOTAL_VIEWS] =
|
|
{
|
|
{IDS_VIEW_DEVICESBYTYPE, IDS_MENU_STATUS_DEVBYTYPE, IDM_VIEW_DEVICESBYTYPE, VIEW_DEVICESBYTYPE},
|
|
{IDS_VIEW_DEVICESBYCONNECTION, IDS_MENU_STATUS_DEVBYCONNECTION, IDM_VIEW_DEVICESBYCONNECTION, VIEW_DEVICESBYCONNECTION},
|
|
{IDS_VIEW_RESOURCESBYTYPE, IDS_MENU_STATUS_RESBYTYPE, IDM_VIEW_RESOURCESBYTYPE, VIEW_RESOURCESBYTYPE},
|
|
{IDS_VIEW_RESOURCESBYCONNECTION, IDS_MENU_STATUS_RESBYCONNECTION, IDM_VIEW_RESOURCESBYCONNECTION, VIEW_RESOURCESBYCONNECTION}
|
|
};
|
|
|
|
const RESOURCEID ResourceTypes[TOTAL_RESOURCE_TYPES] =
|
|
{
|
|
ResType_Mem,
|
|
ResType_IO,
|
|
ResType_DMA,
|
|
ResType_IRQ
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
/// CScopeItem implementations
|
|
///
|
|
|
|
BOOL
|
|
CScopeItem::Create()
|
|
{
|
|
m_strName.LoadString(g_hInstance, m_iNameStringId);
|
|
m_strDesc.LoadString(g_hInstance, m_iDescStringId);
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT
|
|
CScopeItem::GetDisplayInfo(
|
|
LPSCOPEDATAITEM pScopeDataItem
|
|
)
|
|
{
|
|
if (!pScopeDataItem) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (SDI_STR & pScopeDataItem->mask) {
|
|
pScopeDataItem->displayname = (LPTSTR)(LPCTSTR)m_strName;
|
|
}
|
|
|
|
if (SDI_IMAGE & pScopeDataItem->mask) {
|
|
pScopeDataItem->nImage = m_iImage;
|
|
}
|
|
|
|
if (SDI_OPENIMAGE & pScopeDataItem->mask) {
|
|
pScopeDataItem->nOpenImage = m_iOpenImage;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
BOOL
|
|
CScopeItem::EnumerateChildren(
|
|
int Index,
|
|
CScopeItem** ppScopeItem
|
|
)
|
|
{
|
|
if (!ppScopeItem || Index >= m_listChildren.GetCount()) {
|
|
return FALSE;
|
|
}
|
|
|
|
POSITION pos = m_listChildren.FindIndex(Index);
|
|
*ppScopeItem = m_listChildren.GetAt(pos);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT
|
|
CScopeItem::Reset()
|
|
{
|
|
//
|
|
// We have not enumerated!
|
|
//
|
|
m_Enumerated = FALSE;
|
|
|
|
//
|
|
// If there are folder created from this scope item,
|
|
// walk through all of them and tell each one
|
|
// to reset the cached machine object
|
|
//
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_listFolder.IsEmpty()) {
|
|
CFolder* pFolder;
|
|
POSITION pos = m_listFolder.GetHeadPosition();
|
|
|
|
while (NULL != pos) {
|
|
pFolder = m_listFolder.GetNext(pos);
|
|
hr = pFolder->Reset();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
CCookie*
|
|
CScopeItem::FindSelectedCookieData(
|
|
CResultView** ppResultView
|
|
)
|
|
{
|
|
CFolder* pFolder;
|
|
CResultView* pResultView;
|
|
|
|
//
|
|
// This routine returns the Selected Cookie in the result view if it has
|
|
// the focus. This is done by locating the folder from the scopeitem.
|
|
// If the folder is not selected, the current result view is accessed to
|
|
// get the current selected cookie. If any of these fail a NULL value is
|
|
// returned. Optionally the current CResultView class is returned.
|
|
//
|
|
POSITION pos = m_listFolder.GetHeadPosition();
|
|
|
|
while (NULL != pos) {
|
|
pFolder = m_listFolder.GetNext(pos);
|
|
|
|
if (this == pFolder->m_pScopeItem) {
|
|
if (!pFolder->m_bSelect &&
|
|
(pResultView = pFolder->GetCurResultView()) != NULL) {
|
|
if (ppResultView) {
|
|
*ppResultView = pResultView;
|
|
}
|
|
|
|
return pResultView->GetSelectedCookie();
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CScopeItem::~CScopeItem()
|
|
{
|
|
if (!m_listChildren.IsEmpty()) {
|
|
CScopeItem* pChild;
|
|
POSITION pos;
|
|
|
|
pos = m_listChildren.GetHeadPosition();
|
|
|
|
while (NULL != pos) {
|
|
pChild = m_listChildren.GetNext(pos);
|
|
delete pChild;
|
|
}
|
|
|
|
m_listChildren.RemoveAll();
|
|
}
|
|
|
|
if (!m_listFolder.IsEmpty()) {
|
|
POSITION pos;
|
|
pos = m_listFolder.GetHeadPosition();
|
|
|
|
while (NULL != pos) {
|
|
//
|
|
// DO NOT delete it!!!!
|
|
//
|
|
(m_listFolder.GetNext(pos))->Release();
|
|
}
|
|
|
|
m_listFolder.RemoveAll();
|
|
}
|
|
}
|
|
|
|
CFolder*
|
|
CScopeItem::CreateFolder(
|
|
CComponent* pComponent
|
|
)
|
|
{
|
|
ASSERT(pComponent);
|
|
|
|
CFolder* pFolder;
|
|
pFolder = new CFolder(this, pComponent);
|
|
|
|
if (pFolder) {
|
|
m_listFolder.AddTail(pFolder);
|
|
pFolder->AddRef();
|
|
}
|
|
|
|
else {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
return pFolder;
|
|
}
|
|
|
|
HRESULT
|
|
CScopeItem::AddMenuItems(
|
|
LPCONTEXTMENUCALLBACK pCallback,
|
|
long* pInsertionAllowed
|
|
)
|
|
{
|
|
CCookie* pSelectedCookie;
|
|
CResultView* pResultView;
|
|
|
|
if ((pSelectedCookie = FindSelectedCookieData(&pResultView)) != NULL) {
|
|
//
|
|
// Add menu items for the Action menu.
|
|
//
|
|
return pResultView->AddMenuItems(pSelectedCookie, pCallback,
|
|
pInsertionAllowed, FALSE);
|
|
}
|
|
|
|
else {
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CScopeItem::MenuCommand(
|
|
long lCommandId
|
|
)
|
|
{
|
|
CCookie* pSelectedCookie;
|
|
CResultView* pResultView;
|
|
|
|
if ((pSelectedCookie = FindSelectedCookieData(&pResultView)) != NULL) {
|
|
//
|
|
// Handle menu requests for the Action menu.
|
|
//
|
|
return pResultView->MenuCommand(pSelectedCookie, lCommandId);
|
|
}
|
|
|
|
else {
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CScopeItem::QueryPagesFor()
|
|
{
|
|
//
|
|
// We do not have property pages for scope item
|
|
//
|
|
CCookie* pSelectedCookie;
|
|
|
|
if ((pSelectedCookie = FindSelectedCookieData(NULL)) != NULL) {
|
|
return S_OK;
|
|
}
|
|
|
|
else {
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CScopeItem::CreatePropertyPages(
|
|
LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LONG_PTR handle
|
|
)
|
|
{
|
|
CCookie* pSelectedCookie;
|
|
CResultView* pResultView;
|
|
|
|
if ((pSelectedCookie = FindSelectedCookieData(&pResultView)) != NULL) {
|
|
return pResultView->CreatePropertyPages(pSelectedCookie, lpProvider, handle);
|
|
}
|
|
|
|
else {
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
/// CFolder implementations
|
|
///
|
|
|
|
CFolder::CFolder(
|
|
CScopeItem* pScopeItem,
|
|
CComponent* pComponent
|
|
)
|
|
{
|
|
ASSERT(pScopeItem && pComponent);
|
|
|
|
m_pScopeItem = pScopeItem;
|
|
m_pComponent = pComponent;
|
|
m_Show = FALSE;
|
|
m_pMachine = NULL;
|
|
m_bSelect = FALSE;
|
|
m_pOleTaskString = NULL;
|
|
m_Ref = 0;
|
|
m_FirstTimeOnShow = TRUE;
|
|
m_Signature = FOLDER_SIGNATURE_DEVMGR;
|
|
m_pViewTreeByType = NULL;
|
|
m_pViewTreeByConnection = NULL;
|
|
m_pViewResourcesByType = NULL;
|
|
m_pViewResourcesByConnection = NULL;
|
|
m_CurViewType = VIEW_DEVICESBYTYPE;
|
|
m_pCurView = m_pViewTreeByType;
|
|
m_ShowHiddenDevices = FALSE;
|
|
}
|
|
|
|
CFolder::~CFolder()
|
|
{
|
|
if (m_pViewTreeByType) {
|
|
delete m_pViewTreeByType;
|
|
}
|
|
|
|
if (m_pViewTreeByConnection) {
|
|
delete m_pViewTreeByConnection;
|
|
}
|
|
|
|
if (m_pViewResourcesByType) {
|
|
delete m_pViewResourcesByType;
|
|
}
|
|
|
|
if (m_pViewResourcesByConnection) {
|
|
delete m_pViewResourcesByConnection;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::Compare(
|
|
MMC_COOKIE cookieA,
|
|
MMC_COOKIE cookieB,
|
|
int nCol,
|
|
int* pnResult
|
|
)
|
|
{
|
|
ASSERT(pnResult);
|
|
|
|
//
|
|
// We do not have anything in the result pane, thus
|
|
// comparision makes no sense.
|
|
//
|
|
*pnResult = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::GetDisplayInfo(
|
|
LPRESULTDATAITEM pResultDataItem
|
|
)
|
|
{
|
|
if (!pResultDataItem) {
|
|
return E_POINTER;
|
|
}
|
|
|
|
ASSERT(m_pScopeItem);
|
|
|
|
//
|
|
// This only take care of scope pane item(displaying scope pane node
|
|
// on the result pane). The derived classes should take care of
|
|
// result items.
|
|
//
|
|
if (RDI_STR & pResultDataItem->mask) {
|
|
if (0 == pResultDataItem->nCol) {
|
|
if (m_pOleTaskString)
|
|
FreeOleTaskString(m_pOleTaskString);
|
|
m_pOleTaskString = AllocOleTaskString(m_pScopeItem->GetNameString());
|
|
|
|
if (m_pOleTaskString) {
|
|
pResultDataItem->str = m_pOleTaskString;
|
|
}
|
|
|
|
else {
|
|
m_strScratch = m_pScopeItem->GetNameString();
|
|
pResultDataItem->str = (LPTSTR)(LPCTSTR)m_strScratch;
|
|
}
|
|
}
|
|
|
|
else if (2 == pResultDataItem->nCol) {
|
|
if (m_pOleTaskString) {
|
|
FreeOleTaskString(m_pOleTaskString);
|
|
}
|
|
|
|
m_pOleTaskString = AllocOleTaskString(m_pScopeItem->GetDescString());
|
|
|
|
if (m_pOleTaskString) {
|
|
pResultDataItem->str = m_pOleTaskString;
|
|
}
|
|
|
|
else {
|
|
m_strScratch = m_pScopeItem->GetDescString();
|
|
pResultDataItem->str = (LPTSTR)(LPCTSTR)m_strScratch;
|
|
}
|
|
}
|
|
|
|
else {
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
|
|
if (RDI_IMAGE & pResultDataItem->mask) {
|
|
pResultDataItem->nImage = m_pScopeItem->GetImageIndex();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::AddMenuItems(
|
|
CCookie* pCookie,
|
|
LPCONTEXTMENUCALLBACK pCallback,
|
|
long* pInsertionAllowed
|
|
)
|
|
{
|
|
ASSERT(pCookie);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// If the cookie points to a scope item, add view menu items
|
|
//
|
|
if (NULL == pCookie->GetResultItem()) {
|
|
|
|
ASSERT(m_pScopeItem == pCookie->GetScopeItem());
|
|
|
|
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_VIEW) {
|
|
long Flags;
|
|
|
|
for (int i = 0; i < TOTAL_VIEWS; i++) {
|
|
if (m_CurViewType == ViewDevicesMenuItems[i].Type) {
|
|
Flags = MF_ENABLED | MF_CHECKED | MFT_RADIOCHECK;
|
|
}
|
|
|
|
else {
|
|
Flags = MF_ENABLED;
|
|
}
|
|
|
|
hr = AddMenuItem(pCallback,
|
|
ViewDevicesMenuItems[i].idName,
|
|
ViewDevicesMenuItems[i].idStatusBar,
|
|
ViewDevicesMenuItems[i].lCommandId,
|
|
CCM_INSERTIONPOINTID_PRIMARY_VIEW,
|
|
Flags,
|
|
0);
|
|
if (FAILED(hr)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add "Show hidden devices" menu item
|
|
//
|
|
if (SUCCEEDED(hr)) {
|
|
hr = AddMenuItem(pCallback, 0, 0, 0, CCM_INSERTIONPOINTID_PRIMARY_VIEW,
|
|
MF_ENABLED, CCM_SPECIAL_SEPARATOR);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
if (m_ShowHiddenDevices) {
|
|
Flags = MF_ENABLED | MF_CHECKED;
|
|
}
|
|
|
|
else {
|
|
Flags = MF_ENABLED;
|
|
}
|
|
|
|
hr = AddMenuItem(pCallback, IDS_SHOW_ALL, IDS_MENU_STATUS_HIDDEN_DEVICES, IDM_SHOW_ALL,
|
|
CCM_INSERTIONPOINTID_PRIMARY_VIEW, Flags, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else {
|
|
if (m_pCurView) {
|
|
//
|
|
// Add menu items for the Context menu in the result pane.
|
|
//
|
|
hr = m_pCurView->AddMenuItems(pCookie, pCallback,
|
|
pInsertionAllowed, TRUE);
|
|
}
|
|
|
|
else {
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::MenuCommand(
|
|
CCookie* pCookie,
|
|
long lCommandId
|
|
)
|
|
{
|
|
if (NULL == pCookie->GetResultItem()) {
|
|
ASSERT(m_pScopeItem == pCookie->GetScopeItem());
|
|
|
|
//
|
|
// Convert menu id to view type;
|
|
//
|
|
VIEWTYPE ViewType = m_CurViewType;
|
|
BOOL fShowHiddenDevices = m_ShowHiddenDevices;
|
|
|
|
switch (lCommandId) {
|
|
case IDM_VIEW_DEVICESBYTYPE:
|
|
ViewType = VIEW_DEVICESBYTYPE;
|
|
break;
|
|
|
|
case IDM_VIEW_DEVICESBYCONNECTION:
|
|
ViewType = VIEW_DEVICESBYCONNECTION;
|
|
break;
|
|
|
|
case IDM_VIEW_RESOURCESBYTYPE:
|
|
ViewType = VIEW_RESOURCESBYTYPE;
|
|
break;
|
|
|
|
case IDM_VIEW_RESOURCESBYCONNECTION:
|
|
ViewType = VIEW_RESOURCESBYCONNECTION;
|
|
break;
|
|
|
|
case IDM_SHOW_ALL:
|
|
fShowHiddenDevices = !fShowHiddenDevices;
|
|
break;
|
|
|
|
default:
|
|
//not view menu. do nothing
|
|
return S_OK;
|
|
break;
|
|
}
|
|
|
|
if (!SelectView(ViewType, fShowHiddenDevices)) {
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
//
|
|
// Reselect the scopeitem
|
|
//
|
|
return m_pComponent->m_pConsole->SelectScopeItem(*m_pScopeItem);
|
|
}
|
|
|
|
else {
|
|
if (m_pCurView) {
|
|
//
|
|
// Handle menu requests for the Context menu in the result pane.
|
|
//
|
|
return m_pCurView->MenuCommand(pCookie, lCommandId);
|
|
}
|
|
|
|
else {
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::QueryPagesFor(
|
|
CCookie* pCookie
|
|
)
|
|
{
|
|
//
|
|
// We do not have property pages for scope item
|
|
//
|
|
if (NULL == pCookie->GetResultItem()) {
|
|
ASSERT(m_pScopeItem == pCookie->GetScopeItem());
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
//
|
|
// The cookie points to result item, let the current
|
|
// view handle it
|
|
//
|
|
if (m_pCurView) {
|
|
return m_pCurView->QueryPagesFor(pCookie);
|
|
}
|
|
|
|
else {
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::CreatePropertyPages(
|
|
CCookie* pCookie,
|
|
LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LONG_PTR handle
|
|
)
|
|
{
|
|
if (NULL == pCookie->GetResultItem()) {
|
|
ASSERT(m_pScopeItem == pCookie->GetScopeItem());
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
if (m_pCurView) {
|
|
return m_pCurView->CreatePropertyPages(pCookie, lpProvider, handle);
|
|
}
|
|
|
|
else {
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CFolder::SelectView(
|
|
VIEWTYPE ViewType,
|
|
BOOL fShowHiddenDevices
|
|
)
|
|
{
|
|
CResultView* pNewView;
|
|
|
|
if (m_CurViewType == ViewType &&
|
|
m_ShowHiddenDevices == fShowHiddenDevices &&
|
|
m_pCurView) {
|
|
return TRUE;
|
|
}
|
|
|
|
switch (ViewType) {
|
|
case VIEW_DEVICESBYTYPE:
|
|
if (!m_pViewTreeByType) {
|
|
m_pViewTreeByType = new CViewTreeByType();
|
|
|
|
if (m_pViewTreeByType) {
|
|
|
|
m_pViewTreeByType->SetFolder(this);
|
|
}
|
|
}
|
|
|
|
pNewView = m_pViewTreeByType;
|
|
break;
|
|
|
|
case VIEW_DEVICESBYCONNECTION:
|
|
if (!m_pViewTreeByConnection) {
|
|
m_pViewTreeByConnection = new CViewTreeByConnection();
|
|
|
|
if (m_pViewTreeByConnection) {
|
|
|
|
m_pViewTreeByConnection->SetFolder(this);
|
|
}
|
|
}
|
|
|
|
pNewView = m_pViewTreeByConnection;
|
|
break;
|
|
|
|
case VIEW_RESOURCESBYTYPE:
|
|
if (!m_pViewResourcesByType) {
|
|
m_pViewResourcesByType = new CViewResourceTree(IDS_STATUS_RESOURCES_BYTYPE);
|
|
|
|
if (m_pViewResourcesByType) {
|
|
|
|
m_pViewResourcesByType->SetFolder(this);
|
|
}
|
|
}
|
|
|
|
pNewView = m_pViewResourcesByType;
|
|
break;
|
|
|
|
case VIEW_RESOURCESBYCONNECTION:
|
|
if (!m_pViewResourcesByConnection) {
|
|
m_pViewResourcesByConnection = new CViewResourceTree(IDS_STATUS_RESOURCES_BYCONN);
|
|
|
|
if (m_pViewResourcesByConnection) {
|
|
|
|
m_pViewResourcesByConnection->SetFolder(this);
|
|
}
|
|
}
|
|
|
|
pNewView = m_pViewResourcesByConnection;
|
|
break;
|
|
|
|
default:
|
|
pNewView = NULL;
|
|
break;
|
|
}
|
|
|
|
if (pNewView) {
|
|
//
|
|
// Let the view know that it is being diselected.
|
|
//
|
|
if (m_pCurView) {
|
|
if (m_CurViewType != ViewType) {
|
|
m_pComponent->SetDirty();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Let the new active view know that it is being selected.
|
|
//
|
|
m_pCurView = pNewView;
|
|
m_CurViewType = ViewType;
|
|
m_ShowHiddenDevices = fShowHiddenDevices;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::OnShow(
|
|
BOOL fShow
|
|
)
|
|
{
|
|
if (fShow && !m_pMachine) {
|
|
|
|
ASSERT(m_pComponent);
|
|
|
|
if (!m_pComponent->AttachFolderToMachine(this, &m_pMachine)) {
|
|
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
m_Show = fShow;
|
|
|
|
if (m_pMachine) {
|
|
|
|
if (!SelectView(m_CurViewType, m_ShowHiddenDevices)) {
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
if (m_pCurView) {
|
|
|
|
if (m_FirstTimeOnShow && m_Show) {
|
|
|
|
TCHAR WarningMsg[MAX_PATH * 3];
|
|
int ReturnValue;
|
|
|
|
//
|
|
// Subsequent calls are not the first time anymore.
|
|
//
|
|
m_FirstTimeOnShow = FALSE;
|
|
|
|
//
|
|
// This is the first time we show the folder.
|
|
// Put up a message box to warn user if
|
|
// (1) The machine is a remote machine or
|
|
// (2) The user does not have the Adminstator privilege.
|
|
// (3) We can not connect to the remote machine
|
|
//
|
|
ASSERT(m_pComponent && m_pComponent->m_pConsole);
|
|
|
|
//
|
|
// Connect to a remote machine
|
|
//
|
|
if (!m_pMachine->IsLocal()) {
|
|
|
|
String strMsg;
|
|
|
|
//
|
|
// Display a warning if we cannot connect to the remote machine
|
|
//
|
|
if (!VerifyMachineName(m_pMachine->GetRemoteMachineFullName())) {
|
|
|
|
TCHAR WarningFormat[MAX_PATH * 3];
|
|
LPVOID lpLastError = NULL;
|
|
|
|
if (LoadString(g_hInstance,
|
|
IDS_INVALID_COMPUTER_NAME,
|
|
WarningFormat,
|
|
ARRAYLEN(WarningFormat)
|
|
) &&
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
GetLastError(),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)&lpLastError,
|
|
0,
|
|
NULL)) {
|
|
|
|
StringCchPrintf(WarningMsg,
|
|
ARRAYLEN(WarningMsg),
|
|
WarningFormat,
|
|
m_pMachine->GetMachineDisplayName(),
|
|
lpLastError
|
|
);
|
|
|
|
m_pComponent->m_pConsole->MessageBox((LPCTSTR)WarningMsg,
|
|
(LPCTSTR)g_strDevMgr,
|
|
MB_ICONERROR | MB_OK,
|
|
&ReturnValue);
|
|
}
|
|
|
|
if (lpLastError) {
|
|
|
|
LocalFree(lpLastError);
|
|
}
|
|
|
|
//
|
|
// Otherwise display a warning that we are connect to a remote machine and
|
|
// device manager will run in a neutered mode.
|
|
//
|
|
} else {
|
|
|
|
strMsg.LoadString(g_hInstance, IDS_REMOTE_WARNING2);
|
|
::LoadString(g_hInstance, IDS_REMOTE_WARNING1, WarningMsg, ARRAYLEN(WarningMsg));
|
|
lstrcat(WarningMsg, (LPCTSTR)strMsg);
|
|
m_pComponent->m_pConsole->MessageBox(WarningMsg,
|
|
(LPCTSTR)g_strDevMgr,
|
|
MB_ICONEXCLAMATION | MB_OK,
|
|
&ReturnValue);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Running local
|
|
//
|
|
else if (!g_HasLoadDriverNamePrivilege) {
|
|
|
|
::LoadString(g_hInstance, IDS_NOADMIN_WARNING, WarningMsg, ARRAYLEN(WarningMsg));
|
|
m_pComponent->m_pConsole->MessageBox(WarningMsg,
|
|
(LPCTSTR)g_strDevMgr,
|
|
MB_ICONEXCLAMATION | MB_OK,
|
|
&ReturnValue);
|
|
}
|
|
}
|
|
|
|
return m_pCurView->OnShow(fShow);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::OnRestoreView(
|
|
BOOL* pfHandled
|
|
)
|
|
{
|
|
ASSERT(pfHandled);
|
|
|
|
if (!pfHandled) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT hr = OnShow(TRUE);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
*pfHandled = TRUE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::GetResultViewType(
|
|
LPOLESTR* ppViewType,
|
|
long* pViewOptions
|
|
)
|
|
{
|
|
ASSERT(pViewOptions);
|
|
|
|
if (!SelectView(m_CurViewType, m_ShowHiddenDevices)) {
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
if (m_pCurView) {
|
|
return m_pCurView->GetResultViewType(ppViewType, pViewOptions);
|
|
}
|
|
|
|
*pViewOptions = MMC_VIEW_OPTIONS_NONE;
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::Reset()
|
|
{
|
|
//
|
|
// Delete all views so that we will create new ones
|
|
// when OnShow is called.
|
|
//
|
|
if (m_pViewTreeByType) {
|
|
delete m_pViewTreeByType;
|
|
m_pViewTreeByType = NULL;
|
|
}
|
|
|
|
if (m_pViewTreeByConnection) {
|
|
delete m_pViewTreeByConnection;
|
|
m_pViewTreeByConnection = NULL;
|
|
}
|
|
|
|
if (m_pViewResourcesByType) {
|
|
delete m_pViewResourcesByType;
|
|
m_pViewResourcesByType = NULL;
|
|
}
|
|
|
|
if (m_pViewResourcesByConnection) {
|
|
delete m_pViewResourcesByConnection;
|
|
m_pViewResourcesByConnection = NULL;
|
|
}
|
|
|
|
m_pCurView = NULL;
|
|
m_FirstTimeOnShow = TRUE;
|
|
m_pMachine = NULL;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::MachinePropertyChanged(
|
|
CMachine* pMachine
|
|
)
|
|
{
|
|
//
|
|
// Ignore the tvNotify(SELCHANGED) messages while the tree is changed.
|
|
//
|
|
if (m_pCurView) {
|
|
m_pCurView->SetSelectOk(FALSE);
|
|
}
|
|
|
|
if (pMachine) {
|
|
m_pMachine = pMachine;
|
|
}
|
|
|
|
if (m_pViewTreeByType) {
|
|
m_pViewTreeByType->MachinePropertyChanged(pMachine);
|
|
}
|
|
|
|
if (m_pViewTreeByConnection) {
|
|
m_pViewTreeByConnection->MachinePropertyChanged(pMachine);
|
|
}
|
|
|
|
if (m_pViewResourcesByType) {
|
|
m_pViewResourcesByType->MachinePropertyChanged(pMachine);
|
|
}
|
|
|
|
if (m_pViewResourcesByConnection) {
|
|
m_pViewResourcesByConnection->MachinePropertyChanged(pMachine);
|
|
}
|
|
|
|
if (m_pCurView) {
|
|
m_pCurView->SetSelectOk(TRUE);
|
|
}
|
|
|
|
if (m_Show && pMachine) {
|
|
OnShow(TRUE);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::GetPersistData(
|
|
PBYTE pBuffer,
|
|
int BufferSize
|
|
)
|
|
{
|
|
DEVMGRFOLDER_STATES states;
|
|
states.Type = COOKIE_TYPE_SCOPEITEM_DEVMGR;
|
|
states.CurViewType = m_CurViewType;
|
|
states.ShowHiddenDevices = m_ShowHiddenDevices;
|
|
|
|
if (BufferSize && !pBuffer) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (BufferSize >= sizeof(states)) {
|
|
::memcpy(pBuffer, &states, sizeof(states));
|
|
return S_OK;
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::SetPersistData(
|
|
PBYTE pData,
|
|
int Size
|
|
)
|
|
{
|
|
if (!pData) {
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (!Size) {
|
|
ASSERT(FALSE);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
PDEVMGRFOLDER_STATES pStates = (PDEVMGRFOLDER_STATES)pData;
|
|
|
|
if (COOKIE_TYPE_SCOPEITEM_DEVMGR == pStates->Type) {
|
|
if ((VIEW_DEVICESBYTYPE == pStates->CurViewType) ||
|
|
(VIEW_DEVICESBYCONNECTION == pStates->CurViewType) ||
|
|
(VIEW_RESOURCESBYTYPE == pStates->CurViewType) ||
|
|
(VIEW_RESOURCESBYCONNECTION == pStates->CurViewType)) {
|
|
m_CurViewType = pStates->CurViewType;
|
|
|
|
if (m_pCurView) {
|
|
m_pCurView->OnShow(TRUE);
|
|
}
|
|
|
|
m_ShowHiddenDevices = pStates->ShowHiddenDevices;
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::tvNotify(
|
|
HWND hwndTV,
|
|
CCookie* pCookie,
|
|
TV_NOTIFY_CODE Code,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
if (m_pCurView) {
|
|
return m_pCurView->tvNotify(hwndTV, pCookie, Code, arg, param);
|
|
}
|
|
|
|
else {
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CFolder::OnOcxNotify(
|
|
MMC_NOTIFY_TYPE event,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
if (m_pCurView) {
|
|
return m_pCurView->OnOcxNotify(event, arg, param);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//// CResultView implementations
|
|
////
|
|
|
|
CResultView::~CResultView()
|
|
{
|
|
if (m_pCookieComputer) {
|
|
if (m_pIDMTVOCX) {
|
|
m_pIDMTVOCX->DeleteAllItems();
|
|
}
|
|
|
|
delete m_pCookieComputer;
|
|
}
|
|
|
|
if (m_pIDMTVOCX) {
|
|
m_pIDMTVOCX->Release();
|
|
}
|
|
|
|
DestroySavedTreeStates();
|
|
}
|
|
|
|
HRESULT
|
|
CResultView::OnShow(
|
|
BOOL fShow
|
|
)
|
|
{
|
|
if (!fShow) {
|
|
return S_OK;
|
|
}
|
|
|
|
SafeInterfacePtr<IUnknown> pUnk;
|
|
HRESULT hr;
|
|
CComponent* pComponent = m_pFolder->m_pComponent;
|
|
ASSERT(pComponent);
|
|
ASSERT(pComponent->m_pConsole);
|
|
|
|
hr = S_OK;
|
|
|
|
if (NULL == m_pIDMTVOCX) {
|
|
hr = pComponent->m_pConsole->QueryResultView(&pUnk);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
//
|
|
// Get our OCX private interface
|
|
//
|
|
hr = pUnk->QueryInterface(IID_IDMTVOCX, (void**)&m_pIDMTVOCX);
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
m_pIDMTVOCX->Connect(pComponent, (MMC_COOKIE)this);
|
|
m_hwndTV = m_pIDMTVOCX->GetWindowHandle();
|
|
m_pIDMTVOCX->SetActiveConnection((MMC_COOKIE)this);
|
|
|
|
//
|
|
// Set up the annotation map for screen readers.
|
|
//
|
|
IAccPropServices *pAccPropSvc = NULL;
|
|
hr = CoCreateInstance(CLSID_AccPropServices,
|
|
NULL,
|
|
CLSCTX_SERVER,
|
|
IID_IAccPropServices,
|
|
(void**)&pAccPropSvc);
|
|
|
|
if ((hr == S_OK) && pAccPropSvc) {
|
|
//TRACE((TEXT("%s"), (LPTSTR)m_stringAnnotationMap));
|
|
pAccPropSvc->SetHwndPropStr(m_hwndTV, OBJID_CLIENT, 0, PROPID_ACC_DESCRIPTIONMAP, (LPTSTR)m_stringAnnotationMap);
|
|
pAccPropSvc->Release();
|
|
}
|
|
|
|
DisplayTree();
|
|
|
|
String strStartupCommand;
|
|
String strStartupDeviceId;
|
|
|
|
strStartupCommand = GetStartupCommand();
|
|
strStartupDeviceId = GetStartupDeviceId();
|
|
|
|
if (!strStartupCommand.IsEmpty() && !strStartupDeviceId.IsEmpty() &&
|
|
!strStartupCommand.CompareNoCase(DEVMGR_COMMAND_PROPERTY)) {
|
|
hr = DoProperties(m_hwndTV, m_pSelectedCookie);
|
|
}
|
|
}
|
|
}
|
|
|
|
else {
|
|
m_pIDMTVOCX->SetActiveConnection((MMC_COOKIE)this);
|
|
|
|
if (!DisplayTree()) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
inline
|
|
LPCTSTR
|
|
CResultView::GetStartupDeviceId()
|
|
{
|
|
return m_pFolder->m_pComponent->GetStartupDeviceId();
|
|
}
|
|
|
|
inline
|
|
LPCTSTR
|
|
CResultView::GetStartupCommand()
|
|
{
|
|
return m_pFolder->m_pComponent->GetStartupCommand();
|
|
}
|
|
|
|
//
|
|
// This function is called when machine states have changed.
|
|
//
|
|
// INPUT:
|
|
// pMachine -- if NULL, the machine is being destroy.
|
|
//
|
|
// OUTPUT:
|
|
// stanard OLE return code
|
|
HRESULT
|
|
CResultView::MachinePropertyChanged(
|
|
CMachine* pMachine
|
|
)
|
|
{
|
|
if (pMachine) {
|
|
m_pMachine = pMachine;
|
|
}
|
|
|
|
else {
|
|
//
|
|
// pMachine is NULL, the CMachine we associated with is being destroyed.
|
|
//
|
|
if (m_pCookieComputer) {
|
|
ASSERT(!m_pSelectedItem && m_listExpandedItems.IsEmpty());
|
|
|
|
//
|
|
// Save the expanded states
|
|
//
|
|
SaveTreeStates(m_pCookieComputer);
|
|
|
|
m_pIDMTVOCX->DeleteAllItems();
|
|
m_pIDMTVOCX->SetImageList(TVSIL_NORMAL, NULL);
|
|
|
|
delete m_pCookieComputer;
|
|
|
|
//
|
|
// Reset these because they are no longer valid.
|
|
//
|
|
m_pCookieComputer = NULL;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// This function saves the subtree states rooted by pCookieStart.
|
|
// It creates an identifier for each expanded node and inserts
|
|
// the identifier to the class memember, m_listExpandedItems.
|
|
//
|
|
// It also saves the selected cookie by creating an identifier and
|
|
// saving it in m_pSelectedItem.
|
|
//
|
|
// This function may throw CMemoryException
|
|
//
|
|
// INPUT:
|
|
// pCookieStart -- subtree root
|
|
// OUTPUT:
|
|
// NONE
|
|
void
|
|
CResultView::SaveTreeStates(
|
|
CCookie* pCookieStart
|
|
)
|
|
{
|
|
CItemIdentifier* pItem;
|
|
|
|
//
|
|
// If we have a selected item, create an identifier for it
|
|
//
|
|
if (m_pSelectedCookie) {
|
|
m_pSelectedItem = m_pSelectedCookie->GetResultItem()->CreateIdentifier();
|
|
m_pSelectedCookie = NULL;
|
|
}
|
|
|
|
while (pCookieStart) {
|
|
if (pCookieStart->IsFlagsOn(COOKIE_FLAGS_EXPANDED)) {
|
|
pItem = pCookieStart->GetResultItem()->CreateIdentifier();
|
|
m_listExpandedItems.AddTail(pItem);
|
|
}
|
|
|
|
if (pCookieStart->GetChild()) {
|
|
SaveTreeStates(pCookieStart->GetChild());
|
|
}
|
|
|
|
pCookieStart = pCookieStart->GetSibling();
|
|
}
|
|
}
|
|
|
|
void
|
|
CResultView::DestroySavedTreeStates()
|
|
{
|
|
if (!m_listExpandedItems.IsEmpty()) {
|
|
POSITION pos;
|
|
pos = m_listExpandedItems.GetHeadPosition();
|
|
|
|
while (NULL != pos) {
|
|
delete m_listExpandedItems.GetNext(pos);
|
|
}
|
|
|
|
m_listExpandedItems.RemoveAll();
|
|
}
|
|
|
|
if (m_pSelectedItem) {
|
|
delete m_pSelectedItem;
|
|
m_pSelectedItem = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This function restores the expanded and selected state for the cookie.
|
|
//
|
|
// INPUT:
|
|
// pCookie -- cookie to restore states for
|
|
// OUTPUT:
|
|
// NONE
|
|
void
|
|
CResultView::RestoreSavedTreeState(
|
|
CCookie* pCookie
|
|
)
|
|
{
|
|
//
|
|
// If the cookie was expanded before, mark it so that DisplayTree
|
|
// will expand it.
|
|
//
|
|
if (!m_listExpandedItems.IsEmpty()) {
|
|
POSITION pos = m_listExpandedItems.GetHeadPosition();
|
|
CItemIdentifier* pItem;
|
|
|
|
while (NULL != pos) {
|
|
pItem = m_listExpandedItems.GetNext(pos);
|
|
|
|
if (*pItem == *pCookie) {
|
|
pCookie->TurnOnFlags(COOKIE_FLAGS_EXPANDED);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_pSelectedItem && (*m_pSelectedItem == *pCookie)) {
|
|
m_pSelectedCookie = pCookie;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CResultView::DisplayTree()
|
|
{
|
|
BOOL Result = FALSE;
|
|
|
|
ASSERT(m_pIDMTVOCX);
|
|
|
|
::SendMessage(m_hwndTV, WM_SETREDRAW, FALSE, 0L);
|
|
|
|
//
|
|
// Ignore the tvNotify(SELCHANGED) messages while the tree is changed.
|
|
//
|
|
SetSelectOk(FALSE);
|
|
|
|
m_pIDMTVOCX->DeleteAllItems();
|
|
|
|
//
|
|
// Only display the tree if there is something to display
|
|
//
|
|
if (m_pCookieComputer) {
|
|
|
|
m_pIDMTVOCX->SetImageList(TVSIL_NORMAL, m_pMachine->DiGetClassImageList());
|
|
m_pIDMTVOCX->SetStyle(TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT);
|
|
|
|
BOOL HasProblem = FALSE;
|
|
|
|
//
|
|
// Walks down the tree started from m_pCookieComputer
|
|
//
|
|
Result = DisplaySubtree(NULL, m_pCookieComputer, &HasProblem);
|
|
|
|
if (HasProblem && Result) {
|
|
m_pIDMTVOCX->Expand(TVE_EXPAND, (HTREEITEM)m_pCookieComputer->m_lParam);
|
|
}
|
|
|
|
//
|
|
// If we have a pre-selected item, use it. Otherwise, use computer
|
|
// as the selected node.
|
|
//
|
|
HTREEITEM hSelectedItem = (m_pSelectedCookie && m_pSelectedCookie->m_lParam) ?
|
|
(HTREEITEM)m_pSelectedCookie->m_lParam :
|
|
(HTREEITEM)m_pCookieComputer->m_lParam;
|
|
SetSelectOk(TRUE);
|
|
|
|
if (hSelectedItem) {
|
|
m_pIDMTVOCX->SelectItem(TVGN_CARET, hSelectedItem);
|
|
m_pIDMTVOCX->EnsureVisible(hSelectedItem);
|
|
}
|
|
}
|
|
|
|
::SendMessage(m_hwndTV, WM_SETREDRAW, TRUE, 0L);
|
|
InvalidateRect(m_hwndTV, NULL, TRUE);
|
|
|
|
return Result;
|
|
}
|
|
|
|
//
|
|
// This function walks through the given cookie subtree rooted by pCookie
|
|
// and insert each node into the TreeView OCX.
|
|
// INPUT:
|
|
// htiParent -- HTREEITEM for the new cookie to be inserted
|
|
// if NULL is given, TVI_ROOT is assumed.
|
|
// pCookie -- the subtree root cookie to be displayed.
|
|
// OUTPUT:
|
|
// none.
|
|
//
|
|
BOOL
|
|
CResultView::DisplaySubtree(
|
|
HTREEITEM htiParent,
|
|
CCookie* pCookie,
|
|
BOOL* pReportProblem
|
|
)
|
|
{
|
|
TV_INSERTSTRUCT ti;
|
|
CResultItem* pRltItem;
|
|
HTREEITEM hti;
|
|
BOOL bResource;
|
|
BOOL fShowHiddenDevices = m_pFolder->ShowHiddenDevices();
|
|
|
|
while (pCookie) {
|
|
pRltItem = pCookie->GetResultItem();
|
|
ti.item.state = INDEXTOOVERLAYMASK(0);
|
|
bResource = FALSE;
|
|
|
|
//
|
|
// The cookie is not yet in the treeview.
|
|
//
|
|
pCookie->m_lParam = 0;
|
|
|
|
if (COOKIE_TYPE_RESULTITEM_DEVICE == pCookie->GetType()) {
|
|
DWORD Status, Problem;
|
|
CDevice* pDevice = (CDevice*)pRltItem;
|
|
|
|
//
|
|
// This is a hidden device and we are not showing hidden devices
|
|
//
|
|
// Note that we need to special case these devices because they
|
|
// are not shown in the tree view, but their visible children are shown.
|
|
//
|
|
if (!fShowHiddenDevices && pDevice->IsHidden()) {
|
|
|
|
//
|
|
// If the cookie has children, display them
|
|
//
|
|
CCookie* pCookieChild = pCookie->GetChild();
|
|
BOOL ChildProblem = FALSE;
|
|
|
|
if (pCookieChild) {
|
|
DisplaySubtree(htiParent, pCookieChild, &ChildProblem);
|
|
}
|
|
|
|
//
|
|
// Continue on with the next device. This will skip all of the display
|
|
// code below.
|
|
//
|
|
pCookie = pCookie->GetSibling();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If the device is disabled then set the OVERLAYMASK to the Red X
|
|
//
|
|
if (pDevice->IsDisabled()) {
|
|
ti.item.state = INDEXTOOVERLAYMASK(IDI_DISABLED_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
|
|
*pReportProblem = TRUE;
|
|
}
|
|
|
|
//
|
|
// If the device has a problem then set the OVERLAYMASK to the Yellow !
|
|
//
|
|
else if (pDevice->HasProblem()) {
|
|
ti.item.state = INDEXTOOVERLAYMASK(IDI_PROBLEM_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
|
|
*pReportProblem = TRUE;
|
|
}
|
|
|
|
//
|
|
// if the device does not present, then set the state to TVIS_CUT. This grays out
|
|
// the icon a bit so it looks like a ghost icon.
|
|
//
|
|
else if (pDevice->IsPhantom()) {
|
|
ti.item.state = TVIS_CUT;
|
|
}
|
|
}
|
|
|
|
else if (COOKIE_TYPE_RESULTITEM_CLASS == pCookie->GetType()) {
|
|
CClass* pClass = (CClass*)pRltItem;
|
|
|
|
//
|
|
// If we don't have any devices to show for this class, or this
|
|
// is a NoDisplayClass and we are not showing hidden devices,
|
|
// then just get our next sibling and continue without showing
|
|
// this class.
|
|
//
|
|
if ((0 == pClass->GetNumberOfDevices(fShowHiddenDevices)) ||
|
|
(!fShowHiddenDevices && pClass->NoDisplay())) {
|
|
|
|
//
|
|
// Continue on with the next device. This will skip all of the display
|
|
// code below.
|
|
//
|
|
pCookie = pCookie->GetSibling();
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Is this a resource?
|
|
//
|
|
else if (COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_IO == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_DMA == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ == pCookie->GetType()) {
|
|
bResource = TRUE;
|
|
|
|
//
|
|
// If this is a FORCED CONFIG resource then overlay the forced
|
|
// config icon
|
|
//
|
|
if (((CResource*)pCookie->GetResultItem())->IsForced()) {
|
|
ti.item.state = INDEXTOOVERLAYMASK(IDI_FORCED_OVL-IDI_CLASSICON_OVERLAYFIRST+1);
|
|
}
|
|
}
|
|
|
|
|
|
ti.hParent = (htiParent != NULL) ? htiParent : TVI_ROOT;
|
|
ti.hInsertAfter = TVI_SORT;
|
|
ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
|
|
ti.item.iImage = ti.item.iSelectedImage = pRltItem->GetImageIndex();
|
|
|
|
if (bResource) {
|
|
ti.item.pszText = (LPTSTR)((CResource*)pRltItem)->GetViewName();
|
|
}
|
|
|
|
else {
|
|
ti.item.pszText = (LPTSTR)pRltItem->GetDisplayName();
|
|
}
|
|
|
|
ti.item.lParam = (LPARAM)pCookie;
|
|
ti.item.stateMask = TVIS_OVERLAYMASK | TVIS_CUT;
|
|
hti = m_pIDMTVOCX->InsertItem(&ti);
|
|
|
|
//
|
|
// Save the HTREEITEM
|
|
//
|
|
pCookie->m_lParam = (LPARAM)hti;
|
|
|
|
if (NULL != hti) {
|
|
//
|
|
// If the cookie has children, display them
|
|
//
|
|
CCookie* pCookieChild = pCookie->GetChild();
|
|
BOOL ChildProblem = FALSE;
|
|
|
|
if (pCookieChild) {
|
|
if (bResource && htiParent &&
|
|
GetDescriptionStringID() == IDS_STATUS_RESOURCES_BYTYPE) {
|
|
//
|
|
// This is a child of a resource being viewed by type,
|
|
// so the tree needs to be flattened. This is done by
|
|
// using the same parent.
|
|
//
|
|
DisplaySubtree(htiParent, pCookieChild, &ChildProblem);
|
|
}
|
|
|
|
else {
|
|
DisplaySubtree(hti, pCookieChild, &ChildProblem);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If any of the device's children have a problem, or if
|
|
// it was previously expanded, then expand it.
|
|
//
|
|
if (ChildProblem || pCookie->IsFlagsOn(COOKIE_FLAGS_EXPANDED)) {
|
|
m_pIDMTVOCX->Expand(TVE_EXPAND, hti);
|
|
}
|
|
|
|
//
|
|
// Propogate the child's problem state back to the parent
|
|
//
|
|
*pReportProblem |= ChildProblem;
|
|
}
|
|
|
|
pCookie = pCookie->GetSibling();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT
|
|
CResultView::GetResultViewType(
|
|
LPOLESTR* ppViewType,
|
|
long* pViewOptions
|
|
)
|
|
{
|
|
ASSERT(ppViewType && pViewOptions);
|
|
|
|
//
|
|
// The caller is responsible for freeing the memory we allocated.
|
|
//
|
|
LPOLESTR polestr;
|
|
polestr = AllocOleTaskString(OCX_TREEVIEW);
|
|
|
|
if (!polestr) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
*ppViewType = polestr;
|
|
|
|
//
|
|
// We have not list view options
|
|
//
|
|
*pViewOptions = MMC_VIEW_OPTIONS_NOLISTVIEWS;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CResultView::AddMenuItems(
|
|
CCookie* pCookie,
|
|
LPCONTEXTMENUCALLBACK pCallback,
|
|
long* pInsertionAllowed,
|
|
BOOL fContextMenu // True if for result view context menu
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CDevice* pDevice = NULL;
|
|
|
|
if (CCM_INSERTIONALLOWED_TOP & *pInsertionAllowed) {
|
|
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_pMachine->IsLocal() && g_HasLoadDriverNamePrivilege) {
|
|
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 == NULL) {
|
|
break;
|
|
}
|
|
|
|
CClass* pClass = pDevice->GetClass();
|
|
|
|
//
|
|
// All devices can have their driver's updated except for legacy devices.
|
|
//
|
|
if (!IsEqualGUID(*pClass, GUID_DEVCLASS_LEGACYDRIVER)) {
|
|
hr = AddMenuItem(pCallback, IDS_UPDATEDRIVER,
|
|
IDS_MENU_STATUS_UPDATEDRIVER, IDM_UPDATEDRIVER,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_ENABLED, 0);
|
|
}
|
|
|
|
//
|
|
// Only show the Enable/Disable menu item if the device
|
|
// can be disabled.
|
|
//
|
|
if (pDevice->IsDisableable()) {
|
|
if (pDevice->IsStateDisabled()) {
|
|
hr = AddMenuItem(pCallback, IDS_ENABLE,
|
|
IDS_MENU_STATUS_ENABLE, IDM_ENABLE,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_ENABLED, 0);
|
|
} else {
|
|
hr = AddMenuItem(pCallback, IDS_DISABLE,
|
|
IDS_MENU_STATUS_DISABLE, IDM_DISABLE,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_ENABLED, 0);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Only show the uninstall menu item if the device can be
|
|
// uninstalled.
|
|
//
|
|
if (SUCCEEDED(hr) &&
|
|
pDevice->IsUninstallable()) {
|
|
hr = AddMenuItem(pCallback, IDS_REMOVE,
|
|
IDS_MENU_STATUS_REMOVE, IDM_REMOVE,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_ENABLED, 0);
|
|
}
|
|
}
|
|
|
|
// FALL THROUGH........
|
|
|
|
case COOKIE_TYPE_RESULTITEM_CLASS:
|
|
if (g_HasLoadDriverNamePrivilege) {
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = AddMenuItem(pCallback, 0, 0, 0,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_ENABLED, CCM_SPECIAL_SEPARATOR);
|
|
}
|
|
if (SUCCEEDED(hr)) {
|
|
hr = AddMenuItem(pCallback, IDS_REFRESH,
|
|
IDS_MENU_STATUS_SCAN_CHANGES, IDM_REFRESH,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_ENABLED, 0);
|
|
}
|
|
}
|
|
|
|
if (fContextMenu) {
|
|
if (SUCCEEDED(hr)) {
|
|
hr = AddMenuItem(pCallback, 0, 0, 0,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_ENABLED, CCM_SPECIAL_SEPARATOR);
|
|
}
|
|
if (SUCCEEDED(hr)) {
|
|
hr = AddMenuItem(pCallback, IDS_PROPERTIES,
|
|
IDS_MENU_STATUS_PROPERTIES, IDM_PROPERTIES,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_DEFAULT, CCM_SPECIAL_DEFAULT_ITEM);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case COOKIE_TYPE_RESULTITEM_COMPUTER:
|
|
case COOKIE_TYPE_RESULTITEM_RESTYPE:
|
|
if (g_HasLoadDriverNamePrivilege) {
|
|
|
|
hr = AddMenuItem(pCallback, IDS_REFRESH,
|
|
IDS_MENU_STATUS_SCAN_CHANGES, IDM_REFRESH,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_ENABLED, 0);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// This function handles menu command for the device tree.
|
|
//
|
|
// INPUT: pCookie -- the cookie
|
|
// lCommandId -- the command. See AddMenuItems for valid command
|
|
// id for each type of cookie.
|
|
//
|
|
// OUTPUT: HRESULT S_OK if succeeded.
|
|
// S_XXX error code.
|
|
|
|
HRESULT
|
|
CResultView::MenuCommand(
|
|
CCookie* pCookie,
|
|
long lCommandId
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//TRACE1(TEXT("Menu command, commandid = %lx\n"), lCommandId);
|
|
ASSERT(pCookie);
|
|
|
|
CResultItem* pResultItem = pCookie->GetResultItem();
|
|
ASSERT(pResultItem);
|
|
|
|
CDevice* pDevice = NULL;
|
|
|
|
switch (pCookie->GetType()) {
|
|
case COOKIE_TYPE_RESULTITEM_DEVICE:
|
|
pDevice = (CDevice*)pResultItem;
|
|
break;
|
|
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_DMA:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_IO:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY:
|
|
CResource* pResource = (CResource*)pResultItem;
|
|
if (pResource) {
|
|
pDevice = pResource->GetDevice();
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (lCommandId) {
|
|
case IDM_UPDATEDRIVER:
|
|
if (pDevice) {
|
|
BOOL Installed;
|
|
DWORD RestartFlags = 0;
|
|
DWORD Status = 0, Problem = 0;
|
|
|
|
//
|
|
// If the device has the DN_WILL_BE_REMOVED flag set and the user is
|
|
// attempting to update the driver then we will prompt them for a
|
|
// reboot and include text in the prompt that explains this device
|
|
// is in the process of being removed.
|
|
//
|
|
if (pDevice->GetStatus(&Status, &Problem) &&
|
|
(Status & DN_WILL_BE_REMOVED)) {
|
|
|
|
PromptForRestart(m_hwndTV, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_UPDATE_DRIVER);
|
|
|
|
} else {
|
|
//
|
|
// Disable Refreshing while the Update Driver Wizard is up.
|
|
//
|
|
pDevice->m_pMachine->EnableRefresh(FALSE);
|
|
|
|
HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
Installed = pDevice->m_pMachine->InstallDevInst(m_hwndTV, pDevice->GetDeviceID(), TRUE, &RestartFlags);
|
|
|
|
if (hCursorOld) {
|
|
SetCursor(hCursorOld);
|
|
}
|
|
|
|
//
|
|
// Prompt for a restart if one is needed. If the user does NOT answer
|
|
// YES to the restart dialog then schedule a refresh since we might not
|
|
// get one from a WM_DEVICECHANGE.
|
|
//
|
|
if (m_pMachine->IsLocal()) {
|
|
if (PromptForRestart(NULL, RestartFlags) == IDNO) {
|
|
pDevice->m_pMachine->ScheduleRefresh();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enable Refreshing now that we are done updating the driver.
|
|
//
|
|
pDevice->m_pMachine->EnableRefresh(TRUE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_ENABLE:
|
|
case IDM_DISABLE:
|
|
if (pDevice) {
|
|
DWORD RestartFlags = 0;
|
|
DWORD Status = 0, Problem = 0;
|
|
|
|
//
|
|
// If the device has the DN_WILL_BE_REMOVED flag set and the user is
|
|
// attempting to enable/disable the driver then we will prompt them for a
|
|
// reboot and include text in the prompt that explains this device
|
|
// is in the process of being removed.
|
|
//
|
|
if (pDevice->GetStatus(&Status, &Problem) &&
|
|
(Status & DN_WILL_BE_REMOVED)) {
|
|
|
|
PromptForRestart(m_hwndTV, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_CHANGE_SETTINGS);
|
|
|
|
} else {
|
|
|
|
RestartFlags = pDevice->EnableDisableDevice(m_hwndTV,
|
|
(lCommandId == IDM_ENABLE));
|
|
|
|
//
|
|
// Update the toolbar buttons since the device just changed.
|
|
//
|
|
m_pFolder->m_pComponent->UpdateToolbar(pCookie);
|
|
|
|
//
|
|
// Prompt for a Restart if we are running locally.
|
|
// The PromptForRestart() API checks the flags to determine
|
|
// if a restart is actually needed.
|
|
//
|
|
if (m_pMachine->IsLocal()) {
|
|
if (PromptForRestart(NULL, RestartFlags) == IDNO) {
|
|
m_pMachine->ScheduleRefresh();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_REMOVE:
|
|
if (pDevice) {
|
|
hr = RemoveDevice(pDevice);
|
|
}
|
|
break;
|
|
|
|
case IDM_REFRESH:
|
|
//
|
|
// This will force every attached folder to recreate
|
|
// its machine data
|
|
//
|
|
ASSERT(m_pMachine);
|
|
|
|
if (!m_pMachine->Reenumerate()) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
break;
|
|
|
|
case IDM_PROPERTIES:
|
|
hr = DoProperties(m_hwndTV, pCookie);
|
|
break;
|
|
|
|
default:
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// This function reports if property pages are available for the
|
|
// given cookie. Returning S_FALSE, the cookie's "properties" menu
|
|
// item will not displayed.
|
|
//
|
|
// INPUT: pCookie -- the cookie
|
|
//
|
|
// OUTPUT: HRESULT S_OK if pages are available for the cookie.
|
|
// S_FALSE if no pages are available for the cookie.
|
|
HRESULT
|
|
CResultView::QueryPagesFor(
|
|
CCookie* pCookie
|
|
)
|
|
{
|
|
ASSERT(pCookie);
|
|
|
|
if (COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_DMA == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_IO == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_CLASS == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_DEVICE == pCookie->GetType()) {
|
|
return S_OK;
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
// This function creates property page(s) for the given cookie.
|
|
//
|
|
// INPUT: pCookie -- the cookie
|
|
// lpProvider -- interface pointer to IPROPERTYSHEETCALLBACK
|
|
// used to add HPROPSHEETPAGE to the property sheet.
|
|
// handle -- handle for property change notification
|
|
// The handle is required for MMCPropertyChangeNotify
|
|
// API.
|
|
// OUTPUT: HRESULT S_OK if succeeded.
|
|
// S_FALSE if no pages are added.
|
|
// S_XXX error code.
|
|
HRESULT
|
|
CResultView::CreatePropertyPages(
|
|
CCookie* pCookie,
|
|
LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LONG_PTR handle
|
|
)
|
|
{
|
|
//
|
|
// Design issue:
|
|
// We depend on the general page to do some houeskeeping works on the
|
|
// property sheet which is owned and controlled by MMC running in a
|
|
// separate thread. General page is always the first page and its window
|
|
// is always created. If we need to subclass the property sheet someday,
|
|
// having our own General page always assure that we will get the window
|
|
// handle to the property sheet.
|
|
//
|
|
// The most important housekeeping work the General page does is to inform the
|
|
// associate device or class when a property sheet is being created
|
|
// or destroyed. A device can not be removed if it has a property sheet
|
|
// running. The machine can not refresh the device tree if there are property
|
|
// sheet(s) running on any devices/classes it contains. Property sheets
|
|
// created by a folder should be canceled when the folder is being
|
|
// destroyed.
|
|
//
|
|
// So far, no class installers have attempted to add their own General
|
|
// page and I believe it will be true in the future because 1). the page
|
|
// is too complicated and overloaded with features(and hard to implement) and
|
|
// 2). no major gains can be obtained by implementing a new one.
|
|
// To warn the developers who does their own General page,we will have a
|
|
// message box warn them about this and proceed with OUR general page.
|
|
//
|
|
ASSERT(pCookie);
|
|
|
|
CPropSheetData* ppsd = NULL;
|
|
CMachine* pNewMachine = NULL;
|
|
|
|
switch (pCookie->GetType()) {
|
|
case COOKIE_TYPE_RESULTITEM_CLASS:
|
|
CClass* pClass;
|
|
pClass = (CClass*) pCookie->GetResultItem();
|
|
ASSERT(pClass);
|
|
|
|
//
|
|
// Create a new CMachine object that just contains this specific device
|
|
// and it's class. We need to do this since the CDevice and CClass of
|
|
// the cookie that was passed into this API will get destroyed whenever
|
|
// we get a WM_DEVICECHANGE notification.
|
|
//
|
|
PVOID Context;
|
|
pNewMachine = new CMachine(m_pMachine->GetMachineFullName());
|
|
|
|
CClass* pNewClass;
|
|
|
|
if (pNewMachine->Initialize(NULL, NULL, *pClass) &&
|
|
pNewMachine->GetFirstClass(&pNewClass, Context) &&
|
|
pNewClass) {
|
|
|
|
pNewMachine->m_ParentMachine = m_pMachine;
|
|
m_pMachine->AttachChildMachine(pNewMachine);
|
|
pNewMachine->SetPropertySheetShouldDestroy();
|
|
|
|
ppsd = &pNewClass->m_psd;
|
|
|
|
if (ppsd->Create(g_hInstance, m_hwndTV, MAX_PROP_PAGES, handle)) {
|
|
CDevInfoList* pClassDevInfo;
|
|
|
|
//
|
|
// The CDevInfoList object is maintained by the CClass
|
|
// object.
|
|
//
|
|
pClassDevInfo = pNewClass->GetDevInfoList();
|
|
|
|
if (pClassDevInfo && pClassDevInfo->DiGetClassDevPropertySheet(NULL,
|
|
&ppsd->m_psh,
|
|
MAX_PROP_PAGES,
|
|
pNewMachine->IsLocal() ?
|
|
DIGCDP_FLAG_ADVANCED :
|
|
DIGCDP_FLAG_REMOTE_ADVANCED)) {
|
|
if (pClassDevInfo->DiGetFlags(NULL) & DI_GENERALPAGE_ADDED) {
|
|
TCHAR szText[MAX_PATH];
|
|
LoadResourceString(IDS_GENERAL_PAGE_WARNING, szText,
|
|
ARRAYLEN(szText));
|
|
|
|
int ReturnValue;
|
|
m_pFolder->m_pComponent->m_pConsole->MessageBox(
|
|
szText, pNewClass->GetDisplayName(),
|
|
MB_ICONEXCLAMATION | MB_OK, &ReturnValue);
|
|
//
|
|
// fall through to create our general page.
|
|
//
|
|
}
|
|
|
|
SafePtr<CClassGeneralPage> GenPagePtr;
|
|
CClassGeneralPage* pGenPage;
|
|
pGenPage = new CClassGeneralPage;
|
|
|
|
if (pGenPage) {
|
|
GenPagePtr.Attach(pGenPage);
|
|
HPROPSHEETPAGE hPage = pGenPage->Create(pNewClass);
|
|
|
|
//
|
|
// General page has to be the first page
|
|
//
|
|
if (ppsd->InsertPage(hPage, 0)) {
|
|
GenPagePtr.Detach();
|
|
} else {
|
|
::DestroyPropertySheetPage(hPage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_DMA:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_IO:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY:
|
|
case COOKIE_TYPE_RESULTITEM_DEVICE:
|
|
CDevice* pDevice;
|
|
CDevice* pNewDevice;
|
|
|
|
pNewDevice = NULL;
|
|
|
|
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();
|
|
ASSERT(pResource);
|
|
pDevice = pResource->GetDevice();
|
|
}
|
|
ASSERT(pDevice);
|
|
|
|
//
|
|
// Create a new CMachine object that just contains this specific device
|
|
// and it's class. We need to do this since the CDevice and CClass of
|
|
// the cookie that was passed into this API will get destroyed whenever
|
|
// we get a WM_DEVICECHANGE notification.
|
|
//
|
|
PVOID DeviceContext;
|
|
pNewMachine = new CMachine(m_pMachine->GetMachineFullName());
|
|
|
|
if (pNewMachine->Initialize(NULL, pDevice->GetDeviceID()) &&
|
|
pNewMachine->GetFirstDevice(&pNewDevice, DeviceContext) &&
|
|
pNewDevice) {
|
|
|
|
pNewMachine->m_ParentMachine = m_pMachine;
|
|
m_pMachine->AttachChildMachine(pNewMachine);
|
|
pNewMachine->SetPropertySheetShouldDestroy();
|
|
|
|
ppsd = &pNewDevice->m_psd;
|
|
|
|
if (ppsd->Create(g_hInstance, m_hwndTV, MAX_PROP_PAGES, handle)) {
|
|
|
|
//
|
|
// Add any class/device specific property pages
|
|
//
|
|
pNewMachine->DiGetClassDevPropertySheet(*pNewDevice,
|
|
&ppsd->m_psh,
|
|
MAX_PROP_PAGES,
|
|
pNewMachine->IsLocal() ?
|
|
DIGCDP_FLAG_ADVANCED :
|
|
DIGCDP_FLAG_REMOTE_ADVANCED);
|
|
|
|
//
|
|
// Add the general tab
|
|
//
|
|
DWORD DiFlags = pNewMachine->DiGetFlags(*pNewDevice);
|
|
DWORD DiFlagsEx = pNewMachine->DiGetExFlags(*pNewDevice);
|
|
SafePtr<CDeviceGeneralPage> GenPagePtr;
|
|
|
|
if (DiFlags & DI_GENERALPAGE_ADDED) {
|
|
TCHAR szText[MAX_PATH];
|
|
LoadResourceString(IDS_GENERAL_PAGE_WARNING, szText,
|
|
ARRAYLEN(szText));
|
|
|
|
int ReturnValue;
|
|
m_pFolder->m_pComponent->m_pConsole->MessageBox(
|
|
szText, pNewDevice->GetDisplayName(),
|
|
MB_ICONEXCLAMATION | MB_OK, &ReturnValue);
|
|
//
|
|
// fall through to create our general page.
|
|
//
|
|
}
|
|
|
|
CDeviceGeneralPage* pGenPage = new CDeviceGeneralPage;
|
|
|
|
if (pGenPage) {
|
|
GenPagePtr.Attach(pGenPage);
|
|
HPROPSHEETPAGE hPage = pGenPage->Create(pNewDevice);
|
|
|
|
if (hPage) {
|
|
//
|
|
// General page has to be the first page
|
|
//
|
|
if (ppsd->InsertPage(hPage, 0)) {
|
|
GenPagePtr.Detach();
|
|
} else {
|
|
::DestroyPropertySheetPage(hPage);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the driver tab
|
|
//
|
|
SafePtr<CDeviceDriverPage> DrvPagePtr;
|
|
|
|
if (!(DiFlags & DI_DRIVERPAGE_ADDED)) {
|
|
CDeviceDriverPage* pPage = new CDeviceDriverPage;
|
|
|
|
if (pPage) {
|
|
DrvPagePtr.Attach(pPage);
|
|
HPROPSHEETPAGE hPage = pPage->Create(pNewDevice);
|
|
|
|
if (hPage) {
|
|
if (ppsd->InsertPage(hPage)) {
|
|
DrvPagePtr.Detach();
|
|
} else {
|
|
::DestroyPropertySheetPage(hPage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// add the details tab
|
|
//
|
|
// If the environment variable DEVMGR_SHOW_DETAILS does exist and it
|
|
// is not 0 then we will show the details tab
|
|
//
|
|
TCHAR Buffer[MAX_PATH];
|
|
DWORD BufferLen;
|
|
|
|
if (((BufferLen = ::GetEnvironmentVariable(TEXT("DEVMGR_SHOW_DETAILS"),
|
|
Buffer,
|
|
sizeof(Buffer)/sizeof(TCHAR))) != 0) &&
|
|
((BufferLen > 1) ||
|
|
(lstrcmp(Buffer, TEXT("0"))))) {
|
|
|
|
SafePtr<CDeviceDetailsPage> DetailsPagePtr;
|
|
|
|
CDeviceDetailsPage* pDetailsPage = new CDeviceDetailsPage;
|
|
DetailsPagePtr.Attach(pDetailsPage);
|
|
HPROPSHEETPAGE hPage = pDetailsPage->Create(pNewDevice);
|
|
|
|
if (hPage) {
|
|
if (ppsd->InsertPage(hPage)) {
|
|
DetailsPagePtr.Detach();
|
|
} else {
|
|
::DestroyPropertySheetPage(hPage);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the resource tab
|
|
//
|
|
if (pNewDevice->HasResources() && !(DiFlags & DI_RESOURCEPAGE_ADDED)) {
|
|
pNewMachine->DiGetExtensionPropSheetPage(*pNewDevice,
|
|
AddPropPageCallback,
|
|
SPPSR_SELECT_DEVICE_RESOURCES,
|
|
(LPARAM)ppsd
|
|
);
|
|
}
|
|
|
|
#ifndef _WIN64
|
|
//
|
|
// Add the power management tab
|
|
//
|
|
if (pNewMachine->IsLocal() && !(DiFlagsEx & DI_FLAGSEX_POWERPAGE_ADDED)) {
|
|
//
|
|
// Check if the device support power management
|
|
//
|
|
CPowerShutdownEnable ShutdownEnable;
|
|
CPowerWakeEnable WakeEnable;
|
|
|
|
if (ShutdownEnable.Open(pNewDevice->GetDeviceID()) || WakeEnable.Open(pNewDevice->GetDeviceID())) {
|
|
ShutdownEnable.Close();
|
|
WakeEnable.Close();
|
|
SafePtr<CDevicePowerMgmtPage> PowerMgmtPagePtr;
|
|
CDevicePowerMgmtPage* pPowerPage = new CDevicePowerMgmtPage;
|
|
|
|
if (pPowerPage) {
|
|
PowerMgmtPagePtr.Attach(pPowerPage);
|
|
HPROPSHEETPAGE hPage = pPowerPage->Create(pNewDevice);
|
|
|
|
if (hPage) {
|
|
if (ppsd->InsertPage(hPage)) {
|
|
PowerMgmtPagePtr.Detach();
|
|
} else {
|
|
::DestroyPropertySheetPage(hPage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Add any Bus specific property pages if this is the local machine
|
|
//
|
|
if (pNewMachine->IsLocal()) {
|
|
CBusPropPageProvider* pBusPropPageProvider = new CBusPropPageProvider();
|
|
|
|
if (pBusPropPageProvider) {
|
|
SafePtr<CBusPropPageProvider> ProviderPtr;
|
|
ProviderPtr.Attach(pBusPropPageProvider);
|
|
|
|
if (pBusPropPageProvider->EnumPages(pNewDevice, ppsd)) {
|
|
ppsd->AddProvider(pBusPropPageProvider);
|
|
ProviderPtr.Detach();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
HPROPSHEETPAGE hPage;
|
|
|
|
if (ppsd &&
|
|
ppsd->m_psh.nPages) {
|
|
PROPSHEETHEADER& psh = ppsd->m_psh;
|
|
|
|
for (UINT Index = 0; Index < psh.nPages; Index++) {
|
|
lpProvider->AddPage(psh.phpage[Index]);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// If we didn't add any pages then we need to delete the new CMachine we
|
|
// created.
|
|
//
|
|
if (pNewMachine) {
|
|
|
|
delete pNewMachine;
|
|
}
|
|
|
|
//
|
|
// No pages are added, return S_FALSE so that the responsible
|
|
// Component can do its clean up
|
|
//
|
|
return S_FALSE;
|
|
}
|
|
|
|
// This function handles notification codes from the TV OCX.
|
|
//
|
|
// INPUT:
|
|
// hwndTV -- the Window handle of the TV OCX.
|
|
// pCookie -- the cookie
|
|
// Code -- notification code.
|
|
// arg -- argument to the given notification code.
|
|
// param -- another parameter to the given notificaton code.
|
|
//
|
|
// OUTPUT:
|
|
// HRESULT -- S_OK if this function has processed the notification
|
|
// and the caller should not do any further processing.
|
|
// S_FALSE if the caller should do more processing.
|
|
HRESULT
|
|
CResultView::tvNotify(
|
|
HWND hwndTV,
|
|
CCookie* pCookie,
|
|
TV_NOTIFY_CODE Code,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (m_hwndTV != hwndTV) {
|
|
return S_FALSE;
|
|
}
|
|
|
|
//
|
|
// Presume that we do not handle the notification
|
|
//
|
|
hr = S_FALSE;
|
|
|
|
switch (Code) {
|
|
case TV_NOTIFY_CODE_DBLCLK:
|
|
if ((TVHT_ONITEM & param) &&
|
|
(COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_DMA == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_IO == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_DEVICE == pCookie->GetType())) {
|
|
if (SUCCEEDED(DoProperties(hwndTV, pCookie)))
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
|
|
case TV_NOTIFY_CODE_CONTEXTMENU:
|
|
if (SUCCEEDED(DoContextMenu(hwndTV, pCookie, (POINT*)param)))
|
|
hr = S_OK;
|
|
break;
|
|
|
|
case TV_NOTIFY_CODE_EXPANDED:
|
|
if (TVE_EXPAND & param) {
|
|
//TRACE1(TEXT("CResultView::tvNotify, TurnOnFlags(EXPANDED) Cookie = %lx\n"), pCookie);
|
|
pCookie->TurnOnFlags(COOKIE_FLAGS_EXPANDED);
|
|
} else if (TVE_COLLAPSE & param) {
|
|
//TRACE1(TEXT("CResultView:tvNotify, TurnOffFlags(EXPANDED) Cookie = %lx\n"), pCookie);
|
|
pCookie->TurnOffFlags(COOKIE_FLAGS_EXPANDED);
|
|
}
|
|
ASSERT(S_FALSE == hr);
|
|
break;
|
|
|
|
case TV_NOTIFY_CODE_FOCUSCHANGED:
|
|
// gaining the focus, set the console verbs and toolbar buttons
|
|
if (param) {
|
|
//TRACE((TEXT("CResultView::tvNotify -> TV_NOTIFY_CODE_FOCUSCHANGED, SelCookie = %lx"), pCookie));
|
|
UpdateConsoleVerbs(pCookie);
|
|
m_pFolder->m_pComponent->UpdateToolbar(pCookie);
|
|
}
|
|
break;
|
|
|
|
case TV_NOTIFY_CODE_SELCHANGED:
|
|
if (m_SelectOk) {
|
|
// These messages are ignored while the tree is being changed.
|
|
m_pSelectedCookie = pCookie;
|
|
|
|
//TRACE((TEXT("CResultView::tvNotify -> TV_NOTIFY_CODE_SELCHANGED, SelCookie = %lx"), pCookie));
|
|
|
|
UpdateConsoleVerbs(pCookie);
|
|
m_pFolder->m_pComponent->UpdateToolbar(pCookie);
|
|
}
|
|
|
|
break;
|
|
|
|
case TV_NOTIFY_CODE_KEYDOWN:
|
|
if (VK_RETURN == param) {
|
|
if (COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_DMA == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_IO == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_DEVICE == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_CLASS == pCookie->GetType()) {
|
|
if (SUCCEEDED(DoProperties(hwndTV, pCookie)))
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
else if (VK_DELETE == param &&
|
|
COOKIE_TYPE_RESULTITEM_DEVICE == pCookie->GetType()) {
|
|
|
|
//
|
|
// Remove the selected device
|
|
//
|
|
CDevice* pDevice = (CDevice*)pCookie->GetResultItem();
|
|
RemoveDevice(pDevice);
|
|
}
|
|
break;
|
|
|
|
case TV_NOTIFY_CODE_RCLICK:
|
|
case TV_NOTIFY_CODE_CLICK:
|
|
if (pCookie && pCookie->m_lParam) {
|
|
m_pIDMTVOCX->SelectItem(TVGN_CARET, (HTREEITEM)pCookie->m_lParam);
|
|
}
|
|
|
|
case TV_NOTIFY_CODE_GETDISPINFO:
|
|
default:
|
|
ASSERT(S_FALSE == hr);
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// This function updates console verbs based on the selected cookie type.
|
|
//
|
|
HRESULT
|
|
CResultView::UpdateConsoleVerbs(
|
|
CCookie* pCookie
|
|
)
|
|
{
|
|
BOOL bPropertiesEnabled = FALSE;
|
|
BOOL bPrintEnabled = FALSE;
|
|
|
|
if (!m_pFolder->m_bSelect) {
|
|
|
|
switch (pCookie->GetType()) {
|
|
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_DMA:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_IO:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY:
|
|
case COOKIE_TYPE_RESULTITEM_CLASS:
|
|
case COOKIE_TYPE_RESULTITEM_DEVICE:
|
|
bPropertiesEnabled = TRUE;
|
|
bPrintEnabled = TRUE;
|
|
break;
|
|
|
|
case COOKIE_TYPE_RESULTITEM_COMPUTER:
|
|
bPrintEnabled = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Only show the Print button/Action menu item when a something is selected.
|
|
//
|
|
if (bPrintEnabled) {
|
|
|
|
m_pFolder->m_pComponent->m_pConsoleVerb->SetVerbState(MMC_VERB_PRINT, HIDDEN, FALSE);
|
|
m_pFolder->m_pComponent->m_pConsoleVerb->SetVerbState(MMC_VERB_PRINT, ENABLED, TRUE);
|
|
|
|
} else {
|
|
|
|
m_pFolder->m_pComponent->m_pConsoleVerb->SetVerbState(MMC_VERB_PRINT, HIDDEN, TRUE);
|
|
}
|
|
|
|
//
|
|
// Only show the properties button/Action menu item when a device/class is selected.
|
|
//
|
|
if (bPropertiesEnabled) {
|
|
|
|
m_pFolder->m_pComponent->m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, FALSE);
|
|
m_pFolder->m_pComponent->m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
|
|
m_pFolder->m_pComponent->m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES);
|
|
|
|
} else {
|
|
|
|
m_pFolder->m_pComponent->m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, TRUE);
|
|
m_pFolder->m_pComponent->m_pConsoleVerb->SetDefaultVerb(MMC_VERB_NONE);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CResultView::OnOcxNotify(
|
|
MMC_NOTIFY_TYPE event,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TV_ITEM TI;
|
|
|
|
switch (event) {
|
|
case MMCN_BTN_CLICK:
|
|
if ((MMC_CONSOLE_VERB)param == MMC_VERB_PROPERTIES) {
|
|
ASSERT(m_pIDMTVOCX);
|
|
TI.hItem = m_pIDMTVOCX->GetSelectedItem();
|
|
|
|
if (TI.hItem) {
|
|
TI.mask = TVIF_PARAM;
|
|
hr = m_pIDMTVOCX->GetItem(&TI);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = DoProperties(m_hwndTV, (CCookie*)TI.lParam);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MMCN_PRINT:
|
|
hr = DoPrint();
|
|
break;
|
|
|
|
case MMCN_SELECT:
|
|
ASSERT(m_pIDMTVOCX);
|
|
TI.hItem = m_pIDMTVOCX->GetSelectedItem();
|
|
|
|
if (TI.hItem) {
|
|
TI.mask = TVIF_PARAM;
|
|
hr = m_pIDMTVOCX->GetItem(&TI);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = UpdateConsoleVerbs((CCookie*)TI.lParam);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// This function creates the propperty sheet for the given cookie.
|
|
// INPUT:
|
|
// hwndTV -- the window handle to the TV OCX, used as the parent
|
|
// window of the property sheet.
|
|
// pCookie -- the cookie.
|
|
// OUTPUT:
|
|
// HRESULT S_OK if the function succeeded.
|
|
// S_FALSE if no property sheet will be created.
|
|
// S_XXXX other error.
|
|
HRESULT
|
|
CResultView::DoProperties(
|
|
HWND hwndTV,
|
|
CCookie* pCookie
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// If a property sheet is aleady up for the node, bring the
|
|
// property sheet to the foreground.
|
|
//
|
|
HWND hWnd = NULL;
|
|
|
|
if (COOKIE_TYPE_RESULTITEM_DEVICE == pCookie->GetType()) {
|
|
CDevice* pDevice = (CDevice*)pCookie->GetResultItem();
|
|
ASSERT(pDevice);
|
|
hWnd = pDevice->m_pMachine->GetDeviceWindowHandle(pDevice->GetDeviceID());
|
|
}
|
|
|
|
else if (COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_DMA == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_IO == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY == pCookie->GetType()) {
|
|
//
|
|
// This is a resource item, get the pointer for the device
|
|
// object from the resource object.
|
|
//
|
|
CResource* pResource = (CResource*) pCookie->GetResultItem();
|
|
ASSERT(pResource);
|
|
CDevice* pDevice = pResource->GetDevice();
|
|
ASSERT(pDevice);
|
|
hWnd = pDevice->m_pMachine->GetDeviceWindowHandle(pDevice->GetDeviceID());
|
|
}
|
|
|
|
else if (COOKIE_TYPE_RESULTITEM_CLASS == pCookie->GetType()) {
|
|
CClass* pClass = (CClass*)pCookie->GetResultItem();
|
|
ASSERT(pClass);
|
|
hWnd = pClass->m_pMachine->GetClassWindowHandle(*pClass);
|
|
}
|
|
|
|
if (hWnd) {
|
|
//
|
|
// Notify the property sheet that it should go to foreground
|
|
// Do not call SetForegroundWindow here because the subclassed
|
|
// treeview control will grab the focus right after
|
|
// we have brought the property sheet to foreground.
|
|
//
|
|
::PostMessage(hWnd, PSM_QUERYSIBLINGS, QSC_TO_FOREGROUND, 0L);
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// No property sheet is up for this cookie, create a brand new property
|
|
// sheet for it.
|
|
//
|
|
SafeInterfacePtr<IComponent> pComponent;
|
|
SafeInterfacePtr<IPropertySheetProvider> pSheetProvider;
|
|
SafeInterfacePtr<IDataObject> pDataObject;
|
|
SafeInterfacePtr<IExtendPropertySheet> pExtendSheet;
|
|
pComponent.Attach((IComponent*) m_pFolder->m_pComponent);
|
|
|
|
if (FAILED(pComponent->QueryInterface(IID_IExtendPropertySheet, (void**) &pExtendSheet)) ||
|
|
FAILED(pComponent->QueryDataObject((MMC_COOKIE)pCookie, CCT_RESULT, &pDataObject)) ||
|
|
FAILED(m_pFolder->m_pComponent->m_pConsole->QueryInterface(IID_IPropertySheetProvider,
|
|
(void**) &pSheetProvider)) ||
|
|
S_OK == pSheetProvider->FindPropertySheet((MMC_COOKIE)pCookie, pComponent, pDataObject) ||
|
|
S_OK != pExtendSheet->QueryPagesFor(pDataObject)) {
|
|
return S_FALSE;
|
|
}
|
|
|
|
hr = pSheetProvider->CreatePropertySheet(
|
|
pCookie->GetResultItem()->GetDisplayName(),
|
|
TRUE, // not wizard
|
|
(MMC_COOKIE)pCookie, pDataObject,
|
|
MMC_PSO_NOAPPLYNOW // do not want the apply button
|
|
);
|
|
if (SUCCEEDED(hr)) {
|
|
HWND hNotifyWindow;
|
|
|
|
if (!SUCCEEDED(m_pFolder->m_pComponent->m_pConsole->GetMainWindow(&hNotifyWindow)))
|
|
hNotifyWindow = NULL;
|
|
|
|
hNotifyWindow = FindWindowEx(hNotifyWindow, NULL, TEXT("MDIClient"), NULL);
|
|
hNotifyWindow = FindWindowEx(hNotifyWindow, NULL, TEXT("MMCChildFrm"), NULL);
|
|
hNotifyWindow = FindWindowEx(hNotifyWindow, NULL, TEXT("MMCView"), NULL);
|
|
hr = pSheetProvider->AddPrimaryPages(pComponent, TRUE, hNotifyWindow, FALSE);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
pSheetProvider->AddExtensionPages();
|
|
hr = pSheetProvider->Show((LONG_PTR)hwndTV, 0);
|
|
} else {
|
|
//
|
|
// Failed to add primary Component's property page, destroy
|
|
// the property sheet
|
|
//
|
|
pSheetProvider->Show(-1, 0);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// This function creates a context menu for the given cookie
|
|
// INPUT:
|
|
// hwndTV -- the TV OCX window, as the window the context menu to be
|
|
// attached to.
|
|
// pCookie -- the cookie
|
|
// pPoint -- the location where the context menu should anchor in
|
|
// screen coordinate.
|
|
HRESULT
|
|
CResultView::DoContextMenu(
|
|
HWND hwndTV,
|
|
CCookie* pCookie,
|
|
POINT* pPoint
|
|
)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
CMachine *pMachine = NULL;
|
|
|
|
//
|
|
// ISSUE: JasonC 8/14/99
|
|
//
|
|
// If we have a valid cookie then we need to get the CMachine for the given
|
|
// cookie if there is one. Then we need to disable refreshing while the
|
|
// context menu is being displayed. The reason for this is that if we
|
|
// refresh while the menu is displayed but before the user chooses an option
|
|
// then the cookie is no longer valid. The real problem here is that we rebuild
|
|
// all of the classes on a refresh which makes any cookie floating around invalid.
|
|
// I am sure that there is more of these bugs lurking around in the code and this
|
|
// needs to be addressed by a better overall change after NT 5.0.
|
|
//
|
|
if (pCookie) {
|
|
CDevice *pDevice;
|
|
CResource *pResource;
|
|
CClass *pClass;
|
|
|
|
switch (pCookie->GetType()) {
|
|
|
|
case COOKIE_TYPE_RESULTITEM_DEVICE:
|
|
pDevice = (CDevice*)pCookie->GetResultItem();
|
|
if (pDevice) {
|
|
pMachine = pDevice->m_pMachine;
|
|
}
|
|
break;
|
|
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_DMA:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_IO:
|
|
case COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY:
|
|
pResource = (CResource*)pCookie->GetResultItem();
|
|
if (pResource) {
|
|
pDevice = pResource->GetDevice();
|
|
|
|
if (pDevice) {
|
|
pMachine = pDevice->m_pMachine;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case COOKIE_TYPE_RESULTITEM_CLASS:
|
|
pClass = (CClass*)pCookie->GetResultItem();
|
|
if (pClass) {
|
|
pMachine = pClass->m_pMachine;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pMachine = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Disable Refreshing while the context menu is up.
|
|
//
|
|
if (pMachine) {
|
|
pMachine->EnableRefresh(FALSE);
|
|
}
|
|
|
|
SafeInterfacePtr<IDataObject> pDataObject;
|
|
SafeInterfacePtr<IContextMenuProvider> pMenuProvider;
|
|
SafeInterfacePtr<IComponent> pComponent;
|
|
pComponent.Attach((IComponent*)m_pFolder->m_pComponent);
|
|
m_hwndTV = hwndTV;
|
|
|
|
if (FAILED(pComponent->QueryDataObject((MMC_COOKIE)pCookie, CCT_RESULT, &pDataObject)) ||
|
|
FAILED(m_pFolder->m_pComponent->m_pConsole->QueryInterface(IID_IContextMenuProvider,
|
|
(void**)&pMenuProvider))) {
|
|
hr = S_FALSE;
|
|
goto clean0;
|
|
}
|
|
|
|
pMenuProvider->EmptyMenuList();
|
|
CONTEXTMENUITEM MenuItem;
|
|
MenuItem.strName = NULL;
|
|
MenuItem.strStatusBarText = NULL;
|
|
MenuItem.lCommandID = CCM_INSERTIONPOINTID_PRIMARY_TOP;
|
|
MenuItem.lInsertionPointID = 0;
|
|
MenuItem.fFlags = 0;
|
|
MenuItem.fSpecialFlags = CCM_SPECIAL_INSERTION_POINT;
|
|
|
|
if (SUCCEEDED(pMenuProvider->AddItem(&MenuItem)) &&
|
|
SUCCEEDED(pMenuProvider->AddPrimaryExtensionItems(pComponent,
|
|
pDataObject)) &&
|
|
SUCCEEDED(pMenuProvider->AddThirdPartyExtensionItems(pDataObject))) {
|
|
long Selected;
|
|
pMenuProvider->ShowContextMenu(hwndTV, pPoint->x, pPoint->y, &Selected);
|
|
hr = S_OK;
|
|
goto clean0;
|
|
}
|
|
|
|
clean0:
|
|
|
|
//
|
|
// Enable Refreshing again now that the context menu is gone
|
|
//
|
|
if (pMachine) {
|
|
pMachine->EnableRefresh(TRUE);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CResultView::DoPrint()
|
|
{
|
|
DWORD ReportTypeEnableMask;
|
|
ReportTypeEnableMask = REPORT_TYPE_MASK_ALL;
|
|
HTREEITEM hSelectedItem;
|
|
CCookie* pCookie = NULL;
|
|
|
|
m_pMachine->EnableRefresh(FALSE);
|
|
|
|
if (m_pIDMTVOCX) {
|
|
|
|
hSelectedItem = m_pIDMTVOCX->GetSelectedItem();
|
|
|
|
if (hSelectedItem) {
|
|
|
|
TV_ITEM TI;
|
|
TI.hItem = hSelectedItem;
|
|
TI.mask = TVIF_PARAM;
|
|
|
|
if (SUCCEEDED(m_pIDMTVOCX->GetItem(&TI))) {
|
|
|
|
pCookie = (CCookie*)TI.lParam;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pCookie || (COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ != pCookie->GetType() &&
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_DMA != pCookie->GetType() &&
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_IO != pCookie->GetType() &&
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY != pCookie->GetType() &&
|
|
COOKIE_TYPE_RESULTITEM_DEVICE != pCookie->GetType() &&
|
|
COOKIE_TYPE_RESULTITEM_CLASS != pCookie->GetType())) {
|
|
|
|
ReportTypeEnableMask &= ~(REPORT_TYPE_MASK_CLASSDEVICE);
|
|
}
|
|
|
|
if (!g_PrintDlg.PrintDlg(m_pMachine->OwnerWindow(), ReportTypeEnableMask)) {
|
|
|
|
m_pMachine->EnableRefresh(TRUE);
|
|
return S_OK;
|
|
}
|
|
|
|
if (!g_PrintDlg.HDC()) {
|
|
|
|
m_pMachine->EnableRefresh(TRUE);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Create the printer
|
|
//
|
|
CPrinter ThePrinter(m_pMachine->OwnerWindow(), g_PrintDlg.HDC());
|
|
TCHAR DocTitle[MAX_PATH];
|
|
LoadString(g_hInstance, IDS_PRINT_DOC_TITLE, DocTitle, ARRAYLEN(DocTitle));
|
|
int PrintStatus;
|
|
|
|
switch (g_PrintDlg.ReportType()) {
|
|
case REPORT_TYPE_SUMMARY:
|
|
PrintStatus = ThePrinter.StartDoc(DocTitle);
|
|
|
|
if (PrintStatus) {
|
|
|
|
ThePrinter.SetPageTitle(IDS_PRINT_SUMMARY_PAGE_TITLE);
|
|
PrintStatus = ThePrinter.PrintResourceSummary(*m_pMachine);
|
|
}
|
|
break;
|
|
|
|
case REPORT_TYPE_CLASSDEVICE:
|
|
ASSERT(pCookie);
|
|
PrintStatus = ThePrinter.StartDoc(DocTitle);
|
|
|
|
if (PrintStatus) {
|
|
|
|
ThePrinter.SetPageTitle(IDS_PRINT_CLASSDEVICE_PAGE_TITLE);
|
|
|
|
if (COOKIE_TYPE_RESULTITEM_CLASS == pCookie->GetType()) {
|
|
|
|
PrintStatus = ThePrinter.PrintClass((CClass*)pCookie->GetResultItem());
|
|
|
|
} else {
|
|
|
|
CDevice* pDevice;
|
|
|
|
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();
|
|
ASSERT(pResource);
|
|
pDevice = pResource->GetDevice();
|
|
}
|
|
|
|
ASSERT(pDevice);
|
|
PrintStatus = ThePrinter.PrintDevice(pDevice);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case REPORT_TYPE_SUMMARY_CLASSDEVICE:
|
|
PrintStatus = ThePrinter.StartDoc(DocTitle);
|
|
|
|
if (PrintStatus) {
|
|
|
|
ThePrinter.SetPageTitle(IDS_PRINT_SUMMARY_CLASSDEVICE_PAGE_TITLE);
|
|
PrintStatus = ThePrinter.PrintAll(*m_pMachine);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Flush the last page
|
|
//
|
|
ThePrinter.FlushPage();
|
|
|
|
if (PrintStatus) {
|
|
|
|
ThePrinter.EndDoc();
|
|
|
|
} else {
|
|
|
|
ThePrinter.AbortDoc();
|
|
}
|
|
|
|
m_pMachine->EnableRefresh(TRUE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CResultView::RemoveDevice(
|
|
CDevice* pDevice
|
|
)
|
|
{
|
|
//
|
|
// Must be an admin and on the local machine to remove a device.
|
|
//
|
|
if (!m_pMachine->IsLocal() || !g_HasLoadDriverNamePrivilege) {
|
|
//
|
|
// Must be an admin and on the local machine to remove a device.
|
|
//
|
|
return S_FALSE;
|
|
}
|
|
|
|
//
|
|
// Make sure the device can be uninstalled
|
|
//
|
|
if (!pDevice->IsUninstallable()) {
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
//
|
|
// Make sure there is no property sheet up for this device.
|
|
// If it does exist, show a message box for the user and bring up
|
|
// the property sheet to the foreground if the user
|
|
// agree to do so.
|
|
//
|
|
HWND hwndPropSheet;
|
|
hwndPropSheet = pDevice->m_psd.GetWindowHandle();
|
|
int MsgBoxResult;
|
|
TCHAR szText[MAX_PATH];
|
|
|
|
if (hwndPropSheet) {
|
|
LoadResourceString(IDS_PROPSHEET_WARNING, szText, ARRAYLEN(szText));
|
|
MsgBoxResult = m_pFolder->m_pComponent->MessageBox(szText,
|
|
pDevice->GetDisplayName(),
|
|
MB_ICONEXCLAMATION | MB_OKCANCEL);
|
|
|
|
if (IDOK == MsgBoxResult) {
|
|
SetForegroundWindow(hwndPropSheet);
|
|
}
|
|
|
|
//
|
|
// Can not wait for the property sheet because it is running
|
|
// in a separate thread.
|
|
//
|
|
return S_OK;
|
|
}
|
|
|
|
BOOL Refresh = (pDevice->IsPhantom() ||
|
|
pDevice->HasProblem() ||
|
|
!pDevice->IsStarted());
|
|
|
|
CRemoveDevDlg TheDlg(pDevice);
|
|
|
|
//
|
|
// Before removing device, disable refresh. This effectively disables
|
|
// device change notification processing. While we are in the middle
|
|
// of removing device, it is not a good idea to process any
|
|
// device change notification. When the removal is done,
|
|
// we will re-enable the refresh.
|
|
//
|
|
m_pMachine->EnableRefresh(FALSE);
|
|
|
|
if (IDOK == TheDlg.DoModal(m_hwndTV, (LPARAM) &TheDlg)) {
|
|
DWORD DiFlags;
|
|
DiFlags = m_pMachine->DiGetFlags(*pDevice);
|
|
|
|
//
|
|
// We don't check to see if we are running locally at this
|
|
// point because we won't let the user remove the device in
|
|
// the first place if we are not running locally.
|
|
//
|
|
if (PromptForRestart(NULL, DiFlags, IDS_REMOVEDEV_RESTART) == IDNO) {
|
|
|
|
Refresh = TRUE;
|
|
}
|
|
|
|
//
|
|
// Enable refresh since we disabled it in the beginning.
|
|
//
|
|
// We only need to force a refresh here if the device that
|
|
// was removed was a Phantom device or a device that is not
|
|
// started. This is because Phantom devices don't have kernel
|
|
// devnodes and so they won't generate a WM_DEVICECHANGE like
|
|
// live started devnodes will.
|
|
//
|
|
if (Refresh) {
|
|
|
|
m_pMachine->ScheduleRefresh();
|
|
}
|
|
|
|
m_pMachine->EnableRefresh(TRUE);
|
|
}
|
|
|
|
else {
|
|
m_pMachine->EnableRefresh(TRUE);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//// CViewDeviceTree implementations
|
|
////
|
|
|
|
HRESULT
|
|
CViewDeviceTree::OnShow(
|
|
BOOL fShow
|
|
)
|
|
{
|
|
if (!fShow) {
|
|
return S_OK;
|
|
}
|
|
|
|
if (!m_pCookieComputer) {
|
|
CreateDeviceTree();
|
|
}
|
|
|
|
return CResultView::OnShow(fShow);
|
|
}
|
|
|
|
// This function creates a the root device for the device tree.
|
|
// INPUT:
|
|
// NONE.
|
|
// OUTPUT:
|
|
// TRUE if the device is created(Rooted at m_pCookieComputer).
|
|
// FALSE if the device is not created.
|
|
BOOL
|
|
CViewDeviceTree::CreateDeviceTree()
|
|
{
|
|
ASSERT(NULL == m_pCookieComputer);
|
|
m_pMachine = m_pFolder->m_pMachine;
|
|
|
|
//
|
|
// We shouldn't be here if there is not a machine created.
|
|
//
|
|
ASSERT(m_pMachine);
|
|
|
|
CComputer* pComputer = m_pMachine->m_pComputer;
|
|
|
|
//
|
|
// Make sure there is at least a computer
|
|
//
|
|
if (pComputer) {
|
|
m_pCookieComputer = new CCookie(COOKIE_TYPE_RESULTITEM_COMPUTER);
|
|
|
|
if (m_pCookieComputer) {
|
|
|
|
m_pCookieComputer->SetResultItem(pComputer);
|
|
m_pCookieComputer->SetScopeItem(m_pFolder->m_pScopeItem);
|
|
|
|
//
|
|
// Make sure that the computer is expanded and selected.
|
|
//
|
|
m_pCookieComputer->TurnOnFlags(COOKIE_FLAGS_EXPANDED);
|
|
|
|
//
|
|
// If there was no selection, choose the computer
|
|
//
|
|
if (!m_pSelectedItem || (*m_pSelectedItem == *m_pCookieComputer)) {
|
|
m_pSelectedCookie = m_pCookieComputer;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//// CViewTreeByType implementations
|
|
////
|
|
|
|
// This function creates a "view-by-type: device tree rooted at
|
|
// m_pCookieComputer.
|
|
//
|
|
// INPUT:
|
|
// NONE.
|
|
// OUTPUT:
|
|
// TRUE if the tree is created successfully.
|
|
// FALSE if tree is not created.
|
|
BOOL
|
|
CViewTreeByType::CreateDeviceTree()
|
|
{
|
|
if (!CViewDeviceTree::CreateDeviceTree()) {
|
|
return FALSE;
|
|
}
|
|
|
|
ASSERT(m_pCookieComputer);
|
|
CClass* pClass;
|
|
CDevice* pDevice;
|
|
CDevice* pDeviceLast;
|
|
CCookie* pCookieClass;
|
|
CCookie* pCookieClassParent;
|
|
CCookie* pCookieClassSibling;
|
|
CCookie* pCookieDevice;
|
|
CCookie* pCookieDeviceParent;
|
|
CCookie* pCookieDeviceSibling;
|
|
|
|
//
|
|
// Do not have sibling at this moment;
|
|
//
|
|
pCookieClassSibling = NULL;
|
|
|
|
//
|
|
// All classes are children of computer
|
|
//
|
|
pCookieClassParent = m_pCookieComputer;
|
|
|
|
pCookieDeviceParent;
|
|
pCookieDeviceSibling;
|
|
String strStartupDeviceId;
|
|
strStartupDeviceId = GetStartupDeviceId();
|
|
PVOID ContextClass, ContextDevice;
|
|
|
|
if (m_pMachine->GetFirstClass(&pClass, ContextClass)) {
|
|
do {
|
|
//
|
|
// We do not display a class if it does not have any
|
|
// devices in it.
|
|
//
|
|
if (pClass->GetNumberOfDevices(TRUE)) {
|
|
pCookieClass = new CCookie(COOKIE_TYPE_RESULTITEM_CLASS);
|
|
pCookieClass->SetResultItem(pClass);
|
|
pCookieClass->SetScopeItem(m_pFolder->m_pScopeItem);
|
|
|
|
//
|
|
// If the class was expanded before, mark it
|
|
// so that DisplayTree will expand it
|
|
//
|
|
RestoreSavedTreeState(pCookieClass);
|
|
|
|
//
|
|
// No sibling: this is the first child
|
|
//
|
|
if (pCookieClassParent && !pCookieClassSibling) {
|
|
pCookieClassParent->SetChild(pCookieClass);
|
|
}
|
|
|
|
pCookieClass->SetParent(pCookieClassParent);
|
|
|
|
if (pCookieClassSibling) {
|
|
pCookieClassSibling->SetSibling(pCookieClass);
|
|
}
|
|
|
|
pCookieClassSibling = pCookieClass;
|
|
|
|
//
|
|
// Classes are parent of devices
|
|
//
|
|
pCookieDeviceParent = pCookieClass;
|
|
pCookieDeviceSibling = NULL;
|
|
|
|
if (pClass->GetFirstDevice(&pDevice, ContextDevice)) {
|
|
do {
|
|
pCookieDevice = new CCookie(COOKIE_TYPE_RESULTITEM_DEVICE);
|
|
pCookieDevice->SetResultItem(pDevice);
|
|
pCookieDevice->SetScopeItem(m_pFolder->m_pScopeItem);
|
|
|
|
if (!strStartupDeviceId.IsEmpty() &&
|
|
!strStartupDeviceId.CompareNoCase(pDevice->GetDeviceID())) {
|
|
m_pSelectedCookie = pCookieDevice;
|
|
} else {
|
|
if (m_pSelectedItem && (*m_pSelectedItem == *pCookieDevice)) {
|
|
m_pSelectedCookie = pCookieDevice;
|
|
}
|
|
}
|
|
|
|
//
|
|
// No sibling: this is the first child
|
|
//
|
|
if (pCookieDeviceParent && !pCookieDeviceSibling) {
|
|
pCookieDeviceParent->SetChild(pCookieDevice);
|
|
}
|
|
|
|
pCookieDevice->SetParent(pCookieDeviceParent);
|
|
|
|
if (pCookieDeviceSibling) {
|
|
pCookieDeviceSibling->SetSibling(pCookieDevice);
|
|
}
|
|
|
|
pCookieDeviceSibling = pCookieDevice;
|
|
|
|
} while (pClass->GetNextDevice(&pDevice, ContextDevice));
|
|
}
|
|
}
|
|
|
|
} while (m_pMachine->GetNextClass(&pClass, ContextClass));
|
|
}
|
|
|
|
DestroySavedTreeStates();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//// CViewTreeByConnection implementations
|
|
////
|
|
|
|
BOOL
|
|
CViewTreeByConnection::CreateDeviceTree()
|
|
{
|
|
if (!CViewDeviceTree::CreateDeviceTree()) {
|
|
return FALSE;
|
|
}
|
|
|
|
ASSERT(m_pCookieComputer);
|
|
CComputer* pComputer = (CComputer*)m_pCookieComputer->GetResultItem();
|
|
CDevice* pDeviceStart = pComputer->GetChild();
|
|
ASSERT(pDeviceStart);
|
|
|
|
//
|
|
// Collect all the normal devices.
|
|
//
|
|
CreateSubtree(m_pCookieComputer, NULL, pDeviceStart);
|
|
|
|
//
|
|
// Add phantom devices to m_pCookieComputer subtree.
|
|
//
|
|
PVOID Context;
|
|
|
|
if (m_pMachine->GetFirstDevice(&pDeviceStart, Context)) {
|
|
//
|
|
// Locate the end of the CookieComputer Sibling list to add the
|
|
// phantom devices to.
|
|
//
|
|
CCookie* pCookieSibling = NULL;
|
|
CCookie* pNext = m_pCookieComputer->GetChild();
|
|
|
|
while (pNext != NULL) {
|
|
pCookieSibling = pNext;
|
|
pNext = pCookieSibling->GetSibling();
|
|
}
|
|
|
|
do {
|
|
if (pDeviceStart->IsPhantom()) {
|
|
CCookie* pCookie;
|
|
pCookie = new CCookie(COOKIE_TYPE_RESULTITEM_DEVICE);
|
|
pCookie->SetResultItem(pDeviceStart);
|
|
pCookie->SetScopeItem(m_pFolder->m_pScopeItem);
|
|
|
|
if (pCookieSibling) {
|
|
pCookieSibling->SetSibling(pCookie);
|
|
} else {
|
|
m_pCookieComputer->SetChild(pCookie);
|
|
}
|
|
|
|
pCookie->SetParent(m_pCookieComputer);
|
|
pCookieSibling = pCookie;
|
|
|
|
//
|
|
// See if we have to expand the node
|
|
//
|
|
RestoreSavedTreeState(pCookie);
|
|
}
|
|
|
|
} while (m_pMachine->GetNextDevice(&pDeviceStart, Context));
|
|
}
|
|
|
|
DestroySavedTreeStates();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
//This function creates a cookie subtree by walking down the
|
|
//a device subtree led by the given pDeviceStart
|
|
//INPUT:
|
|
// pCookieParent -- the parent of the newly created subtree
|
|
// pCookieSibling -- the sibling of the newly create subtree
|
|
// pDeviceStart -- the device to start with
|
|
//
|
|
//OUTPUT:
|
|
// TRUE if the subtree is created and inserted successfully.
|
|
//
|
|
// This function may throw CMemoryException
|
|
//
|
|
BOOL
|
|
CViewTreeByConnection::CreateSubtree(
|
|
CCookie* pCookieParent,
|
|
CCookie* pCookieSibling,
|
|
CDevice* pDeviceStart
|
|
)
|
|
{
|
|
CCookie* pCookie;
|
|
CDevice* pDeviceChild;
|
|
String strStartupDeviceId;
|
|
CClass* pClass;
|
|
strStartupDeviceId = GetStartupDeviceId();
|
|
|
|
while (pDeviceStart) {
|
|
pClass = pDeviceStart->GetClass();
|
|
|
|
pCookie = new CCookie(COOKIE_TYPE_RESULTITEM_DEVICE);
|
|
|
|
if (pCookie) {
|
|
pCookie->SetResultItem(pDeviceStart);
|
|
pCookie->SetScopeItem(m_pFolder->m_pScopeItem);
|
|
|
|
if (!strStartupDeviceId.IsEmpty() &&
|
|
!strStartupDeviceId.CompareNoCase(pDeviceStart->GetDeviceID())) {
|
|
m_pSelectedCookie = pCookie;
|
|
}
|
|
|
|
//
|
|
// No sibling: this is the first child
|
|
//
|
|
if (pCookieParent && !pCookieSibling) {
|
|
pCookieParent->SetChild(pCookie);
|
|
}
|
|
|
|
pCookie->SetParent(pCookieParent);
|
|
|
|
if (pCookieSibling) {
|
|
pCookieSibling->SetSibling(pCookie);
|
|
}
|
|
|
|
//
|
|
// See if we have to expand the node
|
|
//
|
|
RestoreSavedTreeState(pCookie);
|
|
|
|
pDeviceChild = pDeviceStart->GetChild();
|
|
|
|
if (pDeviceChild) {
|
|
CreateSubtree(pCookie, NULL, pDeviceChild);
|
|
}
|
|
|
|
pCookieSibling = pCookie;
|
|
|
|
}
|
|
|
|
pDeviceStart = pDeviceStart->GetSibling();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//// CViewResourceTree implementations
|
|
////
|
|
|
|
CViewResourceTree::~CViewResourceTree()
|
|
{
|
|
int i;
|
|
|
|
//
|
|
// Destroy all the CResource objects
|
|
//
|
|
for (i = 0; i < TOTAL_RESOURCE_TYPES; i++) {
|
|
if (m_pResourceList[i]) {
|
|
delete m_pResourceList[i];
|
|
m_pResourceList[i] = NULL;
|
|
}
|
|
|
|
if (m_pResourceType[i]) {
|
|
delete m_pResourceType[i];
|
|
m_pResourceType[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// This functions handle MMC standard MMCN_SHOW command
|
|
//
|
|
// This function may throw CMemoryException
|
|
//
|
|
HRESULT
|
|
CViewResourceTree::OnShow(
|
|
BOOL fShow
|
|
)
|
|
{
|
|
if (!fShow) {
|
|
return S_OK;
|
|
}
|
|
|
|
if (!m_pCookieComputer) {
|
|
CreateResourceTree();
|
|
}
|
|
|
|
return CResultView::OnShow(fShow);
|
|
}
|
|
|
|
//
|
|
// This function creates resource lists and cookie trees.
|
|
// The resources are recorded in the member m_pResourceList[]
|
|
// and the cookie tree is rooted at m_pCookieComputer[];
|
|
//
|
|
// This function may throw CMemoryException
|
|
//
|
|
void
|
|
CViewResourceTree::CreateResourceTree()
|
|
{
|
|
int i;
|
|
CCookie* pCookieTypeSibling = NULL;
|
|
|
|
ASSERT(!m_pCookieComputer);
|
|
m_pMachine = m_pFolder->m_pMachine;
|
|
ASSERT(m_pMachine);
|
|
|
|
m_pCookieComputer = new CCookie(COOKIE_TYPE_RESULTITEM_COMPUTER);
|
|
|
|
if (!m_pCookieComputer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return;
|
|
}
|
|
|
|
m_pCookieComputer->SetResultItem(m_pMachine->m_pComputer);
|
|
m_pCookieComputer->SetScopeItem(m_pFolder->m_pScopeItem);
|
|
m_pCookieComputer->TurnOnFlags(COOKIE_FLAGS_EXPANDED);
|
|
|
|
//
|
|
// If no selected item recorded, default to the computer node
|
|
//
|
|
if (!m_pSelectedItem || (*m_pSelectedItem == *m_pCookieComputer)) {
|
|
m_pSelectedCookie = m_pCookieComputer;
|
|
}
|
|
|
|
//
|
|
// Check each resource type (mem, io, dma, irq) and create a result item
|
|
// if resources exist for the resource type.
|
|
//
|
|
for (i = 0; i < TOTAL_RESOURCE_TYPES; i++) {
|
|
RESOURCEID ResType = ResourceTypes[i];
|
|
|
|
//
|
|
// If there is an existing m_pResourceList then delete it.
|
|
//
|
|
if (m_pResourceList[i]) {
|
|
delete m_pResourceList[i];
|
|
}
|
|
|
|
m_pResourceList[i] = new CResourceList(m_pMachine, ResType);
|
|
|
|
PVOID Context;
|
|
CResource* pRes;
|
|
|
|
if (m_pResourceList[i] &&
|
|
m_pResourceList[i]->GetFirst(&pRes, Context)) {
|
|
//
|
|
// Resource items exist, create the resource type result item.
|
|
//
|
|
CCookie* pCookieFirst = NULL;
|
|
|
|
//
|
|
// If there is an existing m_pResourceType then delete it.
|
|
//
|
|
if (m_pResourceType[i]) {
|
|
delete m_pResourceType[i];
|
|
}
|
|
|
|
m_pResourceType[i] = new CResourceType(m_pMachine, ResType);
|
|
|
|
CCookie* pCookieType = new CCookie(COOKIE_TYPE_RESULTITEM_RESTYPE);
|
|
|
|
if (pCookieType) {
|
|
pCookieType->SetResultItem(m_pResourceType[i]);
|
|
pCookieType->SetScopeItem(m_pFolder->m_pScopeItem);
|
|
pCookieType->SetParent(m_pCookieComputer);
|
|
|
|
if (pCookieTypeSibling) {
|
|
pCookieTypeSibling->SetSibling(pCookieType);
|
|
} else {
|
|
m_pCookieComputer->SetChild(pCookieType);
|
|
}
|
|
pCookieTypeSibling = pCookieType;
|
|
|
|
RestoreSavedTreeState(pCookieType);
|
|
|
|
//
|
|
// Create the resource result item for each resource.
|
|
//
|
|
while (pRes) {
|
|
CCookie* pCookie = new CCookie(CookieType(ResType));
|
|
pCookie->SetResultItem(pRes);
|
|
pCookie->SetScopeItem(m_pFolder->m_pScopeItem);
|
|
|
|
if (pCookieFirst) {
|
|
InsertCookieToTree(pCookie, pCookieFirst, TRUE);
|
|
} else {
|
|
pCookieFirst = pCookie;
|
|
pCookieType->SetChild(pCookie);
|
|
pCookie->SetParent(pCookieType);
|
|
}
|
|
RestoreSavedTreeState(pCookie);
|
|
|
|
//
|
|
// Get the next resource item.
|
|
//
|
|
m_pResourceList[i]->GetNext(&pRes, Context);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// The saved tree states have been merged into the newly
|
|
// create cookie tree. destroy the states
|
|
//
|
|
DestroySavedTreeStates();
|
|
}
|
|
|
|
//
|
|
// This function insert the given cookie into a existing cookie subtree
|
|
// rooted at pCookieRoot. If the resource is I/O or MEMORY then the cookie is
|
|
// inserted as a child of any resource it is enclosed by.
|
|
//
|
|
//INPUT:
|
|
// pCookie -- the cookie to be inserted.
|
|
// pCookieRoot -- the subtree root cookie
|
|
// ForcedInsert -- TRUE to insert the cookie as the sibling of
|
|
// of pCookieRoot.
|
|
//OUTPUT:
|
|
// None
|
|
BOOL
|
|
CViewResourceTree::InsertCookieToTree(
|
|
CCookie* pCookie,
|
|
CCookie* pCookieRoot,
|
|
BOOL ForcedInsert
|
|
)
|
|
{
|
|
CResource* pResRef;
|
|
CResource* pResThis = (CResource*)pCookie->GetResultItem();
|
|
CCookie* pCookieLast;
|
|
BOOL Result = FALSE;
|
|
|
|
while (pCookieRoot) {
|
|
//
|
|
// Only check for enclosed resources for I/O and MEMORY.
|
|
//
|
|
if (COOKIE_TYPE_RESULTITEM_RESOURCE_IO == pCookie->GetType() ||
|
|
COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY == pCookie->GetType()) {
|
|
pResRef = (CResource*)pCookieRoot->GetResultItem();
|
|
|
|
if (pResThis->EnclosedBy(*pResRef)) {
|
|
//
|
|
// This cookie is either the pCookieRoot child or grand child
|
|
// figure out which one it is
|
|
//
|
|
if (!pCookieRoot->GetChild()) {
|
|
pCookieRoot->SetChild(pCookie);
|
|
pCookie->SetParent(pCookieRoot);
|
|
} else if (!InsertCookieToTree(pCookie, pCookieRoot->GetChild(), FALSE)) {
|
|
//
|
|
// The cookie is not a grand child of pCookieRoot.
|
|
// search for the last child of pCookieRoot
|
|
//
|
|
CCookie* pCookieSibling;
|
|
pCookieSibling = pCookieRoot->GetChild();
|
|
|
|
while (pCookieSibling->GetSibling()) {
|
|
pCookieSibling = pCookieSibling->GetSibling();
|
|
}
|
|
|
|
pCookieSibling->SetSibling(pCookie);
|
|
pCookie->SetParent(pCookieRoot);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
pCookieLast = pCookieRoot;
|
|
pCookieRoot = pCookieRoot->GetSibling();
|
|
}
|
|
|
|
if (ForcedInsert) {
|
|
//
|
|
// When we reach here, pCookieLast is the last child
|
|
//
|
|
pCookieLast->SetSibling(pCookie);
|
|
pCookie->SetParent(pCookieLast->GetParent());
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//// CBusPropPageProvider implementations
|
|
////
|
|
|
|
//
|
|
// This function loads the bus property sheet pages provider
|
|
// to enumerate pages for the device
|
|
// INPUT:
|
|
// pDevice -- object represents the device
|
|
// ppsd -- object represents where property pages should be added
|
|
// OUTPUT:
|
|
// TRUE if succeeded.
|
|
// FLASE if no pages are added.
|
|
BOOL
|
|
CBusPropPageProvider::EnumPages(
|
|
CDevice* pDevice,
|
|
CPropSheetData* ppsd
|
|
)
|
|
{
|
|
ASSERT(!m_hDll);
|
|
|
|
//
|
|
// Enum bus property pages if there are any
|
|
// if the a bus guid can not be found on the device, no bus property pages
|
|
//
|
|
String strBusGuid;
|
|
|
|
if (pDevice->m_pMachine->CmGetBusGuidString(pDevice->GetDevNode(), strBusGuid)) {
|
|
CSafeRegistry regDevMgr;
|
|
CSafeRegistry regBusTypes;
|
|
CSafeRegistry regBus;
|
|
|
|
if (regDevMgr.Open(HKEY_LOCAL_MACHINE, REG_PATH_DEVICE_MANAGER) &&
|
|
regBusTypes.Open(regDevMgr, REG_STR_BUS_TYPES) &&
|
|
regBus.Open(regBusTypes, strBusGuid)) {
|
|
String strEnumPropPage;
|
|
|
|
if (regBus.GetValue(REGSTR_VAL_ENUMPROPPAGES_32, strEnumPropPage)) {
|
|
PROPSHEET_PROVIDER_PROC PropPageProvider;
|
|
|
|
if (LoadEnumPropPage32(strEnumPropPage, &m_hDll, (FARPROC*)&PropPageProvider)) {
|
|
SP_PROPSHEETPAGE_REQUEST PropPageRequest;
|
|
PropPageRequest.cbSize = sizeof(PropPageRequest);
|
|
PropPageRequest.DeviceInfoSet = (HDEVINFO)*(pDevice->m_pMachine);
|
|
PropPageRequest.DeviceInfoData = *pDevice;
|
|
PropPageRequest.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
|
|
|
|
if (PropPageProvider(&PropPageRequest,
|
|
(LPFNADDPROPSHEETPAGE)AddPropPageCallback,
|
|
(LPARAM)ppsd
|
|
))
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|