1621 lines
42 KiB
C
1621 lines
42 KiB
C
/*++
|
||
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;
|
||
|
||
}
|
||
|