|
|
//+-------------------------------------------------------------------------
//
// 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; }
|