windows-nt/Source/XPSP1/NT/shell/osshell/snapins/devmgr/snapin/cfolder.cpp

3626 lines
107 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}