Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1087 lines
23 KiB

/*++
Copyright (C) 1997-1999 Microsoft Corporation
Module Name:
compdata.cpp
Abstract:
This module implemets CComponentData class
Author:
William Hsieh (williamh) created
Revision History:
--*/
#include "devmgr.h"
#include "factory.h"
#include "genpage.h"
const WCHAR* const DM_COMPDATA_SIGNATURE = L"Device Manager";
CComponentData::CComponentData()
{
m_pScope = NULL;
m_pConsole = NULL;
m_pCookieRoot = NULL;
m_pScopeItemRoot = NULL;
//
// Static scope item default to device manager
//
m_ctRoot = COOKIE_TYPE_SCOPEITEM_DEVMGR;
m_hwndMain = NULL;
m_pMachine = NULL;
m_IsDirty = FALSE;
//
// Increment object count(used by CanUnloadNow)
//
::InterlockedIncrement(&CClassFactory::s_Objects);
m_Ref = 1;
}
CComponentData::~CComponentData()
{
//
// All QIed interfaces should be released during
// Destroy method
//
ASSERT(NULL == m_pScope);
ASSERT(NULL == m_pConsole);
ASSERT(NULL == m_pCookieRoot);
//
// decrement object count(used by CanUnloadNow)
//
::InterlockedDecrement(&CClassFactory::s_Objects);
}
//
// IUnknown interface
//
ULONG
CComponentData::AddRef()
{
::InterlockedIncrement((LONG*)&m_Ref);
return m_Ref;
}
ULONG
CComponentData::Release()
{
::InterlockedDecrement((LONG*)&m_Ref);
if (!m_Ref)
{
delete this;
return 0;
}
return m_Ref;
}
STDMETHODIMP
CComponentData::QueryInterface(
REFIID riid,
void** ppv
)
{
if (!ppv)
{
return E_INVALIDARG;
}
HRESULT hr = S_OK;
if (IsEqualIID(riid, IID_IUnknown))
{
*ppv = (IUnknown*)(IComponentData*)this;
}
else if (IsEqualIID(riid, IID_IComponentData))
{
*ppv = (IComponentData*)this;
}
else if (IsEqualIID(riid, IID_IExtendContextMenu))
{
*ppv = (IExtendContextMenu*)this;
}
else if (IsEqualIID(riid, IID_IExtendPropertySheet))
{
*ppv = (IExtendPropertySheet*)this;
}
else if (IsEqualIID(riid, IID_IPersistStream))
{
*ppv = (IPersistStream*)this;
}
else if (IsEqualIID(riid, IID_ISnapinHelp))
{
*ppv = (ISnapinHelp*)this;
}
else
{
*ppv = NULL;
hr = E_NOINTERFACE;
}
if (SUCCEEDED(hr))
{
AddRef();
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// IComponentData implementation
///
STDMETHODIMP
CComponentData::Initialize(
LPUNKNOWN pUnknown
)
{
if (!pUnknown)
{
return E_INVALIDARG;
}
HRESULT hr;
try
{
//
// This function should be called only once.
//
ASSERT(NULL == m_pScope);
//
// Get the IConsoleNameSpace interface
//
hr = pUnknown->QueryInterface(IID_IConsoleNameSpace, (void**)&m_pScope);
if (SUCCEEDED(hr))
{
hr = pUnknown->QueryInterface(IID_IConsole, (void**)&m_pConsole);
if (SUCCEEDED(hr))
{
//
// Retreive the console main window. It will be used
// as the parent window of property sheets and
// parent handle for setupapi calls
//
m_pConsole->GetMainWindow(&m_hwndMain);
LoadScopeIconsForScopePane();
}
else
{
//
// Unable to the IConsole Interface
//
m_pScope->Release();
}
}
}
catch (CMemoryException* e)
{
e->Delete();
MsgBoxParam(m_hwndMain, 0, 0, 0);
hr = E_OUTOFMEMORY;
}
return hr;
}
// This function creates a new CComponent
// A Component will be created when a new "window" is being created.
//
STDMETHODIMP
CComponentData::CreateComponent(
LPCOMPONENT* ppComponent
)
{
HRESULT hr;
if (!ppComponent)
{
return E_INVALIDARG;
}
try
{
CComponent* pComponent = new CComponent(this);
//
// Return the IComponent interface
//
hr = pComponent->QueryInterface(IID_IComponent, (void**)ppComponent);
pComponent->Release();
if (SUCCEEDED(hr))
{
hr = CreateScopeItems();
if (SUCCEEDED(hr))
{
hr = pComponent->CreateFolderList(m_pCookieRoot);
}
else
{
pComponent->Release();
*ppComponent = NULL;
}
}
}
catch (CMemoryException* e)
{
e->Delete();
MsgBoxParam(m_hwndMain, 0, 0, 0);
hr = E_OUTOFMEMORY;
}
return hr;
}
STDMETHODIMP
CComponentData::Notify(
LPDATAOBJECT lpDataObject,
MMC_NOTIFY_TYPE event,
LPARAM arg,
LPARAM param
)
{
HRESULT hr;
try
{
//
// On MMCN_PROPERTY_CHANGE event, lpDataObject is invalid
// Donot touch it.
//
if (MMCN_PROPERTY_CHANGE == event)
{
PPROPERTY_CHANGE_INFO pPCI = (PPROPERTY_CHANGE_INFO) param;
if (pPCI && PCT_STARTUP_INFODATA == pPCI->Type)
{
PSTARTUP_INFODATA pSI = (PSTARTUP_INFODATA)&pPCI->InfoData;
ASSERT(pSI->Size == sizeof(STARTUP_INFODATA));
if (pSI->MachineName[0] != _T('\0'))
{
m_strMachineName = pSI->MachineName;
}
m_ctRoot = pSI->ct;
SetDirty();
}
return S_OK;
}
else if (MMCN_EXPAND == event)
{
return OnExpand(lpDataObject, arg, param);
}
else if (MMCN_REMOVE_CHILDREN == event)
{
//
// This is basically a hack!!!!
// When the target computer is switched in Computer Management
// snapin(we are an extention to it), we basically get
// a MMCN_REMOVE_CHILDREN followed by MMCN_EXPAND.
// The right thing for MMC to do is to create a new IComponent
// for each new machine so that each IComponent can maintain
// its own states(thus, its own folders).
// Well, it is not a perfect world and we are forced to use
// the old IComponent. So here we notify each scope node
// which in turns will notify all the CFolders.
//
// After reset, each folder does not attach to any CMachine object
// (thus, its m_pMachine will be NULL). Each folder will attach
// to the new machine object when its OnShow method is called
// the very "first" time.
//
if (!IsPrimarySnapin() && m_pScopeItemRoot)
{
ResetScopeItem(m_pScopeItemRoot);
}
return S_OK;
}
ASSERT(m_pScope);
INTERNAL_DATA tID;
hr = ExtractData(lpDataObject, CDataObject::m_cfSnapinInternal,
(PBYTE)&tID, sizeof(tID));
if (SUCCEEDED(hr))
{
switch (event) {
case MMCN_DELETE:
hr = OnDelete(tID.cookie, arg, param);
break;
case MMCN_RENAME:
hr = OnRename(tID.cookie, arg, param);
break;
case MMCN_CONTEXTMENU:
hr = OnContextMenu(tID.cookie, arg, param);
break;
case MMCN_BTN_CLICK:
hr = OnBtnClick(tID.cookie, arg, param);
break;
default:
hr = S_OK;
break;
}
}
}
catch(CMemoryException* e)
{
e->Delete();
hr = E_OUTOFMEMORY;
}
return hr;
}
STDMETHODIMP
CComponentData::GetDisplayInfo(
SCOPEDATAITEM* pScopeDataItem
)
{
if (!pScopeDataItem)
{
return E_INVALIDARG;
}
try
{
//
// IComponentData::GetDisplayInfo only deals with scope pane items.
// Snapin's IComponent::GetDisplayInfo will deal with result pane items
//
CCookie* pCookie = (CCookie*) pScopeDataItem->lParam;
ASSERT(pCookie);
return pCookie->GetScopeItem()->GetDisplayInfo(pScopeDataItem);
}
catch (CMemoryException* e)
{
e->Delete();
MsgBoxParam(m_hwndMain, 0, 0, 0);
return E_OUTOFMEMORY;
}
}
STDMETHODIMP
CComponentData::Destroy()
{
if (m_pCookieRoot)
{
delete m_pCookieRoot;
m_pCookieRoot = NULL;
}
if (m_pScopeItemRoot)
{
delete m_pScopeItemRoot;
}
if (m_pScope)
{
m_pScope->Release();
m_pScope = NULL;
}
if (m_pConsole)
{
m_pConsole->Release();
m_pConsole = NULL;
}
return S_OK;
}
STDMETHODIMP
CComponentData::QueryDataObject(
MMC_COOKIE cookie,
DATA_OBJECT_TYPES type,
LPDATAOBJECT* ppDataObject
)
{
CDataObject* pDataObject;
COOKIE_TYPE ct;
CCookie* pCookie;
try
{
pCookie = GetActiveCookie(cookie);
if (NULL == pCookie)
{
ct = m_ctRoot;
}
else
{
ct = pCookie->GetType();
}
pDataObject = new CDataObject;
pDataObject->Initialize(type, ct, pCookie, m_strMachineName);
pDataObject->AddRef();
*ppDataObject = pDataObject;
}
catch (CMemoryException* e)
{
e->Delete();
MsgBoxParam(m_hwndMain, 0, 0, 0);
return E_OUTOFMEMORY;
}
return S_OK;
}
STDMETHODIMP
CComponentData::CompareObjects(
LPDATAOBJECT lpDataObjectA,
LPDATAOBJECT lpDataObjectB
)
{
HRESULT hr;
try
{
INTERNAL_DATA tID_A, tID_B;
hr = ExtractData(lpDataObjectA, CDataObject::m_cfSnapinInternal,
(PBYTE)&tID_A, sizeof(tID_A));
if (SUCCEEDED(hr))
{
hr = ExtractData(lpDataObjectB, CDataObject::m_cfSnapinInternal,
(PBYTE)&tID_B, sizeof(tID_B));
if (SUCCEEDED(hr))
{
hr = (tID_A.ct == tID_B.ct && tID_A.cookie == tID_B.cookie &&
tID_A.dot == tID_B.dot) ? S_OK : S_FALSE;
}
}
}
catch(CMemoryException* e)
{
e->Delete();
MsgBoxParam(m_hwndMain, 0, 0, 0);
hr = E_OUTOFMEMORY;
}
return hr;
}
///////////////////////////////////////////////////////////////////
//// IExtendPropertySheet implementation
////
STDMETHODIMP
CComponentData::QueryPagesFor(
LPDATAOBJECT lpDataObject
)
{
HRESULT hr;
if (!lpDataObject)
{
return E_INVALIDARG;
}
try
{
INTERNAL_DATA tID;
hr = ExtractData(lpDataObject, CDataObject::m_cfSnapinInternal,
(PBYTE)&tID, sizeof(tID));
if (SUCCEEDED(hr))
{
CScopeItem* pScopeItem;
pScopeItem = FindScopeItem(tID.cookie);
if (CCT_SNAPIN_MANAGER == tID.dot && COOKIE_TYPE_SCOPEITEM_DEVMGR == tID.ct)
{
hr = S_OK;
}
else if (pScopeItem)
{
hr = pScopeItem->QueryPagesFor();
}
else
{
hr = S_FALSE;
}
}
}
catch (CMemoryException* e)
{
e->Delete();
MsgBoxParam(m_hwndMain, 0, 0, 0);
hr = E_OUTOFMEMORY;
}
return hr;
}
STDMETHODIMP
CComponentData::CreatePropertyPages(
LPPROPERTYSHEETCALLBACK lpProvider,
LONG_PTR handle,
LPDATAOBJECT lpDataObject
)
{
if (!lpProvider || !lpDataObject)
{
return E_INVALIDARG;
}
HRESULT hr;
try
{
INTERNAL_DATA tID;
hr = ExtractData(lpDataObject, CDataObject::m_cfSnapinInternal,
reinterpret_cast<BYTE*>(&tID), sizeof(tID)
);
if (SUCCEEDED(hr))
{
CScopeItem* pScopeItem = FindScopeItem(tID.cookie);
if (CCT_SNAPIN_MANAGER == tID.dot && COOKIE_TYPE_SCOPEITEM_DEVMGR == tID.ct)
{
hr = DoStartupProperties(lpProvider, handle, lpDataObject);
}
else if (pScopeItem)
{
hr = pScopeItem->CreatePropertyPages(lpProvider, handle);
}
else
{
hr = S_OK;
}
}
}
catch(CMemoryException* e)
{
e->Delete();
MsgBoxParam(m_hwndMain, 0, 0, 0);
hr = E_OUTOFMEMORY;
}
return hr;
}
////////////////////////////////////////////////////////////
//// IExtendContextMenu implemantation
////
STDMETHODIMP
CComponentData::AddMenuItems(
LPDATAOBJECT lpDataObject,
LPCONTEXTMENUCALLBACK pCallbackUnknown,
long *pInsertionAllowed
)
{
if (!lpDataObject || !pCallbackUnknown || !pInsertionAllowed)
{
return E_INVALIDARG;
}
return S_OK;
}
STDMETHODIMP
CComponentData::Command(
long nCommandID,
LPDATAOBJECT lpDataObject
)
{
if (!lpDataObject)
{
return E_INVALIDARG;
}
return S_OK;
}
HRESULT
CComponentData::CreateCookieSubtree(
CScopeItem* pScopeItem,
CCookie* pCookieParent
)
{
ASSERT(pScopeItem);
CScopeItem* pChild;
CCookie* pCookieSibling;
pCookieSibling = NULL;
int Index = 0;
while (pScopeItem->EnumerateChildren(Index, &pChild))
{
CCookie* pCookie;
pCookie = new CCookie(pChild->GetType());
if (pCookie) {
pCookie->SetScopeItem(pChild);
if (!pCookieSibling)
{
pCookieParent->SetChild(pCookie);
}
else
{
pCookieSibling->SetSibling(pCookie);
}
pCookie->SetParent(pCookieParent);
if (pChild->GetChildCount())
{
CreateCookieSubtree(pChild, pCookie);
}
pCookieSibling = pCookie;
}
Index++;
}
return S_OK;
}
////////////////////////////////////////////////////////////
/// IPersistStream implementation
///
STDMETHODIMP
CComponentData::GetClassID(
CLSID* pClassID
)
{
if(!pClassID)
{
return E_INVALIDARG;
}
*pClassID = GetCoClassID();
return S_OK;
}
STDMETHODIMP
CComponentData::IsDirty()
{
return m_IsDirty ? S_OK : S_FALSE;
}
STDMETHODIMP
CComponentData::Load(
IStream* pStm
)
{
HRESULT hr;
SafeInterfacePtr<IStream> StmPtr(pStm);
//
// Fix up the MachineName that we got from the command line if there was one.
// We need to prepend "\\" to the MachineName if it does not start with two
// backslashes, and then we will verify the machine name by calling CM_Connect_Machine
// to verify that this user has access to that machine. If they do not then we
// will set the MachineName to NULL.
//
if (!g_strStartupMachineName.IsEmpty())
{
if (_T('\\') != g_strStartupMachineName[0])
{
g_strStartupMachineName = TEXT("\\\\") + g_strStartupMachineName;
}
if (!VerifyMachineName(g_strStartupMachineName))
{
g_strStartupMachineName.Empty();
}
}
COMPDATA_PERSISTINFO Info;
ULONG BytesRead;
ASSERT(pStm);
//
// Read the persist data and verify that we have the right data
//
hr = pStm->Read(&Info, sizeof(Info), &BytesRead);
if (SUCCEEDED(hr) &&
(BytesRead >= sizeof(Info)) &&
(Info.Size >= sizeof(Info)) &&
(!wcscmp(Info.Signature, DM_COMPDATA_SIGNATURE)))
{
try
{
m_ctRoot = Info.RootCookie;
m_strMachineName.Empty();
if (UNICODE_NULL != Info.ComputerFullName[0])
{
#ifdef UNICODE
m_strMachineName = Info.ComputerFullName;
#else
CHAR ComputerNameA[MAX_PATH + 3];
WideCharToMultiByte(CP_ACP, 0, Info.ComputerFullName, -1,
ComputerNameA, sizeof(ComputerNameA) / sizeof(CHAR), NULL, ULL);
m_strMachineName = ComputerNameA;
#endif
}
if (COOKIE_TYPE_SCOPEITEM_DEVMGR == m_ctRoot)
{
//
// Parameters from command line has the priority
//
if (!g_strStartupMachineName.IsEmpty())
{
m_strMachineName = g_strStartupMachineName;
}
m_strStartupDeviceId = g_strStartupDeviceId;
m_strStartupCommand = g_strStartupCommand;
}
hr = CreateScopeItems();
if (SUCCEEDED(hr))
{
if (!m_pMachine)
{
if (!g_MachineList.CreateMachine(m_hwndMain, m_strMachineName, &m_pMachine))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
}
}
catch(CMemoryException* e)
{
e->Delete();
MsgBoxParam(m_hwndMain, 0, 0, 0);
hr = E_OUTOFMEMORY;
}
}
m_IsDirty = FALSE;
return hr;
}
STDMETHODIMP
CComponentData::Save(
IStream* pStm,
BOOL fClearDirty
)
{
SafeInterfacePtr<IStream> StmPtr(pStm);
HRESULT hr;
try
{
COMPDATA_PERSISTINFO Info;
Info.Size = sizeof(Info);
Info.RootCookie = m_ctRoot;
wcscpy(Info.Signature, DM_COMPDATA_SIGNATURE);
//
// Assuming it is on local machine. The machine name is saved
// in UNICODE
//
Info.ComputerFullName[0] = UNICODE_NULL;
if (m_strMachineName.GetLength())
#ifdef UNICODE
wcscpy(Info.ComputerFullName, m_strMachineName);
#else
MultiByteToWideChar((CP_ACP, 0, chBuffer, -1, Info.ComputerFullName,
sizeof(Info.ComputerFullName) / sizeof(WCHAR));
#endif
hr = pStm->Write(&Info, sizeof(Info), NULL);
}
catch (CMemoryException* e)
{
e->Delete();
MsgBoxParam(m_hwndMain, 0, 0, 0);
hr = E_OUTOFMEMORY;
}
if (fClearDirty)
{
m_IsDirty = FALSE;
}
return hr;
}
STDMETHODIMP
CComponentData::GetSizeMax(
ULARGE_INTEGER* pcbSize
)
{
if (!pcbSize)
{
return E_INVALIDARG;
}
int len;
len = sizeof(m_ctRoot) + sizeof(len) + (m_strMachineName.GetLength() + 1) * sizeof(TCHAR);
ULISet32(*pcbSize, len);
return S_OK;
}
//
// Method to support html help.
//
//
STDMETHODIMP
CComponentData::GetHelpTopic(
LPOLESTR* lpCompileHelpFile
)
{
if (!lpCompileHelpFile)
{
return E_INVALIDARG;
}
*lpCompileHelpFile = NULL;
UINT Size;
TCHAR HelpFile[MAX_PATH];
Size = GetSystemWindowsDirectory(HelpFile, ARRAYLEN(HelpFile));
if (Size && Size < ARRAYLEN(HelpFile))
{
StrCatN(HelpFile, DEVMGR_HTML_HELP_FILE_NAME, ARRAYLEN(HelpFile));
*lpCompileHelpFile = AllocOleTaskString(HelpFile);
}
return S_OK;
}
CScopeItem*
CComponentData::FindScopeItem(
MMC_COOKIE cookie
)
{
CCookie* pCookie = GetActiveCookie(cookie);
if (pCookie)
return pCookie->GetScopeItem();
return NULL;
}
//
// This function loads icons for the scope items
//
HRESULT
CComponentData::LoadScopeIconsForScopePane()
{
ASSERT(m_pScope);
ASSERT(m_pConsole);
LPIMAGELIST lpScopeImage;
HRESULT hr;
hr = m_pConsole->QueryScopeImageList(&lpScopeImage);
if (SUCCEEDED(hr))
{
HICON hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DEVMGR));
if (hIcon)
{
hr = lpScopeImage->ImageListSetIcon((PLONG_PTR)hIcon, IMAGE_INDEX_DEVMGR);
DestroyIcon(hIcon);
}
hr = lpScopeImage->Release();
}
return hr;
}
//
// This function create the startup wizard property sheet
//
// INPUT:
// lpProvider -- Interface for us to add pages
// handle -- notify console handle
// lpDataObject -- the data object
//
// OUTPUT:
// standard OLE HRESULT
HRESULT
CComponentData::DoStartupProperties(
LPPROPERTYSHEETCALLBACK lpProvider,
LONG_PTR handle,
LPDATAOBJECT lpDataObject
)
{
CGeneralPage* pGenPage;
HPROPSHEETPAGE hPage;
pGenPage = new CGeneralPage();
if (pGenPage)
{
hPage = pGenPage->Create(handle);
if (hPage)
{
lpProvider->AddPage(hPage);
//
// If no console handle is provided, we have to use
// our call back function
//
if(!handle)
{
pGenPage->SetOutputBuffer(&m_strMachineName, &m_ctRoot);
}
return S_OK;
}
else
{
throw &g_MemoryException;
}
}
else
{
throw &g_MemoryException;
}
return E_OUTOFMEMORY;
}
//
// This function creates all the necessary classes represent
// our scope items
//
HRESULT
CComponentData::CreateScopeItems()
{
//
// All classes are linked by cookie with m_pCookieRoot
// points to the "root" scope item
//
if (!m_pScopeItemRoot)
{
switch (m_ctRoot)
{
case COOKIE_TYPE_SCOPEITEM_DEVMGR:
m_pScopeItemRoot = new CScopeItem(COOKIE_TYPE_SCOPEITEM_DEVMGR,
IMAGE_INDEX_DEVMGR,
OPEN_IMAGE_INDEX_DEVMGR,
IDS_NAME_DEVMGR,
IDS_DESC_DEVMGR,
IDS_DISPLAYNAME_SCOPE_DEVMGR);
break;
default:
ASSERT(FALSE);
break;
}
if (m_pScopeItemRoot->Create())
{
//
// Bind scope items and cookies together.
// Cookies know its scopeitem.
// Scopeitems do not know cookies.
//
m_pCookieRoot = new CCookie(m_ctRoot);
if (m_pCookieRoot)
{
ASSERT(m_pScopeItemRoot->GetType() == m_ctRoot);
m_pCookieRoot->SetScopeItem(m_pScopeItemRoot);
CreateCookieSubtree(m_pScopeItemRoot, m_pCookieRoot);
}
}
}
return S_OK;
}
//
// This function resets the given scopeitem.
//
HRESULT
CComponentData::ResetScopeItem(
CScopeItem* pScopeItem
)
{
HRESULT hr = S_OK;
if (pScopeItem)
{
CScopeItem* pChild;
int Index;
Index = 0;
while (SUCCEEDED(hr) && pScopeItem->EnumerateChildren(Index, &pChild))
{
hr = ResetScopeItem(pChild);
Index++;
}
if (SUCCEEDED(hr))
{
return pScopeItem->Reset();
}
}
return hr;
}