Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1308 lines
40 KiB

/*++
Copyright (C) Microsoft Corporation
Module Name:
globals.cpp
Abstract:
This module implements global functions needed for the program.
It also contain global variables/classes.
Author:
William Hsieh (williamh) created
Revision History:
--*/
#include "devmgr.h"
#include <shlobj.h>
#define NO_SHELL_TREE_TYPE
#include <shlobjp.h>
//
// global classes and variables
//
// this, of course, our dll's instance handle.
HINSTANCE g_hInstance = NULL;
//
// A CMachineList is created for each instance of DLL. It is shared
// by all the CComponentData the instance might create. The class CMachine
// contains all the information about all the classes and devices on the
// machine. Each CComponent should register itself to CMachine. This way,
// A CComponent will get notification whenever there are changes in
// the CMachine(Refresh, Property changes on a device, for example).
// We do not rely on MMC's view notification(UpdatAllView) because
// it only reaches all the CComponents created by a CComponenetData.
//
CMachineList g_MachineList;
CMemoryException g_MemoryException(TRUE);
String g_strStartupMachineName;
String g_strStartupDeviceId;
String g_strStartupCommand;
String g_strDevMgr;
BOOL g_IsAdmin = FALSE;
CPrintDialog g_PrintDlg;
//
// UUID consts
//
const CLSID CLSID_DEVMGR = {0x74246BFC,0x4C96,0x11D0,{0xAB,0xEF,0x00,0x20,0xAF,0x6B,0x0B,0x7A}};
const CLSID CLSID_DEVMGR_EXTENSION = {0x90087284,0xd6d6,0x11d0,{0x83,0x53,0x00,0xa0,0xc9,0x06,0x40,0xbf}};
const CLSID CLSID_SYSTOOLS = {0x476e6448,0xaaff,0x11d0,{0xb9,0x44,0x00,0xc0,0x4f,0xd8,0xd5,0xb0}};
const CLSID CLSID_DEVMGR_ABOUT = {0x94abaf2a,0x892a,0x11d1,{0xbb,0xc4,0x00,0xa0,0xc9,0x06,0x40,0xbf}};
const TCHAR* const CLSID_STRING_DEVMGR = TEXT("{74246bfc-4c96-11d0-abef-0020af6b0b7a}");
const TCHAR* const CLSID_STRING_DEVMGR_EXTENSION = TEXT("{90087284-d6d6-11d0-8353-00a0c90640bf}");
const TCHAR* const CLSID_STRING_SYSTOOLS = TEXT("{476e6448-aaff-11d0-b944-00c04fd8d5b0}");
const TCHAR* const CLSID_STRING_DEVMGR_ABOUT = TEXT("{94abaf2a-892a-11d1-bbc4-00a0c90640bf}");
//
// ProgID
//
const TCHAR* const PROGID_DEVMGR = TEXT("DevMgrSnapin.DevMgrSnapin.1");
const TCHAR* const PROGID_DEVMGREXT = TEXT("DevMgrExtension.DevMgrExtension.1");
const TCHAR* const PROGID_DEVMGR_ABOUT = TEXT("DevMgrAbout.DevMgrAbout.1");
//
// Node types const
//
const NODEINFO NodeInfo[TOTAL_COOKIE_TYPES] =
{
{ COOKIE_TYPE_SCOPEITEM_DEVMGR,
IDS_NAME_DEVMGR,
IDS_DISPLAYNAME_SCOPE_DEVMGR,
{0xc41dfb2a,0x4d5b,0x11d0,{0xab,0xef,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
TEXT("{c41dfb2a-4d5b-11d0-abef-0020af6b0b7a}")
},
{ COOKIE_TYPE_RESULTITEM_RESOURCE_IRQ,
IDS_NAME_IRQ,
0,
{0x494535fe,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
TEXT("{494535fe-5aa2-11d0-abf0-0020af6b0b7a}")
},
{ COOKIE_TYPE_RESULTITEM_RESOURCE_DMA,
IDS_NAME_DMA,
0,
{0x49f0df4e,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
TEXT("{49f0df4e-5aa2-11d0-abf0-0020af6b0b7a}")
},
{ COOKIE_TYPE_RESULTITEM_RESOURCE_IO,
IDS_NAME_IO,
0,
{0xa2958d7a,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
TEXT("{a2958d7a-5aa2-11d0-abf0-0020af6b0b7a}")
},
{ COOKIE_TYPE_RESULTITEM_RESOURCE_MEMORY,
IDS_NAME_MEMORY,
0,
{0xa2958d7b,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
TEXT("{a2958d7b-5aa2-11d0-abf0-0020af6b0b7a}")
},
{ COOKIE_TYPE_RESULTITEM_COMPUTER,
IDS_NAME_COMPUTER,
0,
{0xa2958d7c,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
TEXT("{a2958d7c-5aa2-11d0-abf0-0020af6b0b7a}")
},
{ COOKIE_TYPE_RESULTITEM_DEVICE,
IDS_NAME_DEVICE,
0,
{0xa2958d7d,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
TEXT("{a2958d7d-5aa2-11d0-abf0-0020af6b0b7a}")
},
{ COOKIE_TYPE_RESULTITEM_CLASS,
IDS_NAME_CLASS,
0,
{0xe677e204,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
TEXT("{e677e204-5aa2-11d0-abf0-0020af6b0b7a}")
},
{ COOKIE_TYPE_RESULTITEM_RESTYPE,
IDS_NAME_RESOURCES,
0,
{0xa2958d7e,0x5aa2,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}},
TEXT("{a2958d7e-5aa2-11d0-abf0-0020af6b0b7a}")
}
};
const IID IID_IDMTVOCX = \
{0x142525f2,0x59d8,0x11d0,{0xab,0xf0,0x00,0x20,0xaf,0x6b,0x0b,0x7a}};
const IID IID_ISnapinCallback = \
{0x8e0ba98a,0xd161,0x11d0,{0x83,0x53,0x00,0xa0,0xc9,0x06,0x40,0xbf}};
//
// cliboard format strings
//
const TCHAR* const MMC_SNAPIN_MACHINE_NAME = TEXT("MMC_SNAPIN_MACHINE_NAME");
const TCHAR* const SNAPIN_INTERNAL = TEXT("SNAPIN_INTERNAL");
const TCHAR* const DEVMGR_SNAPIN_CLASS_GUID = TEXT("DEVMGR_SNAPIN_CLASS_GUID");
const TCHAR* const DEVMGR_SNAPIN_DEVICE_ID = TEXT("DEVMGR_SNAPIN_DEVICE_ID");
const TCHAR* const DEVMGR_COMMAND_PROPERTY = TEXT("Property");
const TCHAR* const REG_PATH_DEVICE_MANAGER = TEXT("SOFTWARE\\Microsoft\\DeviceManager");
const TCHAR* const REG_STR_BUS_TYPES = TEXT("BusTypes");
const TCHAR* const REG_STR_TROUBLESHOOTERS = TEXT("TroubleShooters");
const TCHAR* const DEVMGR_HELP_FILE_NAME = TEXT("devmgr.hlp");
const TCHAR* const DEVMGR_HTML_HELP_FILE_NAME = TEXT("\\help\\devmgr.chm");
// lookup table to translate problem number to its text resource id.
const PROBLEMINFO g_ProblemInfo[] =
{
{IDS_PROB_NOPROBLEM, 0}, // NO PROBLEM
{IDS_PROB_NOT_CONFIGURED, PIF_CODE_EMBEDDED}, // CM_PROB_NOT_CONFIGURED
{IDS_PROB_DEVLOADERFAILED, PIF_CODE_EMBEDDED}, // CM_PROB_DEVLOADER_FAILED
{IDS_PROB_OUT_OF_MEMORY, PIF_CODE_EMBEDDED}, // CM_PROB_OUT_OF_MEMORY
{IDS_PROB_WRONG_TYPE, PIF_CODE_EMBEDDED}, // CM_PROB_ENTRY_IS_WRONG_TYPE
{IDS_PROB_LACKEDARBITRATOR, PIF_CODE_EMBEDDED}, // CM_PROB_LACKED_ARBITRATOR
{IDS_PROB_BOOT_CONFIG_CONFLICT, PIF_CODE_EMBEDDED}, // CM_PROB_BOOT_CONFIG_CONFLICT
{IDS_PROB_FAILED_FILTER, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_FILTER
{IDS_PROB_DEVLOADER_NOT_FOUND, PIF_CODE_EMBEDDED}, // CM_PROB_DEVLOADER_NOT_FOUND
{IDS_PROB_INVALID_DATA, PIF_CODE_EMBEDDED}, // CM_PROB_INVALID_DATA
{IDS_PROB_FAILED_START, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_START
{IDS_PROB_LIAR, PIF_CODE_EMBEDDED}, // CM_PROB_LIAR
{IDS_PROB_NORMAL_CONFLICT, PIF_CODE_EMBEDDED}, // CM_PROB_NORMAL_CONFLICT
{IDS_PROB_NOT_VERIFIED, PIF_CODE_EMBEDDED}, // CM_PROB_NOT_VERIFIED
{IDS_PROB_NEEDRESTART, PIF_CODE_EMBEDDED}, // CM_PROB_NEED_RESTART
{IDS_PROB_REENUMERATION, PIF_CODE_EMBEDDED}, // CM_PROB_REENUMERATION
{IDS_PROB_PARTIALCONFIG, PIF_CODE_EMBEDDED}, // CM_PROB_PARTIAL_LOG_CONF
{IDS_PROB_UNKNOWN_RESOURCE, PIF_CODE_EMBEDDED}, // CM_PROB_UNKNOWN_RESOURCE
{IDS_PROB_REINSTALL, PIF_CODE_EMBEDDED}, // CM_PROB_REINSTALL
{IDS_PROB_REGISTRY, PIF_CODE_EMBEDDED}, // CM_PROB_REGISTRY
{IDS_PROB_SYSTEMFAILURE, PIF_CODE_EMBEDDED}, // CM_PROB_VXDLDR
{IDS_PROB_WILL_BE_REMOVED, PIF_CODE_EMBEDDED}, // CM_PROB_WILL_BE_REMOVED
{IDS_PROB_DISABLED, PIF_CODE_EMBEDDED}, // CM_PROB_DISABLED
{IDS_PROB_SYSTEMFAILURE, PIF_CODE_EMBEDDED}, // CM_PROB_DEVLOADER_NOT_READY
{IDS_DEVICE_NOT_THERE, PIF_CODE_EMBEDDED}, // CM_PROB_DEVICE_NOT_THERE
{IDS_PROB_MOVED, PIF_CODE_EMBEDDED}, // CM_PROB_MOVED
{IDS_PROB_TOO_EARLY, PIF_CODE_EMBEDDED}, // CM_PROB_TOO_EARLY
{IDS_PROB_NO_VALID_LOG_CONF, PIF_CODE_EMBEDDED}, // CM_PROB_NO_VALID_LOG_CONF
{IDS_PROB_FAILEDINSTALL, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_INSTALL
{IDS_PROB_HARDWAREDISABLED, PIF_CODE_EMBEDDED}, // CM_PROB_HARDWARE_DISABLED
{IDS_PROB_CANT_SHARE_IRQ, PIF_CODE_EMBEDDED}, // CM_PROB_CANT_SHARE_IRQ
{IDS_PROB_FAILED_ADD, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_ADD
{IDS_PROB_DISABLED_SERVICE, PIF_CODE_EMBEDDED}, // CM_PROB_DISABLED_SERVICE
{IDS_PROB_TRANSLATION_FAILED, PIF_CODE_EMBEDDED}, // CM_PROB_TRANSLATION_FAILED
{IDS_PROB_NO_SOFTCONFIG, PIF_CODE_EMBEDDED}, // CM_PROB_NO_SOFTCONFIG
{IDS_PROB_BIOS_TABLE, PIF_CODE_EMBEDDED}, // CM_PROB_BIOS_TABLE
{IDS_PROB_IRQ_TRANSLATION_FAILED, PIF_CODE_EMBEDDED}, // CM_PROB_IRQ_TRANSLATION_FAILED
{IDS_PROB_FAILED_DRIVER_ENTRY, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_DRIVER_ENTRY
{IDS_PROB_DRIVER_FAILED_PRIOR_UNLOAD, PIF_CODE_EMBEDDED}, // CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD
{IDS_PROB_DRIVER_FAILED_LOAD, PIF_CODE_EMBEDDED}, // CM_PROB_DRIVER_FAILED_LOAD
{IDS_PROB_DRIVER_SERVICE_KEY_INVALID, PIF_CODE_EMBEDDED}, // CM_PROB_DRIVER_SERVICE_KEY_INVALID
{IDS_PROB_LEGACY_SERVICE_NO_DEVICES, PIF_CODE_EMBEDDED}, // CM_PROB_LEGACY_SERVICE_NO_DEVICES
{IDS_PROB_DUPLICATE_DEVICE, PIF_CODE_EMBEDDED}, // CM_PROB_DUPLICATE_DEVICE
{IDS_PROB_FAILED_POST_START, PIF_CODE_EMBEDDED}, // CM_PROB_FAILED_POST_START
{IDS_PROB_HALTED, PIF_CODE_EMBEDDED}, // CM_PROB_HALTED
{IDS_PROB_PHANTOM, PIF_CODE_EMBEDDED}, // CM_PROB_PHANTOM
{IDS_PROB_SYSTEM_SHUTDOWN, PIF_CODE_EMBEDDED}, // CM_PROB_SYSTEM_SHUTDOWN
{IDS_PROB_HELD_FOR_EJECT, PIF_CODE_EMBEDDED}, // CM_PROB_HELD_FOR_EJECT
{IDS_PROB_DRIVER_BLOCKED, PIF_CODE_EMBEDDED}, // CM_PROB_DRIVER_BLOCKED
{IDS_PROB_REGISTRY_TOO_LARGE, PIF_CODE_EMBEDDED}, // CM_PROB_REGISTRY_TOO_LARGE
{IDS_PROB_SETPROPERTIES_FAILED, PIF_CODE_EMBEDDED}, // CM_PROB_SETPROPERTIES_FAILED
{IDS_PROB_UNKNOWN_WITHCODE, PIF_CODE_EMBEDDED} // UNKNOWN PROBLEM
};
//
// Global functions
//
#if DBG
//
// Debugging aids
//
void
Trace(
LPCTSTR format,
...
)
{
// according to wsprintf specification, the max buffer size is
// 1024
TCHAR Buffer[1024];
va_list arglist;
va_start(arglist, format);
StringCchVPrintf(Buffer, ARRAYLEN(Buffer), format, arglist);
va_end(arglist);
OutputDebugString(TEXT("DEVMGR: "));
OutputDebugString(Buffer);
OutputDebugString(TEXT("\r\n"));
}
#endif
inline
BOOL
IsBlankChar(TCHAR ch)
{
return (_T(' ') == ch || _T('\t') == ch);
}
inline
LPTSTR
SkipBlankChars(
LPTSTR psz
)
{
while (IsBlankChar(*psz))
psz++;
return psz;
}
//
// This function converts a given string to GUID
// INPUT:
// GuidString -- the null terminated guid string
// LPGUID -- buffer to receive the GUID
// OUTPUT:
// TRUE if the conversion succeeded.
// FALSE if failed.
//
inline
BOOL
GuidFromString(
LPCTSTR GuidString,
LPGUID pGuid
)
{
return ERROR_SUCCESS == pSetupGuidFromString(GuidString, pGuid);
}
// This function converts the given GUID to a string
// INPUT:
// pGuid -- the guid
// Buffer -- the buffer to receive the string
// BufferLen -- the buffer size in char unit
// OUTPUT:
// TRUE if the conversion succeeded.
// FLASE if failed.
//
//
inline
BOOL
GuidToString(
LPGUID pGuid,
LPTSTR Buffer,
DWORD BufferLen
)
{
return ERROR_SUCCESS == pSetupStringFromGuid(pGuid, Buffer, BufferLen);
}
//
// This function allocates an OLE string from OLE task memory pool
// It does necessary char set conversion before copying the string.
//
// INPUT: LPCTSTR str -- the initial string
// OUTPUT: LPOLESTR -- the result OLE string. NULL if the function fails.
//
LPOLESTR
AllocOleTaskString(
LPCTSTR str
)
{
if (!str)
{
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
size_t Len = lstrlen(str);
// allocate the null terminate char also.
LPOLESTR olestr = (LPOLESTR)::CoTaskMemAlloc((Len + 1) * sizeof(TCHAR));
if (olestr)
{
StringCchCopy((LPTSTR)olestr, Len + 1, str);
return olestr;
}
return NULL;
}
inline
void
FreeOleTaskString(
LPOLESTR olestr
)
{
if (olestr)
{
::CoTaskMemFree(olestr);
}
}
//
// This function addes the given menu item to snapin
// INPUT:
// iNameStringId -- menu item text resource id
// iStatusBarStringId -- status bar text resource id.
// iCommandId -- command id to be assigned to the menu item
// InsertionPointId -- Insertion point id
// Flags -- flags
// SpecialFlags -- special flags
// OUTPUT:
// HRESULT
//
HRESULT
AddMenuItem(
LPCONTEXTMENUCALLBACK pCallback,
int iNameStringId,
int iStatusBarStringId,
long lCommandId,
long InsertionPointId,
long Flags,
long SpecialFlags
)
{
ASSERT(pCallback);
CONTEXTMENUITEM tCMI;
memset(&tCMI, 0, sizeof(tCMI));
tCMI.lCommandID = lCommandId;
tCMI.lInsertionPointID = InsertionPointId;
tCMI.fFlags = Flags;
tCMI.fSpecialFlags = SpecialFlags;
TCHAR Name[MAX_PATH];
TCHAR Status[MAX_PATH];
if (::LoadString(g_hInstance, iNameStringId, Name, ARRAYLEN(Name)) != 0) {
tCMI.strName = Name;
}
if (iStatusBarStringId &&
(::LoadString(g_hInstance, iStatusBarStringId, Status, ARRAYLEN(Status)) != 0)) {
tCMI.strStatusBarText = Status;
}
return pCallback->AddItem(&tCMI);
}
//
// This function verifies the given machine name can be accessed remotely.
// INPUT:
// MachineName -- the machine name. The machine name must be
// led by "\\\\".
// OUTPUT:
// BOOL TRUE for success and FALSE for failure. Check GetLastError() for failure
// reason.
//
BOOL
VerifyMachineName(
LPCTSTR MachineName
)
{
CONFIGRET cr = CR_SUCCESS;
HMACHINE hMachine = NULL;
HKEY hRemoteKey = NULL;
HKEY hClass = NULL;
String m_strMachineFullName;
if (MachineName && (_T('\0') != MachineName[0]))
{
if (_T('\\') == MachineName[0] && _T('\\') == MachineName[1]) {
m_strMachineFullName = MachineName;
} else {
m_strMachineFullName = TEXT("\\\\");
m_strMachineFullName+=MachineName;
}
//
// make sure we can connect the machine using cfgmgr32.
//
cr = CM_Connect_Machine((LPTSTR)m_strMachineFullName, &hMachine);
//
// We could not connect to the machine using cfgmgr32
//
if (CR_SUCCESS != cr)
{
goto clean0;
}
//
// make sure we can connect to the registry of the remote machine
//
if (RegConnectRegistry((LPTSTR)m_strMachineFullName,
HKEY_LOCAL_MACHINE,
&hRemoteKey) != ERROR_SUCCESS) {
cr = CR_REGISTRY_ERROR;
goto clean0;
}
cr = CM_Open_Class_Key_Ex(NULL,
NULL,
KEY_READ,
RegDisposition_OpenExisting,
&hClass,
CM_OPEN_CLASS_KEY_INSTALLER,
hMachine
);
}
clean0:
if (hMachine) {
CM_Disconnect_Machine(hMachine);
}
if (hRemoteKey) {
RegCloseKey(hRemoteKey);
}
if (hClass) {
RegCloseKey(hClass);
}
//
// We will basically set two different error codes for this API, since we need
// to present this information to the user.
// 1) ERROR_MACHINE_UNABAILABLE
// 2) ERROR_ACCESS_DENIED.
//
if (CR_SUCCESS == cr) {
SetLastError(NO_ERROR);
} else if (CR_MACHINE_UNAVAILABLE == cr) {
SetLastError(ERROR_MACHINE_UNAVAILABLE);
} else {
SetLastError(ERROR_ACCESS_DENIED);
}
return (CR_SUCCESS == cr);
}
// This function loads the string designated by the given
// string id(resource id) from the module's resource to the provided
// buffer. It returns the required buffer size(in chars) to hold the string,
// not including the terminated NULL chars. Last error will be set
// appropaitely.
//
// input: int StringId -- the resource id of the string to be loaded.
// LPTSTR Buffer -- provided buffer to receive the string
// UINT BufferSize -- the size of Buffer in chars
// output:
// UINT the required buffer size to receive the string
// if it returns 0, GetLastError() returns the error code.
//
UINT
LoadResourceString(
int StringId,
LPTSTR Buffer,
UINT BufferSize
)
{
// do some trivial tests.
if (BufferSize && !Buffer)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
// if caller provides buffer, try to load the string with the given buffer
// and length.
UINT FinalLen;
if (Buffer)
{
FinalLen = ::LoadString(g_hInstance, StringId, Buffer, BufferSize);
if (BufferSize > FinalLen)
{
return FinalLen;
}
}
// Either the caller does not provide the buffer or the given buffer
// is too small. Try to figure out the requried size.
//
// first use a stack-based buffer to get the string. If the buffer
// is big enough, we are happy.
TCHAR Temp[256];
UINT ArrayLen = ARRAYLEN(Temp);
FinalLen = ::LoadString(g_hInstance, StringId, Temp, ArrayLen);
DWORD LastError = ERROR_SUCCESS;
if (ArrayLen <= FinalLen)
{
// the stack-based buffer is too small, use heap-based buffer.
// we have not got all the chars. we increase the buffer size of 256
// chars each time it fails. The initial size is 512(256+256)
// the max size is 32K
ArrayLen = 256;
TCHAR* HeapBuffer;
FinalLen = 0;
while (ArrayLen < 0x8000)
{
ArrayLen += 256;
HeapBuffer = new TCHAR[ArrayLen];
if (HeapBuffer)
{
FinalLen = ::LoadString(g_hInstance, StringId, HeapBuffer, ArrayLen);
delete [] HeapBuffer;
if (FinalLen < ArrayLen)
break;
}
else
{
LastError = ERROR_NOT_ENOUGH_MEMORY;
break;
}
}
if (ERROR_SUCCESS != LastError)
{
SetLastError(LastError);
FinalLen = 0;
}
}
return FinalLen;
}
// This function get the problem text designated by the given problem number
// for the given devnode on the given machine.
//
//
// input:
// ULONG ProblemNumber -- the problem number
// LPTSTR Buffer -- provided buffer to receive the string
// UINT BufferSize -- the size of Buffer in chars
// output:
// UINT the required buffer size to receive the string
// if it returns 0, GetLastError() returns the error code.
//
UINT
GetDeviceProblemText(
ULONG ProblemNumber,
LPTSTR Buffer,
UINT BufferSize
)
{
//
// first does a trivial test
//
if (!Buffer && BufferSize)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
String strMainText;
UINT RequiredSize = 0;
PROBLEMINFO pi;
//
// Get the PROBLEMINFO for the problem number
//
pi = g_ProblemInfo[min(ProblemNumber, DEVMGR_NUM_CM_PROB-1)];
try
{
String strProblemDesc;
strProblemDesc.LoadString(g_hInstance, pi.StringId);
if (pi.Flags & PIF_CODE_EMBEDDED)
{
String strFormat;
strFormat.LoadString(g_hInstance, IDS_PROB_CODE);
String strCodeText;
strCodeText.Format((LPTSTR)strFormat, ProblemNumber);
strMainText.Format((LPTSTR)strProblemDesc, (LPTSTR)strCodeText);
}
else
{
strMainText = strProblemDesc;
}
RequiredSize = strMainText.GetLength() + 1;
//
// copy the main text
//
if (RequiredSize && (BufferSize > RequiredSize))
{
StringCchCopy(Buffer, BufferSize, (LPTSTR)strMainText);
}
}
catch (CMemoryException* e)
{
e->Delete();
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
RequiredSize = 0;
}
return RequiredSize;
}
//
// This function creates and shows a message box
// INPUT:
// hwndParent -- the window handle servers as the parent window to the
// message box
// MsgId -- string id for message box body. The string can be
// a format string.
// CaptionId -- string id for caption. if 0, default is device manager
// Type -- the standard message box flags(MB_xxxx)
// ... -- parameters to MsgId string if it contains any
// format chars.
//OUTPUT:
// return value from MessageBox(IDOK, IDYES...)
int MsgBoxParam(
HWND hwndParent,
int MsgId,
int CaptionId,
DWORD Type,
...
)
{
TCHAR szMsg[MAX_PATH * 4], szCaption[MAX_PATH];;
LPCTSTR pCaption;
va_list parg;
int Result;
// if no MsgId is given, it is for no memory error;
if (MsgId)
{
va_start(parg, Type);
// load the msg string to szCaption(temp). The text may contain
// format information
if (!::LoadString(g_hInstance, MsgId, szCaption, ARRAYLEN(szCaption)))
{
goto NoMemory;
}
//finish up format string
StringCchVPrintf(szMsg, ARRAYLEN(szMsg), szCaption, parg);
// if caption id is given, load it.
if (CaptionId)
{
if (!::LoadString(g_hInstance, CaptionId, szCaption, ARRAYLEN(szCaption)))
{
goto NoMemory;
}
pCaption = szCaption;
}
else
{
pCaption = g_strDevMgr;
}
if ((Result = MessageBox(hwndParent, szMsg, pCaption, Type)) == 0)
{
goto NoMemory;
}
return Result;
}
NoMemory:
g_MemoryException.ReportError(hwndParent);
return 0;
}
// This functin prompts for restart.
// INPUT:
// hwndParent -- the window handle to be used as the parent window
// to the restart dialog
// RestartFlags -- flags(RESTART/REBOOT/POWERRECYCLE)
// ResId -- designated string resource id. If 0, default will
// be used.
// OUTPUT:
// ID returned from the MessageBox. IDYES if the user said Yes to the restart
// dialog and IDNO if they said NO.
INT
PromptForRestart(
HWND hwndParent,
DWORD RestartFlags,
int ResId
)
{
INT id = 0;
if (RestartFlags & (DI_NEEDRESTART | DI_NEEDREBOOT))
{
DWORD ExitWinCode = 0;
try
{
String str;
if (RestartFlags & DI_NEEDRESTART)
{
if (!ResId)
{
ResId = IDS_DEVCHANGE_RESTART;
}
str.LoadString(g_hInstance, ResId);
ExitWinCode = EWX_REBOOT;
}
else
{
if (!ResId && RestartFlags & DI_NEEDPOWERCYCLE)
{
String str2;
str.LoadString(g_hInstance, IDS_POWERCYC1);
str2.LoadString(g_hInstance, IDS_POWERCYC2);
str += str2;
ExitWinCode = EWX_SHUTDOWN;
}
else
{
if (!ResId)
{
ResId = IDS_DEVCHANGE_RESTART;
}
str.LoadString(g_hInstance, ResId);
ExitWinCode = EWX_REBOOT;
}
}
if (ExitWinCode != 0) {
id = RestartDialogEx(hwndParent,
str,
ExitWinCode,
REASON_PLANNED_FLAG | REASON_HWINSTALL
);
}
}
catch(CMemoryException* e)
{
e->Delete();
MsgBoxParam(hwndParent, 0, 0, 0);
}
}
return id;
}
BOOL
LoadEnumPropPage32(
LPCTSTR RegString,
HMODULE* pDll,
FARPROC* pProcAddress
)
{
// verify parameters
if (!RegString || _T('\0') == RegString[0] || !pDll || !pProcAddress)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// make a copy of the string because we have to party on it
ULONG Len = lstrlen(RegString) + 1;
TCHAR* psz = new TCHAR[Len];
if (!psz)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
StringCchCopy(psz, Len, RegString);
LPTSTR DllName = NULL;
LPTSTR DllNameEnd = NULL;
LPTSTR FunctionName = NULL;
LPTSTR FunctionNameEnd = NULL;
LPTSTR p;
p = psz;
SetLastError(ERROR_SUCCESS);
// the format of the string is "dllname, dllentryname"
p = SkipBlankChars(p);
if (_T('\0') != *p)
{
// looking for dllname which could be enclosed
// inside double quote chars.
// NOTE: not double quote chars inside double quoted string is allowed.
if (_T('\"') == *p)
{
DllName = ++p;
while (_T('\"') != *p && _T('\0') != *p)
p++;
DllNameEnd = p;
if (_T('\"') == *p)
p++;
}
else
{
DllName = p;
while (!IsBlankChar(*p) && _T(',') != *p)
p++;
DllNameEnd = p;
}
// looking for ','
p = SkipBlankChars(p);
if (_T('\0') != *p && _T(',') == *p)
{
p = SkipBlankChars(p + 1);
if (_T('\0') != *p)
{
FunctionName = p++;
while (!IsBlankChar(*p) && _T('\0') != *p)
p++;
FunctionNameEnd = p;
}
}
}
if (DllName && FunctionName)
{
if (DllNameEnd) {
*DllNameEnd = _T('\0');
}
if (FunctionNameEnd) {
*FunctionNameEnd = _T('\0');
}
*pDll = LoadLibrary(DllName);
if (*pDll)
{
// convert Wide char to ANSI which is GetProcAddress expected.
// We do not append a 'A" or a "W' here.
CHAR FuncNameA[256];
WideCharToMultiByte(CP_ACP, 0,
FunctionName,
(int)wcslen(FunctionName) + 1,
FuncNameA,
sizeof(FuncNameA),
NULL, NULL);
*pProcAddress = GetProcAddress(*pDll, FuncNameA);
}
}
delete [] psz;
if (!*pProcAddress && *pDll)
FreeLibrary(*pDll);
return (*pDll && *pProcAddress);
}
BOOL
AddPropPageCallback(
HPROPSHEETPAGE hPage,
LPARAM lParam
)
{
CPropSheetData* ppsData = (CPropSheetData*)lParam;
ASSERT(ppsData);
return ppsData->InsertPage(hPage);
}
BOOL
AddToolTips(
HWND hDlg,
UINT id,
LPCTSTR pszText,
HWND *phwnd
)
{
if (*phwnd == NULL)
{
*phwnd = CreateWindow(TOOLTIPS_CLASS,
TEXT(""),
WS_POPUP | TTS_NOPREFIX,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
hDlg,
NULL,
g_hInstance,
NULL);
if (*phwnd)
{
TOOLINFO ti;
ti.cbSize = sizeof(ti);
ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
ti.hwnd = hDlg;
ti.uId = (UINT_PTR)GetDlgItem(hDlg, id);
ti.lpszText = (LPTSTR)pszText; // const -> non const
ti.hinst = g_hInstance;
SendMessage(*phwnd, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
}
}
return (*phwnd) ? TRUE : FALSE;
}
void Int64ToStr(LONGLONG n, LPTSTR lpBuffer)
{
TCHAR szTemp[40];
LONGLONG iChr = 0;
do {
szTemp[iChr++] = TEXT('0') + (TCHAR)(n % 10);
n = n / 10;
} while (n != 0);
do {
iChr--;
*lpBuffer++ = szTemp[iChr];
} while (iChr != 0);
*lpBuffer++ = '\0';
}
//
// Obtain NLS info about how numbers should be grouped.
//
// The annoying thing is that LOCALE_SGROUPING and NUMBERFORMAT
// have different ways of specifying number grouping.
//
// LOCALE NUMBERFMT Sample Country
//
// 3;0 3 1,234,567 United States
// 3;2;0 32 12,34,567 India
// 3 30 1234,567 ??
//
// Not my idea. That's the way it works.
//
UINT GetNLSGrouping(void)
{
TCHAR szGrouping[32];
// If no locale info, then assume Western style thousands
if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szGrouping, ARRAYLEN(szGrouping)))
return 3;
UINT grouping = 0;
LPTSTR psz = szGrouping;
for (;;)
{
if (*psz == '0') break; // zero - stop
else if ((UINT)(*psz - '0') < 10) // digit - accumulate it
grouping = grouping * 10 + (UINT)(*psz - '0');
else if (*psz) // punctuation - ignore it
{ }
else // end of string, no "0" found
{
grouping = grouping * 10; // put zero on end (see examples)
break; // and finished
}
psz++;
}
return grouping;
}
STDAPI_(LPTSTR)
AddCommas64(
LONGLONG n,
LPTSTR pszResult,
UINT cchResult
)
{
TCHAR szTemp[MAX_COMMA_NUMBER_SIZE];
TCHAR szSep[5];
NUMBERFMT nfmt;
nfmt.NumDigits=0;
nfmt.LeadingZero=0;
nfmt.Grouping = GetNLSGrouping();
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYLEN(szSep));
nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
nfmt.NegativeOrder= 0;
Int64ToStr(n, szTemp);
if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, cchResult) == 0)
StringCchCopy(pszResult, cchResult, szTemp);
return pszResult;
}
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
)) {
if (RegQueryValueEx(hKey,
REGSTR_VAL_LOCATION_INFORMATION_OVERRIDE,
NULL,
&Type,
(const PBYTE)Buffer,
&ulSize) != ERROR_SUCCESS) {
Buffer[0] = TEXT('\0');
}
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);
if (CM_Get_DevNode_Registry_Property_Ex(dn,
CM_DRP_LOCATION_INFORMATION,
NULL,
Buffer,
&ulSize,
0,
hMachine) != CR_SUCCESS) {
Buffer[0] = TEXT('\0');
}
}
//
// 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 == sizeof(ULONG))) {
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, ARRAYLEN(UINumberDescFormat));
}
LPTSTR UINumberBuffer = NULL;
//
// Fill in the UINumber string
//
UINumberBuffer = FormatString(UINumberDescFormat, UINumber);
if (UINumberBuffer) {
StringCchCopy((LPTSTR)Location, LocationLen, 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) {
StringCchCat((LPTSTR)Location, LocationLen, TEXT(" ("));
StringCchCat((LPTSTR)Location, LocationLen, Buffer);
StringCchCat((LPTSTR)Location, LocationLen, 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)) != 0)) {
StringCchPrintf((LPTSTR)Location, LocationLen, 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 &&
(::LoadString(g_hInstance, IDS_LOCATION_NOUINUMBER, Format, sizeof(Format)/sizeof(TCHAR)) != 0)) {
//
// We have a description of the parent
//
StringCchPrintf((LPTSTR)Location, LocationLen, Format, Buffer);
} else {
//
// We don't have any information so we will just say Unknown
//
::LoadString(g_hInstance, IDS_UNKNOWN, Location, LocationLen);
}
}
//
// Make sure the Location string is NULL terminated.
//
Location[LocationLen - 1] = TEXT('\0');
return CR_SUCCESS;
}