|
|
/*++
Copyright (C) 1997-1999 Microsoft Corporation
Module Name:
machine.cpp
Abstract:
This module implements CDevInfoList, CMachine and CMachineList
Author:
William Hsieh (williamh) created
Revision History:
--*/
#include "devmgr.h"
extern "C" { #include <initguid.h>
#include <dbt.h>
#include <devguid.h>
#include <wdmguid.h>
}
//
//private setupapi export
//
DWORD pSetupGuidFromString( PWCHAR GuidString, LPGUID Guid );
CONST TCHAR* DEVMGR_NOTIFY_CLASS_NAME = TEXT("DevMgrNotifyClass");
CONST TCHAR* DEVMGR_REFRESH_MSG = TEXT("DevMgrRefreshOn");
//
// The constant is the size we use to allocate GUID list from within
// stack when we have to build a GUID list. The aim of this is
// that buiding a guid list take time and in many case, a minimum
// buffer should retrive all of them. We do not want to get
// the size first, allocate buffer and get it again.
// 64 looks to be fair enough value because there are not
// many classes out there today (and maybe, in the future).
//
const int GUID_LIST_INIT_SIZE = 64;
//
// CDevInfoList implementation
//
BOOL CDevInfoList::DiGetExtensionPropSheetPage( PSP_DEVINFO_DATA DevData, LPFNADDPROPSHEETPAGE pfnAddPropSheetPage, DWORD PageType, LPARAM lParam ) { SP_PROPSHEETPAGE_REQUEST PropPageRequest; LPFNADDPROPSHEETPAGES AddPropPages;
PropPageRequest.cbSize = sizeof(PropPageRequest); PropPageRequest.PageRequested = PageType; PropPageRequest.DeviceInfoSet = m_hDevInfo; PropPageRequest.DeviceInfoData = DevData;
if (SPPSR_SELECT_DEVICE_RESOURCES == PageType) { HINSTANCE hModule = ::GetModuleHandle(TEXT("setupapi.dll"));
if (hModule) { AddPropPages = (LPFNADDPROPSHEETPAGES)GetProcAddress(hModule, "ExtensionPropSheetPageProc");
if (AddPropPages) { if (AddPropPages(&PropPageRequest, pfnAddPropSheetPage, lParam)) { return TRUE; } } } }
return FALSE; }
BOOL CDevInfoList::InstallDevInst( HWND hwndParent, LPCTSTR DeviceId, BOOL UpdateDriver, DWORD* pReboot ) { BOOL Result = FALSE; HINSTANCE hLib = LoadLibrary(TEXT("newdev.dll")); LPFNINSTALLDEVINST InstallDevInst; DWORD Status = ERROR_SUCCESS;
if (hLib) { InstallDevInst = (LPFNINSTALLDEVINST)GetProcAddress(hLib, "InstallDevInst");
if (InstallDevInst) { Result = (*InstallDevInst)(hwndParent, DeviceId, UpdateDriver, pReboot);
Status = GetLastError(); } }
if (hLib) { FreeLibrary(hLib); }
//
// We need to put back the error code that was set by newdev.dll's InstallDevInst
// API. This last error gets overwritten by FreeLibrary which we don't care about.
//
SetLastError(Status);
return Result; }
BOOL CDevInfoList::RollbackDriver( HWND hwndParent, LPCTSTR RegistryKeyName, DWORD Flags, DWORD* pReboot ) { BOOL Result = FALSE; HINSTANCE hLib = LoadLibrary(TEXT("newdev.dll")); LPFNROLLBACKDRIVER RollbackDriver;
if (hLib) { RollbackDriver = (LPFNROLLBACKDRIVER)GetProcAddress(hLib, "RollbackDriver");
if (RollbackDriver) { Result = (*RollbackDriver)(hwndParent, RegistryKeyName, Flags, pReboot); } }
if (hLib) { FreeLibrary(hLib); }
return Result; }
DWORD CDevInfoList::DiGetFlags( PSP_DEVINFO_DATA DevData ) { SP_DEVINSTALL_PARAMS dip; dip.cbSize = sizeof(dip);
if (DiGetDeviceInstallParams(DevData, &dip)) { return dip.Flags; }
return 0; }
DWORD CDevInfoList::DiGetExFlags( PSP_DEVINFO_DATA DevData ) { SP_DEVINSTALL_PARAMS dip; dip.cbSize = sizeof(dip);
if (DiGetDeviceInstallParams(DevData, &dip)) { return dip.FlagsEx; }
return 0; }
BOOL CDevInfoList::DiTurnOnDiFlags( PSP_DEVINFO_DATA DevData, DWORD FlagsMask ) { SP_DEVINSTALL_PARAMS dip; dip.cbSize = sizeof(dip);
if (DiGetDeviceInstallParams(DevData, &dip)) { dip.Flags |= FlagsMask; return DiSetDeviceInstallParams(DevData, &dip); }
return FALSE; }
BOOL CDevInfoList::DiTurnOffDiFlags( PSP_DEVINFO_DATA DevData, DWORD FlagsMask ) { SP_DEVINSTALL_PARAMS dip; dip.cbSize = sizeof(dip);
if (DiGetDeviceInstallParams(DevData, &dip)) { dip.Flags &= ~FlagsMask; return DiSetDeviceInstallParams(DevData, &dip); }
return FALSE; }
BOOL CDevInfoList::DiTurnOnDiExFlags( PSP_DEVINFO_DATA DevData, DWORD FlagsMask ) { SP_DEVINSTALL_PARAMS dip; dip.cbSize = sizeof(dip);
if (DiGetDeviceInstallParams(DevData, &dip)) { dip.FlagsEx |= FlagsMask; return DiSetDeviceInstallParams(DevData, &dip); }
return FALSE; }
BOOL CDevInfoList::DiTurnOffDiExFlags( PSP_DEVINFO_DATA DevData, DWORD FlagsMask ) { SP_DEVINSTALL_PARAMS dip; dip.cbSize = sizeof(dip);
if (DiGetDeviceInstallParams(DevData, &dip)) { dip.FlagsEx &= ~FlagsMask; return DiSetDeviceInstallParams(DevData, &dip); }
return FALSE; }
void CDevInfoList::DiDestroyDeviceInfoList() { if (INVALID_HANDLE_VALUE != m_hDevInfo) { SetupDiDestroyDeviceInfoList(m_hDevInfo); m_hDevInfo = INVALID_HANDLE_VALUE; } }
BOOL CDevInfoList::DiGetDeviceMFGString( PSP_DEVINFO_DATA DevData, TCHAR* pBuffer, DWORD Size, DWORD* pRequiredSize ) { if (Size && !pBuffer) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
DWORD ActualSize = 0; BOOL Result; Result = DiGetDeviceRegistryProperty(DevData, SPDRP_MFG, NULL, (PBYTE)pBuffer, Size * sizeof(TCHAR), &ActualSize);
if (pRequiredSize) { *pRequiredSize = ActualSize / sizeof(TCHAR); }
return Result; }
BOOL CDevInfoList::DiGetDeviceMFGString( PSP_DEVINFO_DATA DevData, String& str ) { DWORD RequiredSize = 0; TCHAR MFG[LINE_LEN];
if (DiGetDeviceMFGString(DevData, MFG, ARRAYLEN(MFG), &RequiredSize)) { str = MFG; return TRUE; }
return FALSE; }
BOOL CDevInfoList::DiGetDeviceIDString( PSP_DEVINFO_DATA DevData, TCHAR* pBuffer, DWORD Size, DWORD* pRequiredSize ) { if (Size && !pBuffer) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
DWORD ActualSize = 0; BOOL Result; Result = DiGetDeviceRegistryProperty(DevData, SPDRP_HARDWAREID, NULL, (PBYTE) pBuffer, Size * sizeof(TCHAR), &ActualSize);
if (pRequiredSize) { *pRequiredSize = ActualSize / sizeof(TCHAR); }
return Result; }
BOOL CDevInfoList::DiGetDeviceIDString( PSP_DEVINFO_DATA DevData, String& str ) { BOOL Result; DWORD RequiredSize = 0; TCHAR DeviceId[MAX_DEVICE_ID_LEN];
if (DiGetDeviceIDString(DevData, DeviceId, ARRAYLEN(DeviceId), &RequiredSize)) { str = DeviceId; return TRUE; }
return FALSE; }
/////////////////////////////////////////////////////////////////////
//// CMachine implementation
////
//
// For every single instance of DevMgr.dll, we maintain a CMachine list
// from which different instances of IComponentData(and IComponent) will
// attach to. The objects created(CDevice, Class, HDEVINFO and etc) are
// shared by all the attached IComponentData and IComponent(the implementation
// use CFolder as the controlling identify).
// Everything changed to the CMachine or one of its object will inform
// all the attached CFolders which would pass the information down to their
// sub-objects(CResultView).
// Imaging that you have two Device Manager window in the same console
// and you do a refresh on one the window. The other window must also
// do a refresh after the first one is done. Since both windows shares
// the same machine(and will get the same notification when machine states
// changed), we can keep the two windows in sync.
CMachine::CMachine( LPCTSTR pMachineName ) { InitializeCriticalSection(&m_CriticalSection); InitializeCriticalSection(&m_PropertySheetCriticalSection); InitializeCriticalSection(&m_ChildMachineCriticalSection);
//
// Get various privilege levels, like if the user has the SE_LOAD_DRIVER_NAME
// privileg or if the user is a Guest.
//
g_HasLoadDriverNamePrivilege = pSetupDoesUserHavePrivilege((PCTSTR)SE_LOAD_DRIVER_NAME); m_UserIsAGuest = SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_GUESTS);
m_RefreshDisableCounter = 0; m_RefreshPending = FALSE; m_pComputer = NULL; m_hMachine = NULL; m_ParentMachine = NULL; m_Initialized = FALSE; TCHAR LocalName[MAX_PATH + 1]; DWORD dwSize = sizeof(LocalName) / sizeof(TCHAR);
if (!GetComputerName(LocalName, &dwSize)) { LocalName[0] = _T('\0'); }
m_strMachineFullName.Empty(); m_strMachineDisplayName.Empty();
//
// Skip over any leading '\' chars
//
if (pMachineName && _T('\0') != *pMachineName) { int len = lstrlen(pMachineName); ASSERT(len >= 3 && _T('\\') == pMachineName[0] && _T('\\') == pMachineName[1]); m_strMachineDisplayName = &pMachineName[2]; m_strMachineFullName = pMachineName; m_IsLocal = (0 == m_strMachineDisplayName.CompareNoCase(LocalName)); }
else { //
// Local machine
//
m_strMachineDisplayName = LocalName; m_strMachineFullName = TEXT("\\\\") + m_strMachineDisplayName; m_IsLocal = TRUE; }
m_hwndNotify = NULL; m_msgRefresh = 0; m_ShowNonPresentDevices = FALSE; m_PropertySheetShoudDestroy = FALSE;
TCHAR Buffer[MAX_PATH]; DWORD BufferLen;
//
// If the environment variable DEVMGR_SHOW_NONPRESENT_DEVICES does exist and it
// is not 0 then we will show Phantom devices.
//
if (((BufferLen = ::GetEnvironmentVariable(TEXT("DEVMGR_SHOW_NONPRESENT_DEVICES"), Buffer, sizeof(Buffer)/sizeof(TCHAR))) != 0) && ((BufferLen > 1) || (lstrcmp(Buffer, TEXT("0"))))) {
m_ShowNonPresentDevices = TRUE; } }
BOOL CMachine::Initialize( IN HWND hwndParent, IN LPCTSTR DeviceId, OPTIONAL IN LPGUID ClassGuid OPTIONAL ) { BOOL Result = TRUE; m_hwndParent = hwndParent;
if (m_Initialized) { return TRUE; }
if (DeviceId && _T('\0') == *DeviceId) { DeviceId = NULL; }
HCURSOR hCursorOld; hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
if (DeviceId || ClassGuid) {
//
// We are ready for device change notification, create the notify window
//
//Result = CreateNotifyWindow();
if (CreateClassesAndDevices(DeviceId, ClassGuid)) {
m_Initialized = TRUE; }
} else {
//
// We are ready for device change notification, create the notify window
//
Result = CreateNotifyWindow();
m_Initialized = TRUE;
ScheduleRefresh(); }
if (hCursorOld) { SetCursor(hCursorOld); }
return Result; }
BOOL CMachine::ScheduleRefresh() { Lock();
//
// Only queue the the request if there is no requests outstanding
// and we have a valid window handle/message to the notify window.
//
if (!m_RefreshPending && m_hwndNotify && m_msgRefresh) { //
// Broadcast the message so that every instance runs on
// the computer get the notification
//
::PostMessage(HWND_BROADCAST, m_msgRefresh, 0, 0); }
Unlock(); return TRUE;
}
//
// This function creates a data window to receive WM_DEVICECHANGE notification
// so that we can refresh the device tree. It also registers a private
// message so that anybody can post a refresh request.
//
BOOL CMachine::CreateNotifyWindow() { WNDCLASS wndClass;
//
// Lets see if the class has been registered.
//
if (!GetClassInfo(g_hInstance, DEVMGR_NOTIFY_CLASS_NAME, &wndClass)) { //
// Register the class
//
memset(&wndClass, 0, sizeof(wndClass)); wndClass.lpfnWndProc = dmNotifyWndProc; wndClass.hInstance = g_hInstance; wndClass.lpszClassName = DEVMGR_NOTIFY_CLASS_NAME;
if (!RegisterClass(&wndClass)) { return FALSE; } }
//
// Register a private message for refresh. The name must contain
// the target machine name so that every machine has its own message.
//
String strMsg = DEVMGR_REFRESH_MSG; strMsg += m_strMachineDisplayName; m_msgRefresh = RegisterWindowMessage(strMsg);
if (m_msgRefresh) { //
// Create a data window.
//
m_hwndNotify = CreateWindowEx(WS_EX_TOOLWINDOW, DEVMGR_NOTIFY_CLASS_NAME, TEXT(""), WS_DLGFRAME|WS_BORDER|WS_DISABLED, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, g_hInstance, (void*)this); return(NULL != m_hwndNotify); }
return FALSE; }
//
// This is the WM_DEVICECHANGE window procedure running in the main thread
// context. It listens to two messages:
// (1). WM_DEVICECHANGE broadcasted by Configuration Manager on device
// addition/removing.
// (2). Private refresh message broadcasted by different instance
// of Device Manager targeting on the same machine.
// On WM_CREATE, we participate the WM_DEVICECHANGE notification chain
// while on WM_DESTROY, we detach oursleves from the chain.
// There are occasions that we have to detach and re-attach to the
// chain duing the window life time, for example, during device uninstallation
// or during re-enumeration. The EnableFresh function is the place
// that does the attach/detach.
//
//
LRESULT dmNotifyWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { CMachine* pThis; pThis = (CMachine*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
//
// Special case for private refresh message
//
if (pThis && uMsg == pThis->m_msgRefresh) { pThis->Refresh(); return FALSE; }
switch (uMsg) { case WM_CREATE: { pThis = (CMachine*)((CREATESTRUCT*)lParam)->lpCreateParams; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis); break; }
case WM_DEVICECHANGE: { if (DBT_DEVNODES_CHANGED == wParam) {
//
// While we are in WM_DEVICECHANGE context,
// no CM apis can be called because it would
// deadlock. Here, we schedule a timer so that
// we can handle the message later on.
//
SetTimer(hWnd, DM_NOTIFY_TIMERID, 1000, NULL); } break; }
case WM_TIMER: { if (DM_NOTIFY_TIMERID == wParam) { KillTimer(hWnd, DM_NOTIFY_TIMERID); ASSERT(pThis); pThis->ScheduleRefresh(); } break; }
default: break; }
return DefWindowProc(hWnd, uMsg, wParam, lParam); }
//
// This function attaches the given CFolder to the class.
// An attached CFolder will get notified when there are state
// changes in the class(Refresh, property changes, for example).
//
BOOL CMachine::AttachFolder( CFolder* pFolder ) { ASSERT(pFolder);
if (!IsFolderAttached(pFolder)) { pFolder->MachinePropertyChanged(this); m_listFolders.AddTail(pFolder); }
return TRUE; }
BOOL CMachine::IsFolderAttached( CFolder* pFolder ) { if (!m_listFolders.IsEmpty()) { POSITION pos = m_listFolders.GetHeadPosition();
while (NULL != pos) { if (pFolder == m_listFolders.GetNext(pos)) { return TRUE; } } }
return FALSE; }
void CMachine::DetachFolder( CFolder* pFolder ) { POSITION nextpos = m_listFolders.GetHeadPosition();
while (nextpos) { POSITION pos = nextpos;
CFolder* pFolderToTest = m_listFolders.GetNext(nextpos);
if (pFolderToTest == pFolder) { m_listFolders.RemoveAt(pos); break; } } }
BOOL CMachine::AttachPropertySheet( HWND hwndPropertySheet ) { ASSERT(hwndPropertySheet);
EnterCriticalSection(&m_PropertySheetCriticalSection);
m_listPropertySheets.AddTail(hwndPropertySheet);
LeaveCriticalSection(&m_PropertySheetCriticalSection);
return TRUE; }
void CMachine::DetachPropertySheet( HWND hwndPropertySheet ) { EnterCriticalSection(&m_PropertySheetCriticalSection);
POSITION nextpos = m_listPropertySheets.GetHeadPosition();
while (nextpos) { POSITION pos = nextpos;
HWND hwndPropertySheetToTest = m_listPropertySheets.GetNext(nextpos);
if (hwndPropertySheetToTest == hwndPropertySheet) { m_listPropertySheets.RemoveAt(pos); break; } }
LeaveCriticalSection(&m_PropertySheetCriticalSection); }
HWND CMachine::GetDeviceWindowHandle( LPCTSTR DeviceId ) { HWND hwnd = NULL;
EnterCriticalSection(&m_ChildMachineCriticalSection);
//
// Enumerate the list of Child CMachines
//
if (!m_listChildMachines.IsEmpty()) {
PVOID DeviceContext; CDevice* pDevice;
POSITION nextpos = m_listChildMachines.GetHeadPosition();
while (nextpos) {
CMachine* pChildMachine = m_listChildMachines.GetNext(nextpos);
//
// Child machines will only have one device (if any at all)
//
if (pChildMachine->GetFirstDevice(&pDevice, DeviceContext) && pDevice) {
//
// If the device Ids match then get the window handle
//
if (lstrcmpi(pDevice->GetDeviceID(), DeviceId) == 0) {
hwnd = pDevice->m_psd.GetWindowHandle(); break; } } } }
LeaveCriticalSection(&m_ChildMachineCriticalSection);
return hwnd; }
HWND CMachine::GetClassWindowHandle( LPGUID ClassGuid ) { HWND hwnd = NULL;
EnterCriticalSection(&m_ChildMachineCriticalSection);
//
// Enumerate the list of Child CMachines
//
if (!m_listChildMachines.IsEmpty()) {
PVOID ClassContext; CClass* pClass;
POSITION nextpos = m_listChildMachines.GetHeadPosition();
while (nextpos) {
CMachine* pChildMachine = m_listChildMachines.GetNext(nextpos);
//
// Any child CMachine that has a device is a device property sheet.
// We only want to look at the ones that have 0 devices since those
// will be class property sheets.
//
if (pChildMachine->GetNumberOfDevices() == 0) {
if (pChildMachine->GetFirstClass(&pClass, ClassContext) && pClass) {
//
// If the ClassGuids match then get the window handle
//
if (IsEqualGUID(*ClassGuid, *pClass)) {
hwnd = pClass->m_psd.GetWindowHandle(); break; } } } } }
LeaveCriticalSection(&m_ChildMachineCriticalSection);
return hwnd; }
BOOL CMachine::AttachChildMachine( CMachine* ChildMachine ) { ASSERT(ChildMachine);
EnterCriticalSection(&m_ChildMachineCriticalSection);
m_listChildMachines.AddTail(ChildMachine);
LeaveCriticalSection(&m_ChildMachineCriticalSection);
return TRUE; }
void CMachine::DetachChildMachine( CMachine* ChildMachine ) { EnterCriticalSection(&m_ChildMachineCriticalSection);
POSITION nextpos = m_listChildMachines.GetHeadPosition();
while (nextpos) { POSITION pos = nextpos;
CMachine* CMachineToTest = m_listChildMachines.GetNext(nextpos);
if (CMachineToTest == ChildMachine) { m_listChildMachines.RemoveAt(pos); break; } }
LeaveCriticalSection(&m_ChildMachineCriticalSection); }
CMachine::~CMachine() { //
// Turn off refresh. We need to do this in case there are any property
// sheets that are still active.
//
EnableRefresh(FALSE);
//
// We first need to destroy all child CMachines
//
while (!m_listChildMachines.IsEmpty()) {
//
// Remove the first child machine from the list. We need to
// do this in the critical section.
//
EnterCriticalSection(&m_ChildMachineCriticalSection);
CMachine* ChildMachine = m_listChildMachines.RemoveHead();
//
// Set the m_ParentMachine to NULL so we won't try to remove it from
// the list again.
//
ChildMachine->m_ParentMachine = NULL;
LeaveCriticalSection(&m_ChildMachineCriticalSection);
delete ChildMachine; }
//
// We need to wait for all of the property sheets to be destroyed.
//
// We will check to see if there are any property pages still around, and
// if there is we will wait for 1 second and then check again. After 5
// seconds we will give up and just destroy the CMachine anyway.
//
int iSecondsCount = 0;
while (!m_listPropertySheets.IsEmpty() && (iSecondsCount++ < 10)) {
//
// Enumerate through all of the property sheets left and if IsWindow fails
// then pull them from the list, otherwise call DestroyWindow on them.
//
// Since property sheets each run in their own thread we need to do this
// in a critical section.
//
EnterCriticalSection(&m_PropertySheetCriticalSection);
POSITION nextpos = m_listPropertySheets.GetHeadPosition();
while (nextpos) { POSITION pos = nextpos;
HWND hwndPropertySheetToTest = m_listPropertySheets.GetNext(nextpos);
if (IsWindow(hwndPropertySheetToTest)) { //
// There is still a valid window for this property sheet so
// call DestroyWindow on it.
//
::DestroyWindow(hwndPropertySheetToTest); } else { //
// There is no window for this property sheet so just remove
// it from the list
//
m_listPropertySheets.RemoveAt(pos); } }
LeaveCriticalSection(&m_PropertySheetCriticalSection);
//
// Sleep for .5 seconds and then try again. This will give the property pages time to
// finish up their work.
//
Sleep(500); }
// if we have created a device change data window for this machine,
// destroy it.
if (m_hwndNotify && IsWindow(m_hwndNotify)) { ::DestroyWindow(m_hwndNotify); m_hwndNotify = NULL; }
DestroyClassesAndDevices();
if (!m_listFolders.IsEmpty()) { m_listFolders.RemoveAll(); }
//
// If we have a parent CMachine then we need to remove oursleves from
// his list of Child CMachines.
//
if (m_ParentMachine) {
m_ParentMachine->DetachChildMachine(this); }
DeleteCriticalSection(&m_CriticalSection); DeleteCriticalSection(&m_PropertySheetCriticalSection); DeleteCriticalSection(&m_ChildMachineCriticalSection); }
//
// This function destroys all the CClass and CDevice we ever created.
// No notification is sent for the attached folder
//
//
void CMachine::DestroyClassesAndDevices() { if (m_pComputer) { delete m_pComputer; m_pComputer = NULL; }
if (!m_listDevice.IsEmpty()) { POSITION pos = m_listDevice.GetHeadPosition();
while (NULL != pos) { CDevice* pDevice = m_listDevice.GetNext(pos); delete pDevice; }
m_listDevice.RemoveAll(); }
if (!m_listClass.IsEmpty()) { POSITION pos = m_listClass.GetHeadPosition();
while (NULL != pos) { CClass* pClass = m_listClass.GetNext(pos); delete pClass; }
m_listClass.RemoveAll(); }
if (m_ImageListData.cbSize) { DiDestroyClassImageList(&m_ImageListData); }
CDevInfoList::DiDestroyDeviceInfoList();
m_hMachine = NULL; }
BOOL CMachine::BuildClassesFromGuidList( LPGUID GuidList, DWORD Guids ) { DWORD Index; CClass* pClass;
//
// Build a list of CClass for each GUID.
//
for (Index = 0; Index < Guids; Index++) { SafePtr<CClass> ClassPtr;
pClass = new CClass(this, &GuidList[Index]); ClassPtr.Attach(pClass); m_listClass.AddTail(ClassPtr); ClassPtr.Detach(); }
return TRUE; }
//
// Create CClass and CDevice for this machine.
// If DeviceId is valid, this function will create the machine
// with ONLY ONE device(and its CClass)
//
// PERFBUG Optimize this function!!!!!!!
// This function is slow because SetupDiGetClassDevs can take a long
// time (over 1 sec of a 300Mhz machine).
// The other slow part is the call to DoNotCreateDevice which needs to
// go through the service manager for all legacy devnodes to see
// if they are Win32 services (which we don't display). This takes
// around 10ms to get this information from the service manager on
// a 300Mhz machine and their are almost 100 of these legacy devices.
// This means another second of time.
//
//
BOOL CMachine::CreateClassesAndDevices( IN LPCTSTR DeviceId, OPTIONAL IN LPGUID ClassGuid OPTIONAL ) { SC_HANDLE SCMHandle = NULL;
//
// Preventing memory leak
//
ASSERT(NULL == m_pComputer); ASSERT(INVALID_HANDLE_VALUE == m_hDevInfo); ASSERT(NULL == m_hMachine);
//
// If the object is being created for a single device,
// create a empty device info list. We will add the
// device to the info list later.
//
if (DeviceId || ClassGuid) {
m_hDevInfo = DiCreateDeviceInfoList(ClassGuid, m_hwndParent); }
else {
//
// We have to pull out the entire devices/classes set
// so create a device info list that contains all of them.
//
m_hDevInfo = DiGetClassDevs(NULL, NULL, m_hwndParent, DIGCF_ALLCLASSES | DIGCF_PROFILE); }
//
// NULL != INVALID_HANDLE_VALUE. We checked both just be safe.
//
if (INVALID_HANDLE_VALUE == m_hDevInfo || NULL == m_hDevInfo) {
return FALSE; }
SP_DEVINFO_LIST_DETAIL_DATA DevInfoDetailData; DevInfoDetailData.cbSize = sizeof(DevInfoDetailData);
//
// Use the HMACHINE returned from Setupapi so that
// every call we make to Cfgmgr32.dll will use the
// same HMACHINE. Two call of CM_Connect_Machine will
// return different hMachines even though they refer to
// the same machine name(and thus, different set of DEVNODE!).
// The catch is that we will be able to call Setuapi and cfgmgr32
// API without worrying about which hMachine to use.
//
if (DiGetDeviceInfoListDetail(&DevInfoDetailData)) { m_hMachine = DevInfoDetailData.RemoteMachineHandle; } else { //
// Unable to get the devinfo detail information.
// In this case we will just default to the local machine.
//
m_hMachine = NULL; }
//
// Get class image list data;
//
m_ImageListData.cbSize = sizeof(m_ImageListData); if (DiGetClassImageList(&m_ImageListData)) { //
// Add extra icons
//
HICON hIcon;
if ((hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DEVMGR))) != NULL) { m_ComputerIndex = ImageList_AddIcon(m_ImageListData.ImageList, hIcon); DestroyIcon(hIcon); }
if ((hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_RESOURCES))) != NULL) { m_ResourceIndex = ImageList_AddIcon(m_ImageListData.ImageList, hIcon); DestroyIcon(hIcon); } }
//
// If the object is created for a particular device,
// do not create the entire device list because it is
// a waste of time.
//
if (DeviceId) { SP_DEVINFO_DATA DevData; GUID DeviceClassGuid; DevData.cbSize = sizeof(DevData); if (DiOpenDeviceInfo(DeviceId, m_hwndParent, 0, &DevData) && CmGetClassGuid(DevData.DevInst, DeviceClassGuid)) { //
// Create a CClass for the device(without CClass, no
// device can not be created).
//
CClass* pClass; SafePtr<CClass> ClassPtr; pClass = new CClass(this, &DeviceClassGuid);
if (pClass) { ClassPtr.Attach(pClass); m_listClass.AddTail(ClassPtr);
//
// The class object has been inserted to the list
// it is safe now to detach the object from the smart pointer
// The class object will be deleted by the list
//
ClassPtr.Detach();
//
// Create the device
//
SafePtr<CDevice> DevicePtr; CDevice* pDevice; pDevice = new CDevice(this, pClass, &DevData);
if (pDevice) { //
// Guard the object
//
DevicePtr.Attach(pDevice); m_listDevice.AddTail(DevicePtr);
//
// Object added..
//
DevicePtr.Detach();
pClass->AddDevice(pDevice); } } }
//
// We should have one class and one device object. no more no less.
// we are done here.
//
return(1 == m_listClass.GetCount() && 1 == m_listDevice.GetCount()); }
//
// If the object is for a specific class then just create the class and add
// it to the CMachine.
//
else if (ClassGuid) {
CClass* pClass; SafePtr<CClass> ClassPtr; pClass = new CClass(this, ClassGuid);
if (pClass) { ClassPtr.Attach(pClass); m_listClass.AddTail(ClassPtr);
//
// The class object has been inserted to the list
// it is safe now to detach the object from the smart pointer
// The class object will be deleted by the list
//
ClassPtr.Detach(); }
//
// We should have one class. no more no less.
// we are done here.
//
return(1 == m_listClass.GetCount()); }
//
// Build class guid list
//
DWORD ClassGuids, GuidsRequired; GuidsRequired = 0;
//
// We make a guess here to save us some time.
//
GUID LocalGuid[GUID_LIST_INIT_SIZE]; ClassGuids = GUID_LIST_INIT_SIZE;
if (DiBuildClassInfoList(0, LocalGuid, ClassGuids, &GuidsRequired)) { BuildClassesFromGuidList(LocalGuid, GuidsRequired); } else if (ERROR_INSUFFICIENT_BUFFER == GetLastError() && GuidsRequired) { //
// The stack based buffer is too small, allocate buffer from
// the heap.
//
BufferPtr<GUID> ClassGuidList(GuidsRequired);
if (DiBuildClassInfoList(0, ClassGuidList, GuidsRequired, &ClassGuids)) { BuildClassesFromGuidList(ClassGuidList, ClassGuids); } }
//
// If we have any classes at all, create devices objects
//
if (!m_listClass.IsEmpty()) { DWORD Index = 0; SP_DEVINFO_DATA DevData;
//
// We need a handle to the service manager in the DoNotCreateDevice
// function. We will open it once and pass it to this function rather
// than opening and closing it for every device.
//
SCMHandle = OpenSCManager(NULL, NULL, GENERIC_READ);
//
// Create every device in the devinfo list and
// associate each device to its class.
//
DevData.cbSize = sizeof(DevData); while (DiEnumDeviceInfo(Index, &DevData)) { POSITION pos = m_listClass.GetHeadPosition(); CClass* pClass;
//
// Find the class for this device
//
while (NULL != pos) { pClass = m_listClass.GetNext(pos);
//
// Match the ClassGuid for this device.
// Note that if the device does not have a class guid (GUID_NULL)
// then we will put it in class GUID_DEVCLASS_UNKNOWN)
//
if ((IsEqualGUID(DevData.ClassGuid, *pClass)) || (IsEqualGUID(GUID_DEVCLASS_UNKNOWN, *pClass) && IsEqualGUID(DevData.ClassGuid, GUID_NULL))) { //
// Is this one of the special DevInst that we should
// not create a CDevice for?
//
if (DoNotCreateDevice(SCMHandle, *pClass, DevData.DevInst)) {
break; }
//
// Create the device
//
SafePtr<CDevice> DevicePtr; CDevice* pDevice; pDevice = new CDevice(this, pClass, &DevData);
//
// Guard the object
//
DevicePtr.Attach(pDevice); m_listDevice.AddTail(DevicePtr);
//
// Object added.
//
DevicePtr.Detach();
//
// Put the device under the class
//
pClass->AddDevice(pDevice);
break; }
//
// No class than, no device
//
}
//
// next device
//
Index++; }
CloseServiceHandle(SCMHandle);
//
// Create a device tree under computer
// the tree order comes from DEVNODE structure;
//
DEVNODE dnRoot = CmGetRootDevNode(); m_pComputer = new CComputer(this, dnRoot); DEVNODE dnStart = CmGetChild(dnRoot); CreateDeviceTree(m_pComputer, NULL, dnStart); }
return TRUE; }
//
// This function builds a device tree based on the Devnode tree retreived
// from configuration manager. Note that ALL CDevice are created before
// this function is called. This function establishs each CDevice relationship.
//
void CMachine::CreateDeviceTree( CDevice* pParent, CDevice* pSibling, DEVNODE dn ) { CDevice* pDevice; DEVNODE dnChild, dnSibling;
while (dn) { pDevice = DevNodeToDevice(dn);
if (pDevice) { //
// No sibling ->this is the first child
//
if (!pSibling) { pParent->SetChild(pDevice); }
else { pSibling->SetSibling(pDevice); }
pDevice->SetParent(pParent); pSibling = pDevice; dnChild = CmGetChild(dn);
if (dnChild) { CreateDeviceTree(pDevice, NULL, dnChild); } }
dn = CmGetSibling(dn); } }
//
// Find CDevice from the given devnode
//
CDevice* CMachine::DevNodeToDevice( DEVNODE dn ) { POSITION pos = m_listDevice.GetHeadPosition();
while (NULL != pos) { CDevice* pDevice = m_listDevice.GetNext(pos);
if (pDevice->GetDevNode() == dn) {
return pDevice; } }
return NULL; }
//
// Find CDevice from the given device id
//
CDevice* CMachine::DeviceIDToDevice( LPCTSTR DeviceID ) { if (!DeviceID) { return NULL; }
POSITION pos = m_listDevice.GetHeadPosition();
while (NULL != pos) { CDevice* pDevice = m_listDevice.GetNext(pos);
if (*pDevice == DeviceID) { return pDevice; } }
return NULL; }
//
// Find CClass from the given GUID
//
CClass* CMachine::ClassGuidToClass( LPGUID ClassGuid ) { if (!ClassGuid) { return NULL; }
POSITION pos = m_listClass.GetHeadPosition();
while (NULL != pos) { CClass* pClass = m_listClass.GetNext(pos);
if (IsEqualGUID(*ClassGuid, *pClass)) { return pClass; } }
return NULL; }
BOOL CMachine::LoadStringWithMachineName( int StringId, LPTSTR Buffer, DWORD* BufferLen ) { if (!BufferLen || *BufferLen && !Buffer) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
TCHAR Format[LINE_LEN]; TCHAR Temp[1024];
LoadResourceString(StringId, Format, ARRAYLEN(Format));
if (IsLocal()) { TCHAR LocalComputer[LINE_LEN]; LoadResourceString(IDS_LOCAL_MACHINE, LocalComputer, ARRAYLEN(LocalComputer)); wsprintf(Temp, Format, LocalComputer); }
else { wsprintf(Temp, Format, (LPCTSTR)m_strMachineFullName); }
DWORD Len = lstrlen(Temp);
if (*BufferLen > Len) { lstrcpyn(Buffer, Temp, Len + 1); *BufferLen = Len; return TRUE; }
else { SetLastError(ERROR_BUFFER_OVERFLOW); *BufferLen = Len; return FALSE; } }
//
// This function reenumerates the devnode tree from the root, rebuilds the
// device tree and notifies every attached folder about the new device tree.
//
BOOL CMachine::Reenumerate() { BOOL Result = FALSE;
if (m_pComputer) { //
// Temporarily disable refresh while we are doing reenumeration
// so that we will not keep refreshing the device tree.
//
EnableRefresh(FALSE);
CDialog WaitDialog(IDD_SCAN_PNP_HARDWARES);
WaitDialog.DoModaless(m_hwndParent, (LPARAM)&WaitDialog);
if (!CmReenumerate( m_pComputer->GetDevNode(), CM_REENUMERATE_SYNCHRONOUS | CM_REENUMERATE_RETRY_INSTALLATION )) {
//
// Win2K doesn't support CM_REENUMERATE_RETRY_INSTALLATION, so we
// retry without the reinstall flag.
//
CmReenumerate(m_pComputer->GetDevNode(), CM_REENUMERATE_SYNCHRONOUS); }
DestroyWindow(WaitDialog);
//
// reenumeration is done, schedule a refresh and enable refresh now.
//
ScheduleRefresh();
EnableRefresh(TRUE);
}
return TRUE; }
//
// This function enable/disable refresh. A disble counter is kept to
// support multiple disabling/enabling. Only when the disable counter
// is zero, a refresh is possible.
// If a refresh is pending while we are enabling, we schedule a new
// request so that we will not lose any requests.
//
BOOL CMachine::EnableRefresh( BOOL fEnable ) { BOOL Result = TRUE; Lock();
if (fEnable) { if (m_RefreshDisableCounter < 0) { m_RefreshDisableCounter++; } }
else { m_RefreshDisableCounter--;
}
//
// If we are enabling refresh and there is one request pending,
// schedule it again. This makes sure that we will not lose
// any requests.
// We schedule a new refresh request instead of calling Refresh
// directly because we can be called by different threads while
// we want the refresh to be done in the main thread. The data window
// we created will receive the message and execute the refresh
// in the main thread context.
//
if (fEnable && m_RefreshPending) { m_RefreshPending = FALSE; ScheduleRefresh(); }
Unlock(); return Result; }
//
//
// This function rebuilds the entire list of CClass and CDevice
// All attached CFolder are notified about the new machine.
//
// There are several occasions that we need to recreate the device tree:
// (1). On WM_DEVICECHANGE.
// (2). Device properties changed.
// (3). Device removal.
// (4). Device drivers updated and
// (5). Reenumeration requested by users.
// The requests may come from different threads and we must serialize
// the requests. A critical section and a new function(EnableRefresh) are added for
// for this purpose.
// Before doing anything on a device or class, one must call EnableRefesh(FALSE)
// to suspend Device change notification. When it is done with the change,
// one must call ScheduleRefesh function(if a refresh is necessary because of
// the changes) and then EnableRefresh(TRUE) to reenable the refresh.
//
BOOL CMachine::Refresh() { BOOL Result = TRUE; POSITION pos; Lock();
if (0 == m_RefreshDisableCounter) {
HCURSOR hCursorOld; hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// Before we destroy all the classes and devices,
// notify every attached folder so that they can dis-engaged
// from us. After we created a new set of classes and devices,
// the notification will be sent again to each folder
// so that each folder can enagage to the machine again.
//
pos = m_listFolders.GetHeadPosition();
while (NULL != pos) { ((CFolder*)m_listFolders.GetNext(pos))->MachinePropertyChanged(NULL); }
//
// we can destroy all the "old" classes and devices now.
//
DestroyClassesAndDevices(); if (CreateClassesAndDevices()) { //
// Notify every attach folder to recreate
//
if (!m_listFolders.IsEmpty()) { pos = m_listFolders.GetHeadPosition();
while (NULL != pos) { CFolder* pFolder = m_listFolders.GetNext(pos); Result = SUCCEEDED(pFolder->MachinePropertyChanged(this)); } }
//
// Notify every property page to refresh
//
if (!m_listChildMachines.IsEmpty()) {
EnterCriticalSection(&m_ChildMachineCriticalSection);
POSITION nextpos = m_listChildMachines.GetHeadPosition();
while (nextpos) { pos = nextpos;
CMachine* pMachineToNotify = m_listChildMachines.GetNext(nextpos);
pMachineToNotify->DoMiniRefresh(); }
LeaveCriticalSection(&m_ChildMachineCriticalSection); } }
if (hCursorOld) { SetCursor(hCursorOld); }
m_RefreshPending = FALSE; }
else { //
// We need to refresh while the refresh is disabled
// Remember this so that when refresh is enabled, we
// can launch a refresh.
//
m_RefreshPending = TRUE; }
Unlock();
return Result; }
//
// A mini refresh is performed when the CMachine only has a single CClass or
// CDevice. This is because this will be the property sheet case. In this
// case we will see if the class or device represented by this property sheet
// still exists. If it doesn't then we will destroy the property sheet.
//
BOOL CMachine::DoMiniRefresh() { BOOL Result = TRUE;
Lock();
//
// If the machine has one CDevice then we need to see if this device is
// still around.
//
if (1 == m_listDevice.GetCount()) {
DEVNODE dn; PVOID Context; CDevice* pDevice;
if (GetFirstDevice(&pDevice, Context)) { /*
//
// We need to verify two things here. First is that we can locate
// this device instance id, at least as a phantom. The second is
// we need to make sure that the devnode is the same as that of the
// property sheet. If we can't locate this device instance id, or
// the devnode is different then we need to destroy the property
// sheet. The device instance id will go away if the user uninstalls
// this device. The devnode will be different if this device goes
// from a live devnode to a phantom or vice versa.
//
if ((CM_Locate_DevNode_Ex(&dn, (DEVNODEID)pDevice->GetDeviceID(), CM_LOCATE_DEVNODE_PHANTOM, m_hMachine ) != CR_SUCCESS) || (dn != pDevice->GetDevNode())) {
//
// Either this device instance id has been uninstalled or the devnode
// has been changed, this means we need to destroy the property sheet.
//
Result = FALSE;
} else { */ //
// If the devnode did not go away we should tell it to refresh itself
// in case something changed.
//
::PostMessage(pDevice->m_psd.GetWindowHandle(), PSM_QUERYSIBLINGS, QSC_PROPERTY_CHANGED, 0L); // }
} }
//
// Note that currently we don't do anything in the class property sheet case.
// The reason for this is that classes can't really go away unless someone deletes
// them from the registry, which probably wills mess up lots of other things. Also
// all current class property sheets don't do anything anyway and so even if someone
// does delete the class key nothing bad will happen to the property sheet.
//
Unlock();
return Result; }
BOOL CMachine::GetFirstDevice( CDevice** ppDevice, PVOID& Context ) { ASSERT(ppDevice);
if (!m_listDevice.IsEmpty()) { POSITION pos = m_listDevice.GetHeadPosition(); *ppDevice = m_listDevice.GetNext(pos); Context = pos; return TRUE; }
*ppDevice = NULL; Context = NULL; return FALSE; }
BOOL CMachine::GetNextDevice( CDevice** ppDevice, PVOID& Context ) { ASSERT(ppDevice); POSITION pos = (POSITION)Context;
if (NULL != pos) { *ppDevice = m_listDevice.GetNext(pos); Context = pos; return TRUE; }
*ppDevice = NULL; return FALSE; }
BOOL CMachine::GetFirstClass( CClass** ppClass, PVOID& Context ) { ASSERT(ppClass);
if (!m_listClass.IsEmpty()) { POSITION pos = m_listClass.GetHeadPosition(); *ppClass = m_listClass.GetNext(pos); Context = pos;
return TRUE; }
*ppClass = NULL; Context = NULL; return FALSE; }
BOOL CMachine::GetNextClass( CClass** ppClass, PVOID& Context ) { ASSERT(ppClass); POSITION pos = (POSITION)Context;
if (NULL != pos) { *ppClass = m_listClass.GetNext(pos); Context = pos; return TRUE; }
*ppClass = NULL; return FALSE; }
BOOL CMachine::pGetOriginalInfName( LPTSTR InfName, String& OriginalInfName ) { SP_ORIGINAL_FILE_INFO InfOriginalFileInformation; PSP_INF_INFORMATION pInfInformation; DWORD InfInformationSize; BOOL bRet;
ZeroMemory(&InfOriginalFileInformation, sizeof(InfOriginalFileInformation));
InfInformationSize = 8192; // I'd rather have this too big and succeed first time, than read the INF twice
pInfInformation = (PSP_INF_INFORMATION)LocalAlloc(LPTR, InfInformationSize);
if (pInfInformation != NULL) {
bRet = SetupGetInfInformation(InfName, INFINFO_INF_NAME_IS_ABSOLUTE, pInfInformation, InfInformationSize, &InfInformationSize );
DWORD Error = GetLastError();
//
// If buffer was too small then make the buffer larger and try again.
//
if (!bRet && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
PVOID newbuff = LocalReAlloc(pInfInformation, InfInformationSize, LPTR);
if (!newbuff) {
LocalFree(pInfInformation); pInfInformation = NULL;
} else {
pInfInformation = (PSP_INF_INFORMATION)newbuff; bRet = SetupGetInfInformation(InfName, INFINFO_INF_NAME_IS_ABSOLUTE, pInfInformation, InfInformationSize, &InfInformationSize ); } }
if (bRet) {
InfOriginalFileInformation.cbSize = sizeof(InfOriginalFileInformation);
if (SetupQueryInfOriginalFileInformation(pInfInformation, 0, NULL, &InfOriginalFileInformation)) {
if (InfOriginalFileInformation.OriginalInfName[0]!=0) {
//
// we have a "real" inf name
//
OriginalInfName = InfOriginalFileInformation.OriginalInfName; } } }
//
// Assume that this INF has not been renamed
//
else {
OriginalInfName = MyGetFileTitle(InfName); }
if (pInfInformation != NULL) {
LocalFree(pInfInformation); pInfInformation = NULL; } }
return TRUE; }
BOOL CMachine::GetDigitalSigner( LPTSTR FullInfPath, String& DigitalSigner ) { SP_INF_SIGNER_INFO InfSignerInfo; BOOL bRet = FALSE;
if (m_UserIsAGuest || !IsLocal()) { //
// If the user is loged in as a guest, or we are not on the local
// machine, then make the digital signer string be 'Not available'
//
DigitalSigner.LoadString(g_hInstance, IDS_NOT_AVAILABLE); } else { InfSignerInfo.cbSize = sizeof(InfSignerInfo); bRet = SetupVerifyInfFile(FullInfPath, NULL, &InfSignerInfo ); if (bRet && (InfSignerInfo.DigitalSigner[0] != TEXT('\0'))) { DigitalSigner = (LPTSTR)InfSignerInfo.DigitalSigner; } }
return bRet; }
BOOL CMachine::DoNotCreateDevice( SC_HANDLE SCMHandle, LPGUID ClassGuid, DEVINST DevInst ) /*++
This function returns whether a CDevice should be created for this DevInst or not. If a CDevice is not created for DevInst then it will never show up in the device manager UI, even when "Show hidden devices" is turned on.
We don't create a CDevice in the following cases:
- DevInst is HTREE\ROOT\0 - DevInst is a Win32 Service.
--*/ { SC_HANDLE ServiceHandle; TCHAR ServiceName[MAX_PATH]; LPQUERY_SERVICE_CONFIG ServiceConfig = NULL; DWORD ServiceConfigSize; ULONG Size; String strDeviceID; BOOL Return = FALSE;
//
// If the DEVMGR_SHOW_NONPRESENT_DEVICES environment variable is not set then
// we do not want to show any Phantom devices.
//
if (!m_ShowNonPresentDevices) {
ULONG Status, Problem;
if ((!CmGetStatus(DevInst, &Status, &Problem)) && ((m_LastCR == CR_NO_SUCH_VALUE) || (m_LastCR == CR_NO_SUCH_DEVINST))) {
return TRUE; } }
//
// Check to see if this device is a Win32 service. Only
// legacy devices could be Win32 services.
//
if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_LEGACYDRIVER)) {
Size = sizeof(ServiceName); if (CmGetRegistryProperty(DevInst, CM_DRP_SERVICE, (PVOID)ServiceName, &Size ) == CR_SUCCESS) {
//
// Open this particular service
//
if ((ServiceHandle = OpenService(SCMHandle, ServiceName, GENERIC_READ)) != NULL) {
//
// Get the service config
//
if ((!QueryServiceConfig(ServiceHandle, NULL, 0, &ServiceConfigSize)) && (ERROR_INSUFFICIENT_BUFFER == GetLastError())) {
if ((ServiceConfig = (LPQUERY_SERVICE_CONFIG)malloc(ServiceConfigSize)) != NULL) {
if (QueryServiceConfig(ServiceHandle, ServiceConfig, ServiceConfigSize, &ServiceConfigSize)) {
if (ServiceConfig->dwServiceType & (SERVICE_WIN32 | SERVICE_FILE_SYSTEM_DRIVER)) {
Return = TRUE; }
}
free(ServiceConfig); } }
CloseServiceHandle(ServiceHandle); } } }
//
// Check to see if this is the HTREE\ROOT\0 device. We don't
// want to create a CDevice for this phantom devnode.
//
// This is an else statement because the HTREE\ROOT\0 device is
// not in the legacy device class.
//
else {
CmGetDeviceIDString(DevInst, strDeviceID); if (!lstrcmpi((LPTSTR)strDeviceID, TEXT("HTREE\\ROOT\\0"))) {
Return = TRUE; } }
return Return; }
BOOL CMachine::DiGetClassFriendlyNameString( LPGUID Guid, String& strClass ) { TCHAR DisplayName[LINE_LEN + 1];
//
// Try friendly name first. If it failed, try the class name
//
if (SetupDiGetClassDescriptionEx(Guid, DisplayName, ARRAYLEN(DisplayName), NULL, GetRemoteMachineFullName(), NULL) || SetupDiClassNameFromGuidEx(Guid, DisplayName, ARRAYLEN(DisplayName), NULL, GetRemoteMachineFullName(), NULL)) { strClass = DisplayName; return TRUE; }
return FALSE; }
DEVNODE CMachine::CmGetParent( DEVNODE dn ) { DEVNODE dnParent;
m_LastCR = CM_Get_Parent_Ex(&dnParent, dn, 0, m_hMachine);
if (CR_SUCCESS == m_LastCR) { return dnParent; }
return NULL; }
DEVNODE CMachine::CmGetChild( DEVNODE dn ) { DEVNODE dnChild; m_LastCR = CM_Get_Child_Ex(&dnChild, dn, 0, m_hMachine);
if (CR_SUCCESS == m_LastCR) { return dnChild; }
return NULL; }
DEVNODE CMachine::CmGetSibling( DEVNODE dn ) { DEVNODE dnSibling;
m_LastCR = CM_Get_Sibling_Ex(&dnSibling, dn, 0, m_hMachine);
if (CR_SUCCESS == m_LastCR) { return dnSibling; }
return NULL; }
DEVNODE CMachine::CmGetRootDevNode() { DEVNODE dnRoot;
m_LastCR = CM_Locate_DevNode_Ex(&dnRoot, NULL, 0, m_hMachine);
if (CR_SUCCESS == m_LastCR) { return dnRoot; }
return NULL; }
BOOL CMachine::CmGetDeviceIDString( DEVNODE dn, String& str ) { TCHAR DeviceID[MAX_DEVICE_ID_LEN + 1];
m_LastCR = CM_Get_Device_ID_Ex(dn, DeviceID, ARRAYLEN(DeviceID), 0, m_hMachine);
if (CR_SUCCESS == m_LastCR) { str = DeviceID; return TRUE; }
return FALSE; }
BOOL CMachine::CmGetConfigFlags( DEVNODE dn, DWORD* pFlags ) { DWORD Size;
Size = sizeof(DWORD); m_LastCR = CmGetRegistryProperty(dn, CM_DRP_CONFIGFLAGS, pFlags, &Size);
return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmGetCapabilities( DEVNODE dn, DWORD* pCapabilities ) { DWORD Size;
Size = sizeof(DWORD); m_LastCR = CmGetRegistryProperty(dn, CM_DRP_CAPABILITIES, pCapabilities, &Size);
return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmGetDescriptionString( DEVNODE dn, String& str ) { TCHAR Description[LINE_LEN + 1]; ULONG Size = sizeof(Description);
Description[0] = TEXT('\0');
m_LastCR = CmGetRegistryProperty(dn, CM_DRP_FRIENDLYNAME, Description, &Size);
if ((CR_NO_SUCH_VALUE == m_LastCR) || (Description[0] == TEXT('\0'))) {
Size = sizeof(Description); m_LastCR = CmGetRegistryProperty(dn, CM_DRP_DEVICEDESC, Description, &Size); }
if ((CR_SUCCESS == m_LastCR) && (Description[0] != TEXT('\0'))) {
str = Description; return TRUE; }
return FALSE; }
BOOL CMachine::CmGetMFGString( DEVNODE dn, String& str ) { TCHAR MFG[LINE_LEN + 1]; ULONG Size = sizeof(MFG);
m_LastCR = CmGetRegistryProperty(dn, CM_DRP_MFG, MFG, &Size);
if (CR_SUCCESS == m_LastCR) { str = MFG; return TRUE; }
return FALSE; }
BOOL CMachine::CmGetProviderString( DEVNODE dn, String& str ) { TCHAR Provider[LINE_LEN + 1]; ULONG Size = sizeof(Provider);
m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("ProviderName"), Provider, &Size);
if (CR_SUCCESS == m_LastCR) { str = Provider; return TRUE; }
return FALSE; }
BOOL CMachine::CmGetDriverDateString( DEVNODE dn, String& str ) { TCHAR DriverDate[LINE_LEN + 1]; ULONG Size = sizeof(DriverDate);
m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("DriverDate"), DriverDate, &Size);
if (CR_SUCCESS == m_LastCR) { str = DriverDate; return TRUE; }
return FALSE; }
BOOL CMachine::CmGetDriverDateData( DEVNODE dn, FILETIME *ft ) { ULONG Size = sizeof(*ft);
m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("DriverDateData"), ft, &Size);
return(m_LastCR == CR_SUCCESS); }
BOOL CMachine::CmGetDriverVersionString( DEVNODE dn, String& str ) { TCHAR DriverVersion[LINE_LEN + 1]; ULONG Size = sizeof(DriverVersion);
m_LastCR = CmGetRegistrySoftwareProperty(dn, TEXT("DriverVersion"), DriverVersion, &Size);
if (CR_SUCCESS == m_LastCR) { str = DriverVersion; return TRUE; }
return FALSE; }
BOOL CMachine::CmGetBusGuid( DEVNODE dn, LPGUID Guid ) {
ULONG Size = sizeof(*Guid);
m_LastCR = CmGetRegistryProperty(dn, CM_DRP_BUSTYPEGUID, (LPVOID)Guid, &Size);
if (CR_SUCCESS == m_LastCR) {
return TRUE; }
return FALSE; }
BOOL CMachine::CmGetBusGuidString( DEVNODE dn, String& str ) { GUID BusGuid; TCHAR BusGuidString[MAX_GUID_STRING_LEN]; ULONG Size;
while (dn) { //
// We have to set the size on each loop
//
Size = sizeof(BusGuid); m_LastCR = CmGetRegistryProperty(dn, CM_DRP_BUSTYPEGUID, &BusGuid, &Size);
if (CR_SUCCESS == m_LastCR && GuidToString(&BusGuid, BusGuidString, ARRAYLEN(BusGuidString))) {
str = BusGuidString; return TRUE; }
dn = CmGetParent(dn); }
return FALSE; }
BOOL CMachine::CmGetClassGuid( DEVNODE dn, GUID& Guid ) { TCHAR szGuidString[MAX_GUID_STRING_LEN + 1]; ULONG Size = sizeof(szGuidString);
m_LastCR = CmGetRegistryProperty(dn, CM_DRP_CLASSGUID, szGuidString, &Size);
if (CR_SUCCESS == m_LastCR && GuidFromString(szGuidString, &Guid)) { return TRUE; }
//
// If we can't get the class GUID from the registry then most likely the device
// does not have a class GUID. If this is the case then we will return
// GUID_DEVCLASS_UNKNOWN
//
else { memcpy(&Guid, &GUID_DEVCLASS_UNKNOWN, sizeof(GUID)); return TRUE; } }
BOOL CMachine::CmGetHardwareIDs( DEVNODE dn, PVOID Buffer, ULONG* BufferLen ) { m_LastCR = CmGetRegistryProperty(dn, CM_DRP_HARDWAREID, Buffer, BufferLen); return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmGetCompatibleIDs( DEVNODE dn, PVOID Buffer, ULONG* BufferLen ) { m_LastCR = CmGetRegistryProperty(dn, CM_DRP_COMPATIBLEIDS, Buffer, BufferLen); return CR_SUCCESS == m_LastCR; }
LPTSTR FormatString( LPCTSTR format, ... ) { LPTSTR str = NULL; va_list arglist; va_start(arglist, format);
if (FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, format, 0, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (LPTSTR)&str, 0, &arglist ) == 0) { str = NULL; }
va_end(arglist);
return str; }
STDAPI_(CONFIGRET) GetLocationInformation( DEVNODE dn, LPTSTR Location, ULONG LocationLen, HMACHINE hMachine ) /*++
Slot x (LocationInformation) Slot x LocationInformation on parent bus
--*/ { CONFIGRET LastCR; DEVNODE dnParent; ULONG ulSize; DWORD UINumber; TCHAR Buffer[MAX_PATH]; TCHAR UINumberDescFormat[MAX_PATH]; TCHAR Format[MAX_PATH];
Buffer[0] = TEXT('\0');
//
// We will first get any LocationInformation for the device. This will either
// be in the LocationInformationOverride value in the devices driver (software) key
// or if that is not present we will look for the LocationInformation value in
// the devices device (hardware) key.
//
HKEY hKey; DWORD Type = REG_SZ; ulSize = sizeof(Buffer); if (CR_SUCCESS == CM_Open_DevNode_Key_Ex(dn, KEY_READ, 0, RegDisposition_OpenExisting, &hKey, CM_REGISTRY_SOFTWARE, hMachine )) {
RegQueryValueEx(hKey, REGSTR_VAL_LOCATION_INFORMATION_OVERRIDE, NULL, &Type, (const PBYTE)Buffer, &ulSize );
RegCloseKey(hKey); }
//
// If the buffer is empty then we didn't get the LocationInformationOverride
// value in the device's software key. So, we will see if their is a
// LocationInformation value in the device's hardware key.
//
if (Buffer[0] == TEXT('\0')) {
ulSize = sizeof(Buffer); CM_Get_DevNode_Registry_Property_Ex(dn, CM_DRP_LOCATION_INFORMATION, NULL, Buffer, &ulSize, 0, hMachine ); }
//
// UINumber has precedence over all other location information so check if this
// device has a UINumber.
//
ulSize = sizeof(UINumber); if (((LastCR = CM_Get_DevNode_Registry_Property_Ex(dn, CM_DRP_UI_NUMBER, NULL, &UINumber, &ulSize, 0, hMachine )) == CR_SUCCESS) && (ulSize > 0)) {
UINumberDescFormat[0] = TEXT('\0'); ulSize = sizeof(UINumberDescFormat);
//
// Get the UINumber description format string from the device's parent,
// if there is one, otherwise default to 'Location %1'
if ((CM_Get_Parent_Ex(&dnParent, dn, 0, hMachine) == CR_SUCCESS) && (CM_Get_DevNode_Registry_Property_Ex(dnParent, CM_DRP_UI_NUMBER_DESC_FORMAT, NULL, UINumberDescFormat, &ulSize, 0, hMachine) == CR_SUCCESS) && *UINumberDescFormat) {
} else { ::LoadString(g_hInstance, IDS_UI_NUMBER_DESC_FORMAT, UINumberDescFormat, sizeof(UINumberDescFormat)/sizeof(TCHAR)); }
LPTSTR UINumberBuffer = NULL;
//
// Fill in the UINumber string
//
UINumberBuffer = FormatString(UINumberDescFormat, UINumber);
if (UINumberBuffer) { lstrcpy((LPTSTR)Location, UINumberBuffer); LocalFree(UINumberBuffer); } else { Location[0] = TEXT('\0'); }
//
// If we also have LocationInformation then tack that on the end of the string
// as well.
//
if (*Buffer) { lstrcat((LPTSTR)Location, TEXT(" (")); lstrcat((LPTSTR)Location, Buffer); lstrcat((LPTSTR)Location, TEXT(")")); } }
//
// We don't have a UINumber but we do have LocationInformation
//
else if (*Buffer) { ::LoadString(g_hInstance, IDS_LOCATION, Format, sizeof(Format)/sizeof(TCHAR)); wsprintf((LPTSTR)Location, Format, Buffer); }
//
// We don't have a UINumber or LocationInformation so we need to get a description
// of the parent of this device.
//
else { if ((LastCR = CM_Get_Parent_Ex(&dnParent, dn, 0, hMachine)) == CR_SUCCESS) {
//
// Try the registry for FRIENDLYNAME
//
Buffer[0] = TEXT('\0'); ulSize = sizeof(Buffer); if (((LastCR = CM_Get_DevNode_Registry_Property_Ex(dnParent, CM_DRP_FRIENDLYNAME, NULL, Buffer, &ulSize, 0, hMachine )) != CR_SUCCESS) || !*Buffer) {
//
// Try the registry for DEVICEDESC
//
ulSize = sizeof(Buffer); if (((LastCR = CM_Get_DevNode_Registry_Property_Ex(dnParent, CM_DRP_DEVICEDESC, NULL, Buffer, &ulSize, 0, hMachine )) != CR_SUCCESS) || !*Buffer) {
ulSize = sizeof(Buffer); if (((LastCR = CM_Get_DevNode_Registry_Property_Ex(dnParent, CM_DRP_CLASS, NULL, Buffer, &ulSize, 0, hMachine )) != CR_SUCCESS) || !*Buffer) {
//
// no parent, or parent name.
//
Buffer[0] = TEXT('\0'); } } } }
if (*Buffer) { //
// We have a description of the parent
//
::LoadString(g_hInstance, IDS_LOCATION_NOUINUMBER, Format, sizeof(Format)/sizeof(TCHAR)); wsprintf((LPTSTR)Location, Format, Buffer); } else { //
// We don't have any information so we will just say Unknown
//
::LoadString(g_hInstance, IDS_UNKNOWN, Location, LocationLen); } }
return CR_SUCCESS; }
BOOL CMachine::CmGetStatus( DEVNODE dn, DWORD* pProblem, DWORD* pStatus ) { ASSERT(pProblem && pStatus); m_LastCR = CM_Get_DevNode_Status_Ex(pStatus, pProblem, dn, 0, m_hMachine); return(CR_SUCCESS == m_LastCR); }
BOOL CMachine::CmGetKnownLogConf( DEVNODE dn, LOG_CONF* plc, DWORD* plcType ) { ASSERT(plc);
*plc = 0;
if (plcType) { *plcType = LOG_CONF_BITS + 1; }
ULONG lcTypeFirst = ALLOC_LOG_CONF; ULONG lcTypeLast = FORCED_LOG_CONF; ASSERT(ALLOC_LOG_CONF + 1 == BOOT_LOG_CONF && BOOT_LOG_CONF + 1 == FORCED_LOG_CONF);
for (ULONG lcType = lcTypeFirst; lcType <= lcTypeLast; lcType++) { m_LastCR = CM_Get_First_Log_Conf_Ex(plc, dn, lcType, m_hMachine);
if (CR_SUCCESS == m_LastCR) { if (plcType) { *plcType = lcType; }
break; } }
return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmHasResources( DEVNODE dn ) { for (ULONG lcType = 0; lcType < NUM_LOG_CONF; lcType++) { m_LastCR = CM_Get_First_Log_Conf_Ex(NULL, dn, lcType, m_hMachine);
if (CR_SUCCESS == m_LastCR) { break; } }
return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmReenumerate( DEVNODE dn, ULONG Flags ) { m_LastCR = CM_Reenumerate_DevNode_Ex(dn, Flags, m_hMachine); return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmGetHwProfileFlags( DEVNODE dn, ULONG Profile, ULONG* pFlags ) { TCHAR DeviceID[MAX_DEVICE_ID_LEN + 1];
m_LastCR = CM_Get_Device_ID_Ex(dn, DeviceID, ARRAYLEN(DeviceID), 0, m_hMachine);
if (CR_SUCCESS == m_LastCR) { return CmGetHwProfileFlags(DeviceID, Profile, pFlags); }
return FALSE; }
BOOL CMachine::CmGetHwProfileFlags( LPCTSTR DeviceID, ULONG Profile, ULONG* pFlags ) { m_LastCR = CM_Get_HW_Prof_Flags_Ex((LPTSTR)DeviceID, Profile, pFlags, 0, m_hMachine); return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmSetHwProfileFlags( DEVNODE dn, ULONG Profile, ULONG Flags ) { TCHAR DeviceID[MAX_DEVICE_ID_LEN + 1];
m_LastCR = CM_Get_Device_ID_Ex(dn, DeviceID, ARRAYLEN(DeviceID), 0, m_hMachine);
if (CR_SUCCESS == m_LastCR) { return CmSetHwProfileFlags(DeviceID, Profile, Flags); }
return FALSE; }
BOOL CMachine::CmSetHwProfileFlags( LPCTSTR DeviceID, ULONG Profile, ULONG Flags ) { m_LastCR = CM_Set_HW_Prof_Flags_Ex((LPTSTR)DeviceID, Profile, Flags, 0, m_hMachine); return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmHasDrivers( DEVNODE dn ) { ULONG Size = 0;
m_LastCR = CmGetRegistryProperty(dn, CM_DRP_DRIVER, NULL, &Size);
if (CR_BUFFER_SMALL != m_LastCR) { Size = 0; m_LastCR = CmGetRegistryProperty(dn, CM_DRP_SERVICE, NULL, &Size); }
return(CR_BUFFER_SMALL == m_LastCR); }
BOOL CMachine::CmGetCurrentHwProfile( ULONG* phwpf ) { HWPROFILEINFO hwpfInfo; ASSERT(phwpf);
if (CmGetHwProfileInfo(0xFFFFFFFF, &hwpfInfo)) { *phwpf = hwpfInfo.HWPI_ulHWProfile; return TRUE; }
return FALSE; }
BOOL CMachine::CmGetHwProfileInfo( int Index, PHWPROFILEINFO pHwProfileInfo ) { m_LastCR = CM_Get_Hardware_Profile_Info_Ex(Index, pHwProfileInfo, 0, m_hMachine);
return(CR_SUCCESS == m_LastCR); }
ULONG CMachine::CmGetResDesDataSize( RES_DES rd ) { ULONG Size;
m_LastCR = CM_Get_Res_Des_Data_Size_Ex(&Size, rd, 0, m_hMachine);
if (CR_SUCCESS == m_LastCR) { return Size; }
return 0; }
BOOL CMachine::CmGetResDesData( RES_DES rd, PVOID Buffer, ULONG BufferSize ) { m_LastCR = CM_Get_Res_Des_Data_Ex(rd, Buffer, BufferSize, 0, m_hMachine);
return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmGetNextResDes( PRES_DES prdNext, RES_DES rd, RESOURCEID ForResource, PRESOURCEID pTheResource ) { m_LastCR = CM_Get_Next_Res_Des_Ex(prdNext, rd, ForResource, pTheResource, 0, m_hMachine); return(CR_SUCCESS == m_LastCR); }
void CMachine::CmFreeResDesHandle( RES_DES rd ) { m_LastCR = CM_Free_Res_Des_Handle(rd); }
void CMachine::CmFreeResDes( PRES_DES prdPrev, RES_DES rd ) { m_LastCR = CM_Free_Res_Des_Ex(prdPrev, rd, 0, m_hMachine); }
void CMachine::CmFreeLogConfHandle( LOG_CONF lc ) { m_LastCR = CM_Free_Log_Conf_Handle(lc); }
int CMachine::CmGetNumberOfBasicLogConf( DEVNODE dn ) { LOG_CONF lcFirst; int nLC = 0;
if (CmGetFirstLogConf(dn, &lcFirst, BASIC_LOG_CONF)) { LOG_CONF lcNext; BOOL NoMore = FALSE;
do { NoMore = !CmGetNextLogConf(&lcNext, lcFirst, BASIC_LOG_CONF); CmFreeLogConfHandle(lcFirst); lcFirst = lcNext; nLC++;
} while (NoMore); }
return nLC; }
BOOL CMachine::CmGetFirstLogConf( DEVNODE dn, LOG_CONF* plc, ULONG Type ) { m_LastCR = CM_Get_First_Log_Conf_Ex(plc, dn, Type, m_hMachine);
return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmGetNextLogConf( LOG_CONF* plcNext, LOG_CONF lcRef, ULONG Type ) { m_LastCR = CM_Get_Next_Log_Conf_Ex(plcNext, lcRef, Type, m_hMachine);
return CR_SUCCESS == m_LastCR; }
ULONG CMachine::CmGetArbitratorFreeDataSize( DEVNODE dn, RESOURCEID ResType ) { ULONG Size; m_LastCR = CM_Query_Arbitrator_Free_Size_Ex(&Size, dn, ResType, 0, m_hMachine); if (CR_SUCCESS == m_LastCR) { return Size; }
return 0; }
BOOL CMachine::CmGetArbitratorFreeData( DEVNODE dn, PVOID pBuffer, ULONG BufferSize, RESOURCEID ResType ) { m_LastCR = CM_Query_Arbitrator_Free_Data_Ex(pBuffer, BufferSize, dn, ResType, 0, m_hMachine );
return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmTestRangeAvailable( RANGE_LIST RangeList, DWORDLONG dlBase, DWORDLONG dlEnd ) { m_LastCR = CM_Test_Range_Available(dlBase, dlEnd, RangeList, 0);
return(CR_SUCCESS == m_LastCR); }
void CMachine::CmDeleteRange( RANGE_LIST RangeList, DWORDLONG dlBase, DWORDLONG dlLen ) { DWORDLONG dlEnd = dlBase + dlLen - 1;
m_LastCR = CM_Delete_Range(dlBase, dlEnd, RangeList, 0); }
BOOL CMachine::CmGetFirstRange( RANGE_LIST RangeList, DWORDLONG* pdlBase, DWORDLONG* pdlLen, RANGE_ELEMENT* pre ) { m_LastCR = CM_First_Range(RangeList, pdlBase, pdlLen, pre, 0);
if (CR_SUCCESS == m_LastCR) { *pdlLen = *pdlLen - *pdlBase + 1; return TRUE; }
return FALSE; }
BOOL CMachine::CmGetNextRange( RANGE_ELEMENT* pre, DWORDLONG* pdlBase, DWORDLONG* pdlLen ) { m_LastCR = CM_Next_Range(pre, pdlBase, pdlLen, 0);
if (CR_SUCCESS == m_LastCR) { *pdlLen = *pdlLen - *pdlBase + 1; return TRUE; }
return FALSE; }
void CMachine::CmFreeRangeList( RANGE_LIST RangeList ) { m_LastCR = CM_Free_Range_List(RangeList, 0); }
CONFIGRET CMachine::CmGetRegistryProperty( DEVNODE dn, ULONG Property, PVOID pBuffer, ULONG* pBufferSize ) { return CM_Get_DevNode_Registry_Property_Ex(dn, Property, NULL, pBuffer, pBufferSize, 0, m_hMachine ); }
CONFIGRET CMachine::CmGetRegistrySoftwareProperty( DEVNODE dn, LPCTSTR ValueName, PVOID pBuffer, ULONG* pBufferSize ) { HKEY hKey; DWORD Type = REG_SZ; CONFIGRET CR;
if (CR_SUCCESS == (CR = CM_Open_DevNode_Key_Ex(dn, KEY_READ, 0, RegDisposition_OpenExisting, &hKey, CM_REGISTRY_SOFTWARE, m_hMachine))) {
if (ERROR_SUCCESS != RegQueryValueEx(hKey, ValueName, NULL, &Type, (const PBYTE)pBuffer, pBufferSize)) {
CR = CR_REGISTRY_ERROR; }
RegCloseKey(hKey); }
return CR; }
BOOL CMachine::CmGetDeviceIdListSize( LPCTSTR Filter, ULONG* Size, ULONG Flags ) { m_LastCR = CM_Get_Device_ID_List_Size_Ex(Size, Filter, Flags, m_hMachine);
return CR_SUCCESS == m_LastCR; }
BOOL CMachine::CmGetDeviceIdList( LPCTSTR Filter, TCHAR* Buffer, ULONG BufferSize, ULONG Flags ) { m_LastCR = CM_Get_Device_ID_List_Ex(Filter, Buffer, BufferSize, Flags, m_hMachine);
return CR_SUCCESS == m_LastCR; }
CMachineList::~CMachineList() { if (!m_listMachines.IsEmpty()) { POSITION pos = m_listMachines.GetHeadPosition(); CMachine* pMachine;
while (NULL != pos) { pMachine = m_listMachines.GetNext(pos); delete pMachine; }
m_listMachines.RemoveAll(); } }
//
// This function creates a machine object on the given machine name
// INPUT:
// hwndParent -- Window Handle to be used as the owner window
// of all possible windows this function may create
// MachineName -- the machine name. Must be in full qualified format
// NULL means the local machine
// ppMachine -- buffer to receive the newly create machine.
//
// OUTPUT:
// TRUE if the machine is created successfully. ppMachine
// is filled with the newly created Machine.
// FALSE if the function failed.
// NOTE:
// The caller should NOT free any machine object retruned
// from this function.
//
BOOL CMachineList::CreateMachine( HWND hwndParent, LPCTSTR MachineName, CMachine** ppMachine ) { ASSERT(ppMachine); *ppMachine = NULL;
CMachine* pMachine = NULL;
if (!MachineName || _T('\0') == MachineName[0]) { //
// Local machine.
//
String strMachineName; strMachineName.GetComputerName(); pMachine = FindMachine(strMachineName); }
else { pMachine = FindMachine(MachineName); }
if (NULL == pMachine) { pMachine = new CMachine(MachineName); m_listMachines.AddTail(pMachine); }
*ppMachine = pMachine;
return NULL != pMachine; }
CMachine* CMachineList::FindMachine( LPCTSTR MachineName ) { if (!m_listMachines.IsEmpty()) { POSITION pos = m_listMachines.GetHeadPosition();
while (NULL != pos) { CMachine* pMachine; pMachine = m_listMachines.GetNext(pos);
if (!lstrcmpi(MachineName, pMachine->GetMachineFullName())) { return pMachine; } } }
return NULL; }
|