877 lines
25 KiB
C++
877 lines
25 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1997 - 2000
|
||
|
//
|
||
|
// File: miscutil.c
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include "HotPlug.h"
|
||
|
#include <initguid.h>
|
||
|
#include <ntddstor.h>
|
||
|
#include <wdmguid.h>
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
PTCHAR
|
||
|
BuildLocationInformation(
|
||
|
DEVINST DevInst,
|
||
|
HMACHINE hMachine
|
||
|
)
|
||
|
{
|
||
|
CONFIGRET ConfigRet;
|
||
|
ULONG ulSize;
|
||
|
DWORD UINumber;
|
||
|
PTCHAR Location = NULL;
|
||
|
PTCHAR ParentName;
|
||
|
DEVINST DevInstParent;
|
||
|
int BusLocationStringId;
|
||
|
TCHAR szBuffer[MAX_PATH];
|
||
|
TCHAR UINumberDescFormat[MAX_PATH];
|
||
|
TCHAR szFormat[MAX_PATH];
|
||
|
HKEY hKey;
|
||
|
DWORD Type = REG_SZ;
|
||
|
|
||
|
szBuffer[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.
|
||
|
//
|
||
|
ulSize = sizeof(szBuffer);
|
||
|
if (CR_SUCCESS == CM_Open_DevNode_Key_Ex(DevInst,
|
||
|
KEY_READ,
|
||
|
0,
|
||
|
RegDisposition_OpenExisting,
|
||
|
&hKey,
|
||
|
CM_REGISTRY_SOFTWARE,
|
||
|
hMachine
|
||
|
)) {
|
||
|
|
||
|
RegQueryValueEx(hKey,
|
||
|
REGSTR_VAL_LOCATION_INFORMATION_OVERRIDE,
|
||
|
NULL,
|
||
|
&Type,
|
||
|
(const PBYTE)szBuffer,
|
||
|
&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 (szBuffer[0] == TEXT('\0')) {
|
||
|
|
||
|
//
|
||
|
// Get the LocationInformation for this device.
|
||
|
//
|
||
|
ulSize = sizeof(szBuffer);
|
||
|
CM_Get_DevNode_Registry_Property_Ex(DevInst,
|
||
|
CM_DRP_LOCATION_INFORMATION,
|
||
|
NULL,
|
||
|
szBuffer,
|
||
|
&ulSize,
|
||
|
0,
|
||
|
hMachine
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// UINumber has precedence over all other location information so check if this
|
||
|
// device has a UINumber
|
||
|
//
|
||
|
ulSize = sizeof(UINumber);
|
||
|
if ((CM_Get_DevNode_Registry_Property_Ex(DevInst,
|
||
|
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(&DevInstParent, DevInst, 0, hMachine) == CR_SUCCESS) &&
|
||
|
(CM_Get_DevNode_Registry_Property_Ex(DevInstParent,
|
||
|
CM_DRP_UI_NUMBER_DESC_FORMAT,
|
||
|
NULL,
|
||
|
UINumberDescFormat,
|
||
|
&ulSize,
|
||
|
0,
|
||
|
hMachine) == CR_SUCCESS) &&
|
||
|
*UINumberDescFormat) {
|
||
|
|
||
|
} else {
|
||
|
|
||
|
LoadString(hHotPlug, IDS_UI_NUMBER_DESC_FORMAT, UINumberDescFormat, sizeof(UINumberDescFormat)/sizeof(TCHAR));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Prepend "at " to the begining of the UINumber string.
|
||
|
//
|
||
|
LoadString(hHotPlug, IDS_AT, szFormat, sizeof(szFormat)/sizeof(TCHAR));
|
||
|
lstrcat(szFormat, UINumberDescFormat);
|
||
|
|
||
|
//
|
||
|
// Fill in the UINumber string
|
||
|
//
|
||
|
Location = FormatString(szFormat, UINumber);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We don't have a UINumber but we do have LocationInformation
|
||
|
//
|
||
|
else if (*szBuffer) {
|
||
|
|
||
|
LoadString(hHotPlug, IDS_LOCATION, szFormat, sizeof(szFormat)/sizeof(TCHAR));
|
||
|
Location = (PTCHAR)LocalAlloc(LPTR, lstrlen(szBuffer)*sizeof(TCHAR) + sizeof(szFormat) + sizeof(TCHAR));
|
||
|
|
||
|
if (Location) {
|
||
|
|
||
|
wsprintf(Location, szFormat, szBuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We don't have a UINumber or LocationInformation so we need to get a description
|
||
|
// of the parent of this device.
|
||
|
//
|
||
|
else {
|
||
|
|
||
|
ConfigRet = CM_Get_Parent_Ex(&DevInstParent, DevInst, 0, hMachine);
|
||
|
if (ConfigRet == CR_SUCCESS) {
|
||
|
|
||
|
//
|
||
|
// Try the registry for FRIENDLYNAME
|
||
|
//
|
||
|
|
||
|
ulSize = sizeof(szBuffer);
|
||
|
ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInstParent,
|
||
|
CM_DRP_FRIENDLYNAME,
|
||
|
NULL,
|
||
|
szBuffer,
|
||
|
&ulSize,
|
||
|
0,
|
||
|
hMachine
|
||
|
);
|
||
|
if (ConfigRet != CR_SUCCESS || !*szBuffer) {
|
||
|
//
|
||
|
// Try the registry for DEVICEDESC
|
||
|
//
|
||
|
|
||
|
ulSize = sizeof(szBuffer);
|
||
|
ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInstParent,
|
||
|
CM_DRP_DEVICEDESC,
|
||
|
NULL,
|
||
|
szBuffer,
|
||
|
&ulSize,
|
||
|
0,
|
||
|
hMachine
|
||
|
);
|
||
|
if (ConfigRet != CR_SUCCESS || !*szBuffer) {
|
||
|
|
||
|
GUID ClassGuid;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialize ClassGuid to GUID_NULL
|
||
|
//
|
||
|
CopyMemory(&ClassGuid,
|
||
|
&GUID_NULL,
|
||
|
sizeof(GUID)
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Try the registry for CLASSNAME
|
||
|
//
|
||
|
ulSize = sizeof(szBuffer);
|
||
|
ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInstParent,
|
||
|
CM_DRP_CLASSGUID,
|
||
|
NULL,
|
||
|
szBuffer,
|
||
|
&ulSize,
|
||
|
0,
|
||
|
hMachine
|
||
|
);
|
||
|
|
||
|
|
||
|
if (ConfigRet == CR_SUCCESS) {
|
||
|
|
||
|
pSetupGuidFromString(szBuffer, &ClassGuid);
|
||
|
}
|
||
|
|
||
|
|
||
|
if (!IsEqualGUID(ClassGuid, GUID_NULL) &&
|
||
|
!IsEqualGUID(ClassGuid, GUID_DEVCLASS_UNKNOWN))
|
||
|
{
|
||
|
ulSize = sizeof(szBuffer);
|
||
|
ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInstParent,
|
||
|
CM_DRP_CLASS,
|
||
|
NULL,
|
||
|
szBuffer,
|
||
|
&ulSize,
|
||
|
0,
|
||
|
hMachine
|
||
|
);
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
|
||
|
ConfigRet = ~CR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (*szBuffer) {
|
||
|
|
||
|
LoadString(hHotPlug, IDS_LOCATION_NOUINUMBER, szFormat, sizeof(szFormat)/sizeof(TCHAR));
|
||
|
Location = (PTCHAR)LocalAlloc(LPTR, lstrlen(szBuffer)*sizeof(TCHAR) + sizeof(szFormat) + sizeof(TCHAR));
|
||
|
|
||
|
if (Location) {
|
||
|
|
||
|
wsprintf(Location, szFormat, szBuffer);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Location;
|
||
|
}
|
||
|
|
||
|
PTCHAR
|
||
|
BuildFriendlyName(
|
||
|
DEVINST DevInst,
|
||
|
HMACHINE hMachine
|
||
|
)
|
||
|
{
|
||
|
PTCHAR FriendlyName;
|
||
|
CONFIGRET ConfigRet;
|
||
|
ULONG ulSize;
|
||
|
TCHAR szBuffer[MAX_PATH];
|
||
|
|
||
|
//
|
||
|
// Try the registry for FRIENDLYNAME
|
||
|
//
|
||
|
|
||
|
ulSize = sizeof(szBuffer);
|
||
|
ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
|
||
|
CM_DRP_FRIENDLYNAME,
|
||
|
NULL,
|
||
|
szBuffer,
|
||
|
&ulSize,
|
||
|
0,
|
||
|
hMachine
|
||
|
);
|
||
|
if (ConfigRet != CR_SUCCESS || !*szBuffer) {
|
||
|
//
|
||
|
// Try the registry for DEVICEDESC
|
||
|
//
|
||
|
|
||
|
ulSize = sizeof(szBuffer);
|
||
|
ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
|
||
|
CM_DRP_DEVICEDESC,
|
||
|
NULL,
|
||
|
szBuffer,
|
||
|
&ulSize,
|
||
|
0,
|
||
|
hMachine
|
||
|
);
|
||
|
if (ConfigRet != CR_SUCCESS || !*szBuffer) {
|
||
|
GUID ClassGuid;
|
||
|
|
||
|
//
|
||
|
// Initialize ClassGuid to GUID_NULL
|
||
|
//
|
||
|
CopyMemory(&ClassGuid,
|
||
|
&GUID_NULL,
|
||
|
sizeof(GUID)
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Try the registry for CLASSNAME
|
||
|
//
|
||
|
|
||
|
ulSize = sizeof(szBuffer);
|
||
|
ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
|
||
|
CM_DRP_CLASSGUID,
|
||
|
NULL,
|
||
|
szBuffer,
|
||
|
&ulSize,
|
||
|
0,
|
||
|
hMachine
|
||
|
);
|
||
|
|
||
|
|
||
|
if (ConfigRet == CR_SUCCESS) {
|
||
|
|
||
|
pSetupGuidFromString(szBuffer, &ClassGuid);
|
||
|
}
|
||
|
|
||
|
|
||
|
if (!IsEqualGUID(ClassGuid, GUID_NULL) &&
|
||
|
!IsEqualGUID(ClassGuid, GUID_DEVCLASS_UNKNOWN))
|
||
|
{
|
||
|
ulSize = sizeof(szBuffer);
|
||
|
ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
|
||
|
CM_DRP_CLASS,
|
||
|
NULL,
|
||
|
szBuffer,
|
||
|
&ulSize,
|
||
|
0,
|
||
|
hMachine
|
||
|
);
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
|
||
|
ConfigRet = ~CR_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ConfigRet == CR_SUCCESS && *szBuffer) {
|
||
|
|
||
|
FriendlyName = (PTCHAR)LocalAlloc(LPTR, ulSize);
|
||
|
if (FriendlyName) {
|
||
|
|
||
|
memcpy(FriendlyName, szBuffer, ulSize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
|
||
|
FriendlyName = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
return FriendlyName;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* ----------------------------------------------------------------------
|
||
|
* SetDlgText - Set Dialog Text Field
|
||
|
*
|
||
|
* Concatenates a number of string resources and does a SetWindowText()
|
||
|
* for a dialog text control.
|
||
|
*
|
||
|
* Parameters:
|
||
|
*
|
||
|
* hDlg - Dialog handle
|
||
|
* iControl - Dialog control ID to receive text
|
||
|
* nStartString - ID of first string resource to concatenate
|
||
|
* nEndString - ID of last string resource to concatenate
|
||
|
*
|
||
|
* Note: the string IDs must be consecutive.
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
SetDlgText(HWND hDlg, int iControl, int nStartString, int nEndString)
|
||
|
{
|
||
|
int iX;
|
||
|
TCHAR szText[MAX_PATH];
|
||
|
|
||
|
szText[0] = '\0';
|
||
|
|
||
|
for (iX = nStartString; iX<= nEndString; iX++) {
|
||
|
|
||
|
LoadString(hHotPlug,
|
||
|
iX,
|
||
|
szText + lstrlen(szText),
|
||
|
sizeof(szText)/sizeof(TCHAR) - lstrlen(szText)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (iControl) {
|
||
|
|
||
|
SetDlgItemText(hDlg, iControl, szText);
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
|
||
|
SetWindowText(hDlg, szText);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
HotPlugPropagateMessage(
|
||
|
HWND hWnd,
|
||
|
UINT uMessage,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam
|
||
|
)
|
||
|
{
|
||
|
while ((hWnd = GetWindow(hWnd, GW_CHILD))) {
|
||
|
|
||
|
SendMessage(hWnd, uMessage, wParam, lParam);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
RemovalPermission(
|
||
|
void
|
||
|
)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
HPMessageBox(
|
||
|
HWND hWnd,
|
||
|
int IdText,
|
||
|
int IdCaption,
|
||
|
UINT Type
|
||
|
)
|
||
|
{
|
||
|
TCHAR szText[MAX_PATH];
|
||
|
TCHAR szCaption[MAX_PATH];
|
||
|
|
||
|
if (LoadString(hHotPlug, IdText, szText, MAX_PATH) &&
|
||
|
LoadString(hHotPlug, IdCaption, szCaption, MAX_PATH))
|
||
|
{
|
||
|
return MessageBox(hWnd, szText, szCaption, Type);
|
||
|
}
|
||
|
|
||
|
return IDIGNORE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
InvalidateTreeItemRect(
|
||
|
HWND hwndTree,
|
||
|
HTREEITEM hTreeItem
|
||
|
)
|
||
|
{
|
||
|
RECT rect;
|
||
|
|
||
|
if (hTreeItem && TreeView_GetItemRect(hwndTree, hTreeItem, &rect, FALSE)) {
|
||
|
|
||
|
InvalidateRect(hwndTree, &rect, FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
GetHotPlugFlags(
|
||
|
PHKEY phKey
|
||
|
)
|
||
|
{
|
||
|
HKEY hKey;
|
||
|
LONG Error;
|
||
|
DWORD HotPlugFlags, cbHotPlugFlags;
|
||
|
|
||
|
Error = RegCreateKey(HKEY_CURRENT_USER, REGSTR_PATH_SYSTRAY, &hKey);
|
||
|
if (Error == ERROR_SUCCESS) {
|
||
|
|
||
|
cbHotPlugFlags = sizeof(HotPlugFlags);
|
||
|
|
||
|
Error = RegQueryValueEx(hKey,
|
||
|
szHotPlugFlags,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
(LPBYTE)&HotPlugFlags,
|
||
|
&cbHotPlugFlags
|
||
|
);
|
||
|
|
||
|
if (phKey) {
|
||
|
|
||
|
*phKey = hKey;
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
|
||
|
RegCloseKey(hKey);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Error != ERROR_SUCCESS) {
|
||
|
|
||
|
HotPlugFlags = 0;
|
||
|
}
|
||
|
|
||
|
return HotPlugFlags;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This function determines if the device is a boot storage device.
|
||
|
// We spit out a warning when users are trying to remove or disable
|
||
|
// a boot storage device(or a device contains a boot storage device).
|
||
|
//
|
||
|
// INPUT:
|
||
|
// NONE
|
||
|
// OUTPUT:
|
||
|
// TRUE if the device is a boot device
|
||
|
// FALSE if the device is not a boot device
|
||
|
LPTSTR
|
||
|
DevNodeToDriveLetter(
|
||
|
DEVINST DevInst
|
||
|
)
|
||
|
{
|
||
|
ULONG ulSize;
|
||
|
TCHAR szBuffer[MAX_PATH];
|
||
|
TCHAR DeviceID[MAX_DEVICE_ID_LEN];
|
||
|
PTSTR DriveString = NULL;
|
||
|
PTSTR DeviceInterface = NULL;
|
||
|
|
||
|
if (CM_Get_Device_ID_Ex(DevInst,
|
||
|
DeviceID,
|
||
|
sizeof(DeviceID)/sizeof(TCHAR),
|
||
|
0,
|
||
|
NULL
|
||
|
) != CR_SUCCESS) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// create a device info list contains all the interface classed
|
||
|
// exposed by this device.
|
||
|
ulSize = 0;
|
||
|
|
||
|
if ((CM_Get_Device_Interface_List_Size(&ulSize,
|
||
|
(LPGUID)&VolumeClassGuid,
|
||
|
DeviceID,
|
||
|
0) == CR_SUCCESS) &&
|
||
|
(ulSize > 1) &&
|
||
|
((DeviceInterface = (PTSTR)LocalAlloc(LPTR, ulSize*sizeof(TCHAR))) != NULL) &&
|
||
|
(CM_Get_Device_Interface_List((LPGUID)&VolumeClassGuid,
|
||
|
DeviceID,
|
||
|
DeviceInterface,
|
||
|
ulSize,
|
||
|
0
|
||
|
) == CR_SUCCESS) &&
|
||
|
*DeviceInterface)
|
||
|
{
|
||
|
PTSTR devicePath, p;
|
||
|
TCHAR thisVolumeName[MAX_PATH];
|
||
|
TCHAR enumVolumeName[MAX_PATH];
|
||
|
TCHAR driveName[4];
|
||
|
ULONG length;
|
||
|
BOOL bResult;
|
||
|
|
||
|
length = lstrlen(DeviceInterface);
|
||
|
devicePath = (PTSTR)LocalAlloc(LPTR, (length + 1) * sizeof(TCHAR) + sizeof(UNICODE_NULL));
|
||
|
|
||
|
if (devicePath) {
|
||
|
|
||
|
lstrcpyn(devicePath, DeviceInterface, length + 1);
|
||
|
|
||
|
p = wcschr(&(devicePath[4]), TEXT('\\'));
|
||
|
|
||
|
if (!p) {
|
||
|
//
|
||
|
// No refstring is present in the symbolic link; add a trailing
|
||
|
// '\' char (as required by GetVolumeNameForVolumeMountPoint).
|
||
|
//
|
||
|
p = devicePath + length;
|
||
|
*p = TEXT('\\');
|
||
|
}
|
||
|
|
||
|
p++;
|
||
|
*p = UNICODE_NULL;
|
||
|
|
||
|
thisVolumeName[0] = UNICODE_NULL;
|
||
|
bResult = GetVolumeNameForVolumeMountPoint(devicePath,
|
||
|
thisVolumeName,
|
||
|
MAX_PATH
|
||
|
);
|
||
|
LocalFree(devicePath);
|
||
|
|
||
|
if (bResult && thisVolumeName[0]) {
|
||
|
|
||
|
driveName[1] = TEXT(':');
|
||
|
driveName[2] = TEXT('\\');
|
||
|
driveName[3] = TEXT('\0');
|
||
|
|
||
|
for (driveName[0] = TEXT('A'); driveName[0] <= TEXT('Z'); driveName[0]++) {
|
||
|
|
||
|
enumVolumeName[0] = TEXT('\0');
|
||
|
|
||
|
GetVolumeNameForVolumeMountPoint(driveName, enumVolumeName, MAX_PATH);
|
||
|
|
||
|
if (!lstrcmpi(thisVolumeName, enumVolumeName)) {
|
||
|
|
||
|
driveName[2] = TEXT('\0');
|
||
|
|
||
|
wsprintf(szBuffer, TEXT(" - (%s)"), driveName);
|
||
|
|
||
|
DriveString = (PTSTR)LocalAlloc(LPTR, (lstrlen(szBuffer) + 1) * sizeof(TCHAR));
|
||
|
|
||
|
if (DriveString) {
|
||
|
|
||
|
lstrcpy(DriveString, szBuffer);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (DeviceInterface) {
|
||
|
|
||
|
LocalFree(DeviceInterface);
|
||
|
}
|
||
|
|
||
|
return DriveString;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
IsHotPlugDevice(
|
||
|
DEVINST DevInst,
|
||
|
HMACHINE hMachine
|
||
|
)
|
||
|
/**+
|
||
|
|
||
|
A device is considered a HotPlug device if the following are TRUE:
|
||
|
- has Capability CM_DEVCAP_REMOVABLE
|
||
|
- does NOT have Capability CM_DEVCAP_SURPRISEREMOVALOK
|
||
|
- does NOT have Capability CM_DEVCAP_DOCKDEVICE
|
||
|
- must be started (have the DN_STARTED devnode flag)
|
||
|
- unless has capability CM_DEVCAP_EJECTSUPPORTED
|
||
|
- or unless has capability CM_DEVCAP_RAWDEVICEOK
|
||
|
|
||
|
Returns:
|
||
|
TRUE if this is a HotPlug device
|
||
|
FALSE if this is not a HotPlug device.
|
||
|
|
||
|
-**/
|
||
|
{
|
||
|
DWORD Capabilities;
|
||
|
DWORD Len;
|
||
|
DWORD Status, Problem;
|
||
|
|
||
|
Capabilities = Status = Problem = 0;
|
||
|
|
||
|
Len = sizeof(Capabilities);
|
||
|
|
||
|
if (CM_Get_DevNode_Registry_Property_Ex(DevInst,
|
||
|
CM_DRP_CAPABILITIES,
|
||
|
NULL,
|
||
|
(PVOID)&Capabilities,
|
||
|
&Len,
|
||
|
0,
|
||
|
hMachine) != CR_SUCCESS) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (CM_Get_DevNode_Status_Ex(&Status,
|
||
|
&Problem,
|
||
|
DevInst,
|
||
|
0,
|
||
|
hMachine) != CR_SUCCESS) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If this device is not removable, or it is surprise removal ok, or
|
||
|
// it is a dock device, then it is not a hotplug device.
|
||
|
//
|
||
|
if ((!(Capabilities & CM_DEVCAP_REMOVABLE)) ||
|
||
|
(Capabilities & CM_DEVCAP_SURPRISEREMOVALOK) ||
|
||
|
(Capabilities & CM_DEVCAP_DOCKDEVICE)) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We won't consider a device to be a hotplug device if it is not started,
|
||
|
// unless it is either RAW capabile or an eject capable device.
|
||
|
//
|
||
|
// The reason for this test is that a bus driver might set the
|
||
|
// CM_DEVCAP_REMOVABLE capability, but if the PDO doesn't get loaded then
|
||
|
// it can't set the CM_DEVCAP_SURPRISEREMOVALOK. So we won't trust the
|
||
|
// CM_DEVCAP_REMOVABLE capability if the PDO is not started.
|
||
|
//
|
||
|
if ((!(Capabilities & CM_DEVCAP_EJECTSUPPORTED)) &&
|
||
|
(!(Status & DN_STARTED))) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
OpenPipeAndEventHandles(
|
||
|
IN LPWSTR szCmd,
|
||
|
OUT LPHANDLE lphHotPlugPipe,
|
||
|
OUT LPHANDLE lphHotPlugEvent
|
||
|
)
|
||
|
{
|
||
|
BOOL status = FALSE;
|
||
|
HANDLE hPipe = INVALID_HANDLE_VALUE;
|
||
|
HANDLE hEvent = NULL;
|
||
|
ULONG ulEventNameSize;
|
||
|
WCHAR szEventName[MAX_PATH];
|
||
|
DWORD dwBytesRead;
|
||
|
|
||
|
|
||
|
__try {
|
||
|
//
|
||
|
// Validate supplied arguments.
|
||
|
//
|
||
|
if (!lphHotPlugPipe || !lphHotPlugEvent) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure that a named pipe was specified in the cmd line.
|
||
|
//
|
||
|
if(!szCmd || !*szCmd) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Wait for the specified named pipe to become available from the server.
|
||
|
//
|
||
|
if (!WaitNamedPipe(szCmd,
|
||
|
180000) // BUGBUG-2000/07/10-jamesca: How long should we wait?
|
||
|
) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Open a handle to the specified named pipe
|
||
|
//
|
||
|
hPipe = CreateFile(szCmd,
|
||
|
GENERIC_READ,
|
||
|
0,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
0,
|
||
|
NULL);
|
||
|
if (hPipe == INVALID_HANDLE_VALUE) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The very first thing in the pipe should be the size of the event name.
|
||
|
//
|
||
|
if (ReadFile(hPipe,
|
||
|
(LPVOID)&ulEventNameSize,
|
||
|
sizeof(ULONG),
|
||
|
&dwBytesRead,
|
||
|
NULL)) {
|
||
|
|
||
|
ASSERT(ulEventNameSize != 0);
|
||
|
if ((ulEventNameSize == 0) ||
|
||
|
(ulEventNameSize > MAX_PATH)) {
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The next thing in the pipe should be the name of the event.
|
||
|
//
|
||
|
if (!ReadFile(hPipe,
|
||
|
(LPVOID)&szEventName,
|
||
|
ulEventNameSize,
|
||
|
&dwBytesRead,
|
||
|
NULL)) {
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
if (GetLastError() == ERROR_INVALID_HANDLE) {
|
||
|
//
|
||
|
// The handle to the named pipe is not valid. Make sure we don't
|
||
|
// try to close it on exit.
|
||
|
//
|
||
|
hPipe = INVALID_HANDLE_VALUE;
|
||
|
}
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Open a handle to the specified named event that we can set and wait on.
|
||
|
//
|
||
|
hEvent = OpenEventW(EVENT_MODIFY_STATE | SYNCHRONIZE,
|
||
|
FALSE,
|
||
|
szEventName);
|
||
|
if (hEvent == NULL) {
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We should now have valid handles to both the pipe and the event.
|
||
|
//
|
||
|
status = TRUE;
|
||
|
ASSERT((hPipe != INVALID_HANDLE_VALUE) && hEvent);
|
||
|
|
||
|
|
||
|
clean0:
|
||
|
;
|
||
|
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
|
||
|
status = FALSE;
|
||
|
}
|
||
|
|
||
|
if (status) {
|
||
|
|
||
|
*lphHotPlugPipe = hPipe;
|
||
|
*lphHotPlugEvent = hEvent;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if (hPipe != INVALID_HANDLE_VALUE) {
|
||
|
CloseHandle(hPipe);
|
||
|
}
|
||
|
if (hEvent) {
|
||
|
CloseHandle(hEvent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|