|
|
/*++
Copyright (C) Microsoft Corporation, 1998 - 1999
Module Name:
RedBook.c
Abstract:
This command line utility adds and removes redbook for a given drive.
Author:
Henry Gabryjelski (henrygab)
Environment:
user mode only
Notes:
Revision History:
07-30-98 : Created
--*/
#include <propp.h>
#include <initguid.h>
#include <ntddredb.h>
#define _NTSCSI_USER_MODE_ // prevents all the kernel-mode stuff
#include <scsi.h>
#include "setupapi.h"
#include "resource.h" // strings
#include "storprop.h" // exported function definitions
//
// redefine these to do what i want them to.
// allows the appearance of structured c++ with
// the performance of c.
//
#ifdef TRY
#undef TRY
#endif
#ifdef LEAVE
#undef LEAVE
#endif
#ifdef FINALLY
#undef FINALLY
#endif
#define TRY
#define LEAVE goto __label;
#define FINALLY __label:
//
// just to give out unique errors
//
#define ERROR_REDBOOK_FILTER 0x80ff00f0L
#define ERROR_REDBOOK_PASS_THROUGH 0x80ff00f1L
//
// we initiate a pass-through request for capabilities
// to determine if the drive can support dae
//
#define SPT_MAX_DATA_SIZE 512
typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS {
SCSI_PASS_THROUGH PassThrough; ULONG_PTR Reserved; // realign buffers
UCHAR SenseBuffer[32]; UCHAR DataBuffer[SPT_MAX_DATA_SIZE];
} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
//
// easier to understand than != NULL
//
#ifndef ARGUMENT_PRESENT
#define ARGUMENT_PRESENT(ArgumentPointer) (\
(CHAR *)(ArgumentPointer) != (CHAR *)(NULL) ) #endif // ARGUMENT_PRESENT
#if DBG
#ifdef UNICODE
#define DbgPrintAllMultiSz DbgPrintAllMultiSzW
#else
#define DbgPrintAllMultiSz DbgPrintAllMultiSzA
#endif // UNICODE
VOID DbgPrintAllMultiSzW(WCHAR *String) { ULONG i = 0; while(*String != UNICODE_NULL) { DebugPrint((1, "StorProp => MultiSz %3d: %ws\n", i++, String)); while (*String != UNICODE_NULL) { *String++; } *String++; // go past the first NULL
} } VOID DbgPrintAllMultiSzA(CHAR *String) { ULONG i = 0; while(*String != ANSI_NULL) { DebugPrint((1, "StorProp => MultiSz %3d: %ws\n", i++, String)); while (*String != ANSI_NULL) { *String++; } *String++; // go past the first NULL
} }
#else // !DBG
#define DbgPrintAllMultiSz
#define DbgPrintAllMultiSz
#endif // DBG
////////////////////////////////////////////////////////////////////////////////
// Local prototypes, not exported anywhere
BOOL IsUserAdmin();
LONG RedbookpUpperFilterRegDelete( DEVINST DevInst ); LONG RedbookpUpperFilterRegInstall( DEVINST DevInst ); BOOLEAN UtilpIsSingleSzOfMultiSzInMultiSz( IN LPTSTR FindOneOfThese, IN LPTSTR WithinThese ); DWORD UtilpMultiSzSearchAndDeleteCaseInsensitive( LPTSTR FindThis, LPTSTR FindWithin, DWORD *NewStringLength );
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// the actual callbacks should do very little, codewise
//
////////////////////////////////////////////////////////////////////////////////
DWORD CdromCddaInfo( IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData, OUT PREDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO CddaInfo, IN OUT PULONG BufferSize ) /*++
Routine Description:
Returns whether the drive is a 'known good' drive. Returns whether the drive supports CDDA at all. Returns whether the drive supports accurate CDDA for only some read sizes. ...
Arguments:
CDDAInfo must point to a pre-allocated buffer for this info BufferSize will give size of this buffer, to allow for more fields to be added later in a safe manner.
Return Value:
will return ERROR_SUCCESS/STATUS_SUCCESS (both zero)
Notes:
If cannot open these registry keys, will default to FALSE, since the caller will most likely not have the ability to enable redbook anyways.
--*/ { HKEY enumHandle = INVALID_HANDLE_VALUE; HKEY subkeyHandle = INVALID_HANDLE_VALUE; REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO info; ULONG i; DWORD dataType; DWORD dataSize; LONG error;
error = ERROR_SUCCESS;
if ((*BufferSize == 0) || (CddaInfo == NULL)) {
*BufferSize = sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO); return ERROR_INSUFFICIENT_BUFFER;
}
RtlZeroMemory(CddaInfo, *BufferSize); RtlZeroMemory(&info, sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO));
info.Version = REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO_VERSION;
TRY {
enumHandle = SetupDiOpenDevRegKey(HDevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (enumHandle == INVALID_HANDLE_VALUE) { DebugPrint((1, "StorProp.CddaInfo => unable to open dev key\n")); error = ERROR_OUT_OF_PAPER; LEAVE; }
error = RegOpenKey(enumHandle, TEXT("DigitalAudio"), &subkeyHandle); if (error != ERROR_SUCCESS) { DebugPrint((1, "StorProp.CddaInfo => unable to open subkey\n")); LEAVE; }
for (i=0; i<3; i++) {
PBYTE buffer; TCHAR * keyName;
if (i == 0) { keyName = TEXT("CDDAAccurate"); buffer = (PBYTE)(&info.Accurate); } else if (i == 1) { keyName = TEXT("CDDASupported"); buffer = (PBYTE)(&info.Supported); } else if (i == 2) { keyName = TEXT("ReadSizesSupported"); buffer = (PBYTE)(&info.AccurateMask0);
#if DBG
} else { DebugPrint((0, "StorProp.CddaInfo => Looping w/o handling\n")); DebugBreak(); #endif
}
dataSize = sizeof(DWORD); error = RegQueryValueEx(subkeyHandle, keyName, NULL, &dataType, buffer, &dataSize);
if (error != ERROR_SUCCESS) { DebugPrint((1, "StorProp.CddaInfo => unable to query %ws %x\n", keyName, error)); LEAVE; } if (dataType != REG_DWORD) { DebugPrint((1, "StorProp.CddaInfo => %ws wrong data type (%x)\n", keyName, dataType)); error = ERROR_INVALID_DATA; LEAVE; }
DebugPrint((1, "StorProp.CddaInfo => %ws == %x\n", keyName, *buffer));
}
} FINALLY {
if (subkeyHandle != INVALID_HANDLE_VALUE) { RegCloseKey(subkeyHandle); } if (enumHandle != INVALID_HANDLE_VALUE) { RegCloseKey(enumHandle); }
if (error == ERROR_SUCCESS) {
//
// everything succeeded -- copy only the amount they requested
// and don't care about it being aligned on any particular buffer size.
// this is the only other place the user buffer should be modified
//
if (*BufferSize > sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO)) { *BufferSize = sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO); }
DebugPrint((2, "StorProp.CddaInfo => everything worked\n")); RtlCopyMemory(CddaInfo, &info, *BufferSize);
} else {
DebugPrint((2, "StorProp.CddaInfo => something failed\n")); *BufferSize = 0;
}
}
return error; }
BOOL CdromKnownGoodDigitalPlayback( IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData ) /*++
Routine Description:
Returns whether this drive is a 'known good' drive.
Arguments:
Return Value:
Notes:
default to FALSE, since if fails, caller probably does not have ability to enable redbook anyways. this routine is outdated -- callers should call CdromCddaInfo() directly for more exact information.
--*/ { REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO CddaInfo; ULONG bufferSize; DWORD error;
bufferSize = sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO);
#if DBG
DbgPrint("\n\nOutdated call to CdromKnownGoodDigitalPlayback(), " "should be calling CdromCddaInfo()\n\n"); #endif // DBG
error = CdromCddaInfo(HDevInfo, DevInfoData, &CddaInfo, &bufferSize);
if (error != ERROR_SUCCESS) { return FALSE; }
if (bufferSize <= sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO)) { return FALSE; }
if (CddaInfo.Accurate) { return TRUE; }
if (CddaInfo.Supported && CddaInfo.AccurateMask0) { return TRUE; }
return FALSE;
}
LONG CdromEnableDigitalPlayback( IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData, IN BOOLEAN ForceUnknown ) /*++
Routine Description:
Enables redbook 1) add redbook to filter list (if not there) 2) if not on stack (via test of guid) re-start stack 3) if still not on stack, error 4) set wmi guid item enabled
Arguments:
DevInfo - the device to enable it on DevInfoData - ForceUnknown - will set a popup if not a known good drive and this is false
Return Value:
ERROR_XXX value
--*/ { LONG status; SP_DEVINSTALL_PARAMS devInstallParameters; REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO digitalInfo; ULONG digitalInfoSize; BOOLEAN enableIt;
//
// restrict to administrator ???
//
if (!IsUserAdmin()) { DebugPrint((1, "StorProp.Enable => you need to be administrator to " "enable redbook\n")); return ERROR_ACCESS_DENIED; }
digitalInfoSize = sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO); RtlZeroMemory(&digitalInfo, digitalInfoSize);
status = CdromCddaInfo(HDevInfo, DevInfoData, &digitalInfo, &digitalInfoSize);
if (status != ERROR_SUCCESS) {
DebugPrint((1, "StorProp.Enable => not success getting info %x\n", status));
//
// fake some info
//
digitalInfo.Version = REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO_VERSION; digitalInfo.Accurate = 0; digitalInfo.Supported = 1; digitalInfo.AccurateMask0 = -1; digitalInfoSize = sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO);
}
if (digitalInfoSize < sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO)) { DebugPrint((3, "StorProp.Enable => returned %x bytes? (not %x)\n", digitalInfoSize, sizeof(REDBOOK_DIGITAL_AUDIO_EXTRACTION_INFO) )); return ERROR_ACCESS_DENIED; }
if (!digitalInfo.Supported) { DebugPrint((1, "StorProp.Enable => This drive will never " "support redbook\n")); // return ERROR_INVALID_FUNCTION; // log an error here?
}
//
// if it's not accurate AND we don't have the compensating info AND
// they didn't force it to install, then popup a dialog.
//
if (!(digitalInfo.Accurate) && !(digitalInfo.AccurateMask0) && !(ForceUnknown) ) {
BOOLEAN okToProceed = FALSE; TCHAR buffer[MAX_PATH+1]; TCHAR bufferTitle[MAX_PATH+1];
buffer[0] = '\0'; bufferTitle[0] = '\0'; buffer[MAX_PATH] = '\0'; bufferTitle[MAX_PATH] = '\0';
//
// not forced, and not known good. pop up a box asking permission
//
LoadString(ModuleInstance, REDBOOK_UNKNOWN_DRIVE_CONFIRM, buffer, MAX_PATH); LoadString(ModuleInstance, REDBOOK_UNKNOWN_DRIVE_CONFIRM_TITLE, bufferTitle, MAX_PATH); if (MessageBox(GetDesktopWindow(), buffer, bufferTitle, MB_YESNO | // ok and cancel buttons
MB_ICONQUESTION | // question icon
MB_DEFBUTTON2 | // cancel is default
MB_SYSTEMMODAL // must respond to this box
) == IDYES) { okToProceed = TRUE; }
if (!okToProceed) { DebugPrint((3, "StorProp.Enable => User did not force installation " "on unknown drive\n")); return ERROR_REDBOOK_FILTER; } }
//
// ensure it is in the filter list
//
RedbookpUpperFilterRegInstall(DevInfoData->DevInst);
//
// restart the device to load redbook
//
if (!UtilpRestartDevice(HDevInfo, DevInfoData)) {
DebugPrint((1, "StorProp.Enable => Restart failed\n"));
} else {
DebugPrint((1, "StorProp.Enable => Restart succeeded\n"));
} return ERROR_SUCCESS;
}
LONG CdromDisableDigitalPlayback( IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData ) {
//
// restrict to administrator
//
if (!IsUserAdmin()) { DebugPrint((1, "StorProp.Disable => User is not administrator\n")); return ERROR_ACCESS_DENIED; }
//
// delete it from the filter list regardless
//
RedbookpUpperFilterRegDelete(DevInfoData->DevInst);
//
// restart the device to remove redbook from the stack
//
if (!UtilpRestartDevice(HDevInfo, DevInfoData)) {
DebugPrint((1, "StorProp.Disable => Restart failed\n"));
} else {
DebugPrint((1, "StorProp.Disable => restart succeeded\n"));
}
return ERROR_SUCCESS; }
LONG CdromIsDigitalPlaybackEnabled( IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData, OUT PBOOLEAN Enabled ) { //
// check if it's on the filters list.
//
CONFIGRET cr = CR_DEFAULT; TCHAR *buffer = NULL; DWORD size = 0;
*Enabled = FALSE;
TRY {
cr = CM_Get_DevNode_Registry_Property(DevInfoData->DevInst, CM_DRP_UPPERFILTERS, NULL, NULL, &size, 0);
if (cr == CR_NO_SUCH_VALUE) { DebugPrint((1, "StorProp.IsEnabled => no upper filters\n")); LEAVE; }
if (cr != CR_BUFFER_SMALL) { DebugPrint((1, "StorProp.IsEnabled => Other error: %x\n", cr)); LEAVE; }
buffer = LocalAlloc(LPTR, size); if (buffer == NULL) { DebugPrint((1, "StorProp.IsEnabled => Not enough mem\n")); cr = CR_OUT_OF_MEMORY; LEAVE; }
cr = CM_Get_DevNode_Registry_Property(DevInfoData->DevInst, CM_DRP_UPPERFILTERS, NULL, buffer, &size, 0);
if (cr != CR_SUCCESS) { DebugPrint((1, "StorProp.IsEnabled => Cannot get upper filter %x\n", cr)); LEAVE; }
if (UtilpIsSingleSzOfMultiSzInMultiSz(TEXT("redbook\0"), buffer)) { DebugPrint((1, "StorProp.IsEnabled => redbook enabled\n"));
//
// further verification needed? maybe a wmi query?
//
*Enabled = TRUE; cr = CR_SUCCESS;
} else { DebugPrint((1, "StorProp.IsEnabled => redbook NOT enabled\n")); }
} FINALLY {
if (buffer != NULL) { LocalFree(buffer); } }
if (cr == CR_SUCCESS) { DebugPrint((1, "StorProp.IsEnabled => returning %x\n", *Enabled)); return CR_SUCCESS; }
//
// if we couldn't query the filters key, try WMI...
//
{ WMIHANDLE wmiHandle = INVALID_HANDLE_VALUE; HANDLE hEnum = INVALID_HANDLE_VALUE; PREDBOOK_WMI_STD_DATA wmiData = NULL; PWNODE_SINGLE_INSTANCE wmiInstance = NULL; DWORD dataSize = 0; DWORD status = ERROR_INVALID_FUNCTION; TCHAR *instanceName;
DWORD nameChars; TCHAR buffer[2];
instanceName = NULL;
DebugPrint((1, "StorProp.IsEnabled => Using alternate method\n"));
hEnum = UtilpGetDeviceHandle(HDevInfo, DevInfoData, (LPGUID) &CdRomClassGuid, GENERIC_READ | GENERIC_WRITE);
if (hEnum == INVALID_HANDLE_VALUE) { DebugPrint((3, "StorProp.IsEnabled => Busy drive\n")); goto FinalExit; }
//
// get a handle to redbook's wmi block by passing its guid in
//
status = WmiOpenBlock((LPGUID) &MSRedbook_DriverInformationGuid, 0, &wmiHandle);
if (status != ERROR_SUCCESS) { DebugPrint((3, "StorProp.IsEnabled => WmiOpenBlock " "returned %x\n", status)); goto FinalExit; }
//
// on the first try, figure out the length of the wmi name
//
nameChars = 2; status = WmiFileHandleToInstanceName(wmiHandle, hEnum, &nameChars, buffer);
if (status != ERROR_SUCCESS && status != ERROR_INSUFFICIENT_BUFFER) { DebugPrint((3, "StorProp.IsEnabled => Can't get instance " "name %x\n", status)); status = ERROR_WMI_GUID_NOT_FOUND; goto FinalExit; }
//
// allocate just enough memory for this name
//
instanceName = (TCHAR *)LocalAlloc(LPTR, nameChars*sizeof(TCHAR));
if (instanceName == NULL) { DebugPrint((3, "StorProp.IsEnabled => insufficient memory\n")); status = ERROR_NOT_ENOUGH_MEMORY; goto FinalExit; }
//
// get the wmi instance name of the device associated with this handle
//
status = WmiFileHandleToInstanceName(wmiHandle, hEnum, &nameChars, instanceName); if (status != ERROR_SUCCESS) { DebugPrint((3, "StorProp.IsEnabled => Can't get instance " " name2 %x\n", status)); status = ERROR_WMI_GUID_NOT_FOUND; goto FinalExit; }
//
// query the data block -- returns buffer size needed in BYTES
//
status = WmiQuerySingleInstance(wmiHandle, instanceName, &dataSize, NULL);
if (dataSize == 0) { DebugPrint((3, "StorProp.IsEnabled => No data for " "redbook instance? %x\n", status)); goto FinalExit; }
wmiInstance = LocalAlloc(LPTR, dataSize); if (wmiInstance == NULL) { DebugPrint((3, "StorProp.IsEnabled !! No Memory for wmiNode\n")); status = ERROR_NOT_ENOUGH_MEMORY; goto FinalExit; }
status = WmiQuerySingleInstance(wmiHandle, instanceName, &dataSize, wmiInstance);
if (status == ERROR_SUCCESS) { DebugPrint((3, "StorProp.IsEnabled => Redbook is currently on the " "device stack\n")); *Enabled = TRUE; } else { DebugPrint((3, "StorProp.IsEnabled => Redbook query failed %x\n", status)); } goto FinalExit;
////////////////////////////////////////////////////////////////////////
// Deallocate all resources here
FinalExit: if (wmiInstance != NULL) { LocalFree(wmiInstance); } if (hEnum != INVALID_HANDLE_VALUE) { CloseHandle(hEnum); } if (wmiHandle != INVALID_HANDLE_VALUE) { WmiCloseBlock(wmiHandle); } if (instanceName != NULL) { LocalFree(instanceName); }
}
DebugPrint((1, "StorProp.IsEnabled => returning(2) %x\n", *Enabled)); return cr; }
////////////////////////////////////////////////////////////////////////////////
//
// The support routines do all the work....
//
////////////////////////////////////////////////////////////////////////////////
HANDLE UtilpGetDeviceHandle( HDEVINFO DevInfo, PSP_DEVINFO_DATA DevInfoData, LPGUID ClassGuid, DWORD DesiredAccess ) /*++
Routine Description:
gets a handle for a device
Arguments:
the name of the device to open
Return Value:
handle to the device opened, which must be later closed by the caller.
Notes:
this function is also in the class installer (syssetup.dll) so please propogate fixes there as well
--*/ { BOOL status; ULONG i; HANDLE fileHandle = INVALID_HANDLE_VALUE;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
HDEVINFO devInfoWithInterface = NULL; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; PTSTR deviceInstanceId = NULL;
ULONG deviceInterfaceDetailDataSize; ULONG deviceInstanceIdSize;
TRY {
//
// get the ID for this device
//
for (i=deviceInstanceIdSize=0; i<2; i++) {
if (deviceInstanceIdSize != 0) {
//
// deviceInstanceIdSize is returned in CHARACTERS
// by SetupDiGetDeviceInstanceId(), so must allocate
// returned size * sizeof(TCHAR)
//
deviceInstanceId = LocalAlloc(LPTR, deviceInstanceIdSize * sizeof(TCHAR));
if (deviceInstanceId == NULL) { DebugPrint((1, "StorProp.GetDeviceHandle => Unable to " "allocate for deviceInstanceId\n")); LEAVE; }
}
status = SetupDiGetDeviceInstanceId(DevInfo, DevInfoData, deviceInstanceId, deviceInstanceIdSize, &deviceInstanceIdSize ); }
if (!status) { DebugPrint((1, "StorProp.GetDeviceHandle => Unable to get " "Device IDs\n")); LEAVE; }
//
// Get all the cdroms in the system
//
devInfoWithInterface = SetupDiGetClassDevs(ClassGuid, deviceInstanceId, NULL, DIGCF_DEVICEINTERFACE );
if (devInfoWithInterface == NULL) { DebugPrint((1, "StorProp.GetDeviceHandle => Unable to get " "list of CdRom's in system\n")); LEAVE; }
memset(&deviceInterfaceData, 0, sizeof(SP_DEVICE_INTERFACE_DATA)); deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
status = SetupDiEnumDeviceInterfaces(devInfoWithInterface, NULL, ClassGuid, 0, &deviceInterfaceData );
if (!status) { DebugPrint((1, "StorProp.GetDeviceHandle => Unable to get " "SP_DEVICE_INTERFACE_DATA\n")); LEAVE; }
for (i=deviceInterfaceDetailDataSize=0; i<2; i++) {
if (deviceInterfaceDetailDataSize != 0) {
//
// deviceInterfaceDetailDataSize is returned in BYTES
// by SetupDiGetDeviceInstanceId(), so must allocate
// returned size only
//
deviceInterfaceDetailData = LocalAlloc (LPTR, deviceInterfaceDetailDataSize);
if (deviceInterfaceDetailData == NULL) { DebugPrint((1, "StorProp.GetDeviceHandle => Unable to " "allocate for deviceInterfaceDetailData\n")); LEAVE; }
deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
}
status = SetupDiGetDeviceInterfaceDetail(devInfoWithInterface, &deviceInterfaceData, deviceInterfaceDetailData, deviceInterfaceDetailDataSize, &deviceInterfaceDetailDataSize, NULL); }
if (!status) { DebugPrint((1, "StorProp.GetDeviceHandle => Unable to get " "DeviceInterfaceDetail\n")); LEAVE; }
if (deviceInterfaceDetailDataSize <= FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath)) { DebugPrint((1, "StorProp.GetDeviceHandle => No device path\n")); status = ERROR_PATH_NOT_FOUND; LEAVE; }
//
// no need to memcpy it, just use the path returned to us.
//
fileHandle = CreateFile(deviceInterfaceDetailData->DevicePath, DesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (fileHandle == INVALID_HANDLE_VALUE) { DebugPrint((1, "StorProp.GetDeviceHandle => Final CreateFile() " "failed\n")); LEAVE; }
DebugPrint((3, "StorProp.GetDeviceHandle => handle %x opened\n", fileHandle));
} FINALLY {
if (devInfoWithInterface != NULL) { SetupDiDestroyDeviceInfoList(devInfoWithInterface); }
if (deviceInterfaceDetailData != NULL) { LocalFree (deviceInterfaceDetailData); }
}
return fileHandle; }
BOOLEAN UtilpRestartDevice( IN HDEVINFO HDevInfo, IN PSP_DEVINFO_DATA DevInfoData ) /*++
Routine Description:
Arguments:
Return Value:
--*/ { SP_PROPCHANGE_PARAMS parameters; SP_DEVINSTALL_PARAMS installParameters; BOOLEAN succeeded = FALSE;
RtlZeroMemory(¶meters, sizeof(SP_PROPCHANGE_PARAMS)); RtlZeroMemory(&installParameters, sizeof(SP_DEVINSTALL_PARAMS));
//
// Initialize the SP_CLASSINSTALL_HEADER struct at the beginning of the
// SP_PROPCHANGE_PARAMS struct. this allows SetupDiSetClassInstallParams
// to work.
//
parameters.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); parameters.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
//
// Initialize SP_PROPCHANGE_PARAMS such that the device will be STOPPED
//
parameters.Scope = DICS_FLAG_CONFIGSPECIFIC; parameters.HwProfile = 0; // current profile
//
// prepare for the call to SetupDiCallClassInstaller (to stop the device)
//
parameters.StateChange = DICS_STOP;
if (!SetupDiSetClassInstallParams(HDevInfo, DevInfoData, (PSP_CLASSINSTALL_HEADER)¶meters, sizeof(SP_PROPCHANGE_PARAMS))) { DebugPrint((1, "UtilpRestartDevice => Couldn't stop the device (%x)\n", GetLastError())); goto FinishRestart; }
//
// actually stop the device
//
if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, HDevInfo, DevInfoData)) { DebugPrint((1, "UtilpRestartDevice => call to class installer " "(STOP) failed (%x)\n", GetLastError())); goto FinishRestart; }
//
// prepare for the call to SetupDiCallClassInstaller (to start the device)
//
parameters.StateChange = DICS_START;
if (!SetupDiSetClassInstallParams(HDevInfo, DevInfoData, (PSP_CLASSINSTALL_HEADER)¶meters, sizeof(SP_PROPCHANGE_PARAMS))) { DebugPrint((1, "UtilpRestartDevice => Couldn't stop the device (%x)\n", GetLastError())); goto FinishRestart; }
//
// actually start the device
//
if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, HDevInfo, DevInfoData)) { DebugPrint((1, "UtilpRestartDevice => call to class installer " "(STOP) failed (%x)\n", GetLastError())); goto FinishRestart; }
succeeded = TRUE;
FinishRestart:
//
// this call will succeed, but we should still check the status
//
if (!SetupDiGetDeviceInstallParams(HDevInfo, DevInfoData, &installParameters)) { DebugPrint((1, "UtilpRestartDevice => Couldn't get the device install " "paramters (%x)\n", GetLastError())); return FALSE; }
if (TEST_FLAG(installParameters.Flags, DI_NEEDREBOOT)) { DebugPrint((1, "UtilpRestartDevice => Device needs a reboot.\n")); return FALSE; } if (TEST_FLAG(installParameters.Flags, DI_NEEDRESTART)) { DebugPrint((1, "UtilpRestartDevice => Device needs a restart(!).\n")); return FALSE; }
if (succeeded) { DebugPrint((1, "UtilpRestartDevice => Device successfully stopped and " "restarted.\n")); return TRUE; }
SET_FLAG(installParameters.Flags, DI_NEEDRESTART);
DebugPrint((1, "UtilpRestartDevice => Device needs to be restarted.\n")); SetupDiSetDeviceInstallParams(HDevInfo, DevInfoData, &installParameters);
return FALSE;
}
LONG RedbookpUpperFilterRegDelete( DEVINST DevInst ) /*++
Routine Description: Opens the UpperFilters registry key for this device instance and deletes all instances of redbook.
Arguments: the device instance
Return Value: ERROR_SUCCESS if deleted ERROR_SUCCESS if it wasn't there in the first place
--*/ { CONFIGRET cr = CR_SUCCESS; TCHAR *buffer; DWORD size;
buffer = NULL; size = 0;
TRY {
size = 0;
//
// CM_Get_DevNode_Registry_Property() returns the number
// of actual bytes required, not number of chars
//
cr = CM_Get_DevNode_Registry_Property(DevInst, CM_DRP_UPPERFILTERS, NULL, NULL, &size, 0);
if (cr == CR_NO_SUCH_VALUE) { DebugPrint((1, "StorProp.RegDelete => Redbook not on filter list\n")); LEAVE; }
if (cr != CR_BUFFER_SMALL) { DebugPrint((1, "StorProp.RegDelete => Other error: %x\n", cr)); LEAVE; }
buffer = LocalAlloc(LPTR, size); if (buffer == NULL) { DebugPrint((1, "StorProp.RegDelete => Not enough mem\n")); LEAVE; }
cr = CM_Get_DevNode_Registry_Property(DevInst, CM_DRP_UPPERFILTERS, NULL, buffer, &size, 0);
if (cr != CR_SUCCESS) { DebugPrint((1, "StorProp.RegDelete => Cannot get upper filter %x\n", cr)); LEAVE; }
//
// DELETE: Check and see if redbook is already there
//
DebugPrint((1, "StorProp.RegDelete => Registry currently contains %x " "bytes in the multi-sz\n", size));
if (UtilpMultiSzSearchAndDeleteCaseInsensitive(TEXT("redbook"), buffer, &size)) {
DebugPrint((1,"StorProp.RegDelete => Attempting to remove redbook " "as an upper filter, %x bytes remain at %p\n", size, buffer));
if (size == 0) { cr = CM_Set_DevNode_Registry_Property(DevInst, CM_DRP_UPPERFILTERS, NULL, size, 0); } else { cr = CM_Set_DevNode_Registry_Property(DevInst, CM_DRP_UPPERFILTERS, buffer, size, 0); }
if (cr != CR_SUCCESS) { DebugPrint((1,"StorProp.RegDelete !! Could not access upper " "filters %x\n", cr)); LEAVE; }
} else {
//
// optimization -- why write an unmodified value?
//
DebugPrint((1,"StorProp.RegDelete => Redbook is not installed as " "an upper filter\n"));
}
//
// the new list is now in place
//
} FINALLY {
if (buffer != NULL) { LocalFree(buffer); buffer = NULL; }
}
return ERROR_SUCCESS;
}
LONG RedbookpUpperFilterRegInstall( DEVINST DevInst ) /*++
Routine Description: Opens the UpperFilters registry key for this device instance and adds one instance of redbook as an upper filter
Arguments: the device instance
Return Value: ERROR_SUCCESS if installed ERROR_SUCCESS if was already there
--*/ { HKEY hDeviceKey; CONFIGRET cr = CR_SUCCESS; TCHAR *buffer = NULL; TCHAR *currentLocation; DWORD length = 0; DWORD newLength = 0;
//
// Open the device key for the source device instance
// length is returned in BYTES by CM_Get_DevNode_Registry_Property()
//
cr = CM_Get_DevNode_Registry_Property(DevInst, CM_DRP_UPPERFILTERS, NULL, buffer, &length, 0);
//
// allocate only the memory required for this
//
newLength = _tcslen(TEXT("redbook")) + 1; newLength *= sizeof(TCHAR);
if (length == 0) { newLength += sizeof(TCHAR); // extra NULL to double-NULL terminate string
} else { newLength += length; }
buffer = LocalAlloc(LPTR, newLength); if (buffer == NULL) { return ERROR_REDBOOK_FILTER; }
if (cr == CR_NO_SUCH_VALUE) {
assert( length == 0 );
} else {
DWORD temp;
cr = CM_Get_DevNode_Registry_Property(DevInst, CM_DRP_UPPERFILTERS, NULL, buffer, &length, 0);
if (cr != CR_SUCCESS) {
//
// don't want to wipe existing values if this fails
//
LocalFree(buffer); return ERROR_REDBOOK_FILTER; }
//
// succeed if already is on the stack.
// length will contain the number of bytes of
// usable data at this point
//
DbgPrintAllMultiSz(buffer);
//
// if already on the stack (send Multi_Sz "redbook\0"), return
//
if (UtilpIsSingleSzOfMultiSzInMultiSz(TEXT("redbook\0"), buffer)) { LocalFree(buffer); return ERROR_SUCCESS; }
//
// get the length of the sz's already as upper filters
// this may be different than above, as above may have removed
// multiple instances of redbook from the multisz
//
temp = 0; while ( _tcscmp(buffer+temp, TEXT("")) != 0 ) {
//
// don't forget your pointer arithmetic
//
temp += (_tcslen(buffer+temp) + 1); // this string
}
//
// assert the size of the upper filters has not changed
// between the first and second query
//
if (temp * sizeof(TCHAR) != length) { DebugPrint((1, "StorProp.RegInstall !! Size of upper filters has " "changed since last query -- aborting install\n")); LocalFree(buffer); return ERROR_REDBOOK_FILTER; }
//
// move all existing text ahead by N bytes, where N is
// the sizeof the new filter to add
//
temp = _tcslen(TEXT("redbook")) + 1;
RtlMoveMemory(buffer + temp, // destination (pointer arithmetic)
buffer, // source
length); // number of bytes of old filters
}
//
// now have the old values in buffer (offset enough to insert redbook)
// newLength specifies total memory we have alloc'd
// length is size of existing registry entries retrieved OR
// sizeof(TCHAR) if none were in the original registry
//
//
// now fill that new space with the new filter addition
// this includes the NULL for the filter being added
//
_tcscpy(buffer, TEXT("redbook"));
//
// set the new multisz as the new filter
//
cr = CM_Set_DevNode_Registry_Property(DevInst, CM_DRP_UPPERFILTERS, buffer, newLength, 0);
if (cr != CR_SUCCESS) { DebugPrint((1, "StorProp.RegInstall !! Could not edit Redbook's " "filter status %x\n", cr)); LocalFree(buffer); return ERROR_REDBOOK_FILTER; } else { DebugPrint((1, "StorProp.RegInstall => Redbook now installed as " "an upper filter\n")); LocalFree(buffer); return ERROR_SUCCESS; }
}
BOOLEAN UtilpIsSingleSzOfMultiSzInMultiSz( IN LPTSTR FindOneOfThese, IN LPTSTR WithinThese ) /*++
Routine Description:
Deletes all instances of a string from within a multi-sz. automagically operates on either unicode or ansi or ??
Arguments:
FindOneOfThese - multisz to search with WithinThese - multisz to search in
Return Value:
1/20 of one cent, or the number of strings deleted, rounded down.
Notes:
expect small inputs, so n*m is acceptable run time.
--*/ { LPTSTR searchFor; LPTSTR within;
//
// loop through all strings in FindOneOfThese
//
searchFor = FindOneOfThese; while ( _tcscmp(searchFor, TEXT("\0")) ) {
//
// loop through all strings in WithinThese
//
within = WithinThese; while ( _tcscmp(within, TEXT("\0"))) {
//
// if the are equal, return TRUE
//
if ( !_tcscmp(searchFor, within) ) { return TRUE; }
within += _tcslen(within) + 1; } // end of WithinThese loop
searchFor += _tcslen(searchFor) + 1; } // end of FindOneOfThese loop
return FALSE; }
DWORD UtilpMultiSzSearchAndDeleteCaseInsensitive( LPTSTR FindThis, LPTSTR FindWithin, DWORD *NewStringLength ) /*++
Routine Description:
Deletes all instances of a string from within a multi-sz. automagically operates on either unicode or ansi or ??
Arguments:
NewStringLength is in BYTES, not number of chars
Return Value:
1/20 of one cent, or the number of strings deleted, rounded down.
--*/ { LPTSTR search; DWORD charOffset; DWORD instancesDeleted;
if ((*NewStringLength) % sizeof(TCHAR)) { assert(!"String must be in bytes, does not divide by sizeof(TCHAR)\n"); return 0; }
if ((*NewStringLength) < sizeof(TCHAR)*2) { assert(!"String must be multi-sz, which requires at least two chars\n"); return 0; }
charOffset = 0; instancesDeleted = 0; search = FindWithin;
//
// loop while there string length is not zero
// couldn't find a TNULL, or i'd just compare.
//
while (_tcsicmp(search, TEXT("\0")) != 0) {
//
// if this string matches...
//
if (_tcsicmp(search, FindThis) == 0) {
//
// the new length is smaller
// remove the string (and terminating null)
//
instancesDeleted++; *NewStringLength -= (_tcslen(search) + 1) * sizeof(TCHAR);
RtlMoveMemory(search, search + _tcslen(search) + 1, *NewStringLength - (charOffset * sizeof(TCHAR)) );
} else {
//
// move current search pointer
// increment current offset (in CHARS)
//
charOffset += _tcslen(search) + 1; search += _tcslen(search) + 1;
}
//
// it's that simple
//
}
//
// if deleted all strings, set to double-null
//
if (*NewStringLength == sizeof(TCHAR)) { FindWithin = TEXT("\0"); *NewStringLength = 0; }
return instancesDeleted;
}
|