422 lines
8.3 KiB
C++
422 lines
8.3 KiB
C++
|
/*++
|
||
|
|
||
|
STRINGS.CXX
|
||
|
|
||
|
Copyright (C) 1999 Microsoft Corporation, all rights reserved.
|
||
|
|
||
|
DESCRIPTION: MultiString class
|
||
|
|
||
|
Created, Dec 29, 1999 by DavidCHR.
|
||
|
|
||
|
CONTENTS: CMULTISTRING
|
||
|
WriteToRegistry
|
||
|
ReadFromRegistry
|
||
|
RemoveString
|
||
|
AddString
|
||
|
~CMULTISTRING
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "everything.hxx"
|
||
|
|
||
|
/*++**************************************************************
|
||
|
NAME: CMULTISTRING
|
||
|
|
||
|
constructor for the class.
|
||
|
|
||
|
**************************************************************--*/
|
||
|
|
||
|
CMULTISTRING::
|
||
|
CMULTISTRING( VOID ) {
|
||
|
|
||
|
this->cEntries = 0;
|
||
|
this->pEntries = NULL;
|
||
|
this->TotalStringCount = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
/*++**************************************************************
|
||
|
NAME: ~CMULTISTRING
|
||
|
|
||
|
destructor for the class. Frees any strings still around.
|
||
|
|
||
|
**************************************************************--*/
|
||
|
|
||
|
CMULTISTRING::
|
||
|
~CMULTISTRING( VOID ) {
|
||
|
|
||
|
ULONG i;
|
||
|
|
||
|
if ( this->cEntries &&
|
||
|
this->pEntries ) {
|
||
|
|
||
|
for ( i = 0 ;
|
||
|
i < this->cEntries ;
|
||
|
i ++ ) {
|
||
|
|
||
|
if ( this->pEntries[ i ] ) {
|
||
|
free( this->pEntries[ i ] );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
free( this->pEntries );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++**************************************************************
|
||
|
NAME: AddString
|
||
|
|
||
|
adds a string to the end of string table
|
||
|
|
||
|
MODIFIES: this->pEntries, this->cEntries
|
||
|
|
||
|
TAKES: String -- string to add (duplicated)
|
||
|
|
||
|
RETURNS: TRUE when the function succeeds.
|
||
|
FALSE otherwise.
|
||
|
|
||
|
LOGGING: printf on failure
|
||
|
CREATED: Dec 29, 1999
|
||
|
LOCKING: none
|
||
|
CALLED BY: anyone
|
||
|
FREE WITH: ~CMULTISTRING
|
||
|
|
||
|
**************************************************************--*/
|
||
|
|
||
|
BOOL CMULTISTRING::
|
||
|
AddString( IN LPWSTR String ) {
|
||
|
|
||
|
LPWSTR *tempString;
|
||
|
|
||
|
tempString = (LPWSTR *) realloc( this->pEntries,
|
||
|
( this->cEntries + 1 ) *
|
||
|
sizeof( LPWSTR ) );
|
||
|
|
||
|
if ( tempString ) {
|
||
|
|
||
|
this->pEntries = tempString;
|
||
|
tempString[ this->cEntries ] = _wcsdup( String );
|
||
|
|
||
|
if ( tempString[ this->cEntries ] ) {
|
||
|
|
||
|
this->cEntries ++;
|
||
|
this->TotalStringCount += wcslen( String );
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
printf( "Cannot add string %ld (%ws). Not enough memory.\n",
|
||
|
this->cEntries,
|
||
|
String );
|
||
|
|
||
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
|
||
|
}
|
||
|
|
||
|
// don't free the string.
|
||
|
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
|
||
|
}
|
||
|
|
||
|
/*++**************************************************************
|
||
|
NAME: RemoveString
|
||
|
|
||
|
removes a string from the list
|
||
|
|
||
|
MODIFIES: this->pEntries, this->cEntries
|
||
|
|
||
|
TAKES: String -- string to remove (case-insensitive)
|
||
|
|
||
|
RETURNS: TRUE when the function succeeds.
|
||
|
FALSE otherwise.
|
||
|
LOGGING: printf if the string doesn't exist
|
||
|
CREATED: Dec 29, 1999
|
||
|
LOCKING: none
|
||
|
CALLED BY: anyone
|
||
|
FREE WITH: n/a -- no resources are allocated
|
||
|
|
||
|
**************************************************************--*/
|
||
|
|
||
|
|
||
|
BOOL CMULTISTRING::
|
||
|
RemoveString( IN LPWSTR String ) {
|
||
|
|
||
|
ULONG i, DeleteCount = 0;
|
||
|
BOOL ret = TRUE;
|
||
|
|
||
|
// first, go through and free the matches
|
||
|
|
||
|
for ( i = 0 ;
|
||
|
i < this->cEntries ;
|
||
|
i ++ ) {
|
||
|
|
||
|
if ( _wcsicmp( String,
|
||
|
this->pEntries[ i ] ) == 0 ) {
|
||
|
|
||
|
// match. Free it.
|
||
|
|
||
|
free( this->pEntries[ i ] );
|
||
|
this->pEntries[ i ] = NULL;
|
||
|
DeleteCount++;
|
||
|
|
||
|
} else if ( DeleteCount > 0 ) {
|
||
|
|
||
|
/* If we've deleted stuff already, and we're not deleting
|
||
|
this one, then move this entry earlier in the array. */
|
||
|
|
||
|
this->pEntries[ i - DeleteCount ] = this->pEntries[ i ];
|
||
|
|
||
|
#if DBG
|
||
|
|
||
|
/* For the sake of debugging, set this to a known
|
||
|
bad value. */
|
||
|
#ifdef _WIN64 // to avoid ia64 compile-time error, give it a qword for a pointer
|
||
|
this->pEntries[ i ] = (LPWSTR) 0xdeadbeefdeadbeef;
|
||
|
#else
|
||
|
this->pEntries[ i ] = (LPWSTR) ULongToPtr( 0xdeadbeef );
|
||
|
#endif // _WIN64
|
||
|
|
||
|
#endif // DBG
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( DeleteCount ) {
|
||
|
|
||
|
this->cEntries -= DeleteCount;
|
||
|
this->TotalStringCount -= DeleteCount * wcslen( String );
|
||
|
|
||
|
/* We could realloc the array down to the correct cEntries now,
|
||
|
but there's no pressing need. */
|
||
|
|
||
|
} else {
|
||
|
|
||
|
printf( "No match for %ws.\n",
|
||
|
String );
|
||
|
|
||
|
ret = FALSE;
|
||
|
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++**************************************************************
|
||
|
NAME: ReadFromRegistry
|
||
|
|
||
|
reads a string vector from a REG_MULTI_SZ in the registry
|
||
|
|
||
|
MODIFIES: this, indirectly
|
||
|
|
||
|
TAKES: hKey -- handle to open parent key
|
||
|
ValueName -- value to read
|
||
|
|
||
|
RETURNS: TRUE when the function succeeds.
|
||
|
FALSE otherwise.
|
||
|
LOGGING: printf on failure
|
||
|
CREATED: Dec 29, 1999
|
||
|
LOCKING: none
|
||
|
CALLED BY: anyone
|
||
|
FREE WITH: n/a -- no resources are allocated
|
||
|
|
||
|
**************************************************************--*/
|
||
|
|
||
|
|
||
|
BOOL CMULTISTRING::
|
||
|
ReadFromRegistry( IN HKEY hKey,
|
||
|
IN LPWSTR ValueName ) {
|
||
|
|
||
|
ULONG RegistrySize = 0;
|
||
|
ULONG cEntries = 0;
|
||
|
LPWSTR RegistryStrings;
|
||
|
LPWSTR *StringTable = NULL;
|
||
|
LPWSTR *pTempTable, Cursor;
|
||
|
DWORD WinError;
|
||
|
DWORD Type;
|
||
|
BOOL ret = FALSE;
|
||
|
|
||
|
WinError = RegQueryValueEx( hKey,
|
||
|
ValueName,
|
||
|
NULL,
|
||
|
&Type,
|
||
|
NULL,
|
||
|
&RegistrySize );
|
||
|
|
||
|
if (WinError == ERROR_SUCCESS) {
|
||
|
|
||
|
RegistryStrings = (LPWSTR) malloc( RegistrySize );
|
||
|
|
||
|
if ( RegistryStrings ) {
|
||
|
|
||
|
WinError = RegQueryValueEx( hKey,
|
||
|
ValueName,
|
||
|
NULL,
|
||
|
&Type,
|
||
|
(PUCHAR) RegistryStrings,
|
||
|
&RegistrySize );
|
||
|
|
||
|
if (WinError == ERROR_SUCCESS) {
|
||
|
|
||
|
ret = TRUE;
|
||
|
|
||
|
if ( RegistrySize > 2 * sizeof( WCHAR ) ) { /* 2 == two nulls
|
||
|
which would indicate
|
||
|
that the value is
|
||
|
empty. */
|
||
|
|
||
|
/* Now, allocate a string vector, counting the strings
|
||
|
as we go. */
|
||
|
|
||
|
for ( Cursor = RegistryStrings ;
|
||
|
*Cursor != L'\0' ;
|
||
|
Cursor = wcschr( Cursor, '\0' ) +1 ) {
|
||
|
|
||
|
if ( !this->AddString( Cursor ) ) {
|
||
|
|
||
|
ret = FALSE;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} // else the value was empty -- nothing to do.
|
||
|
|
||
|
} else {
|
||
|
|
||
|
printf("Failed to query value %ws: 0x%x\n",
|
||
|
ValueName,
|
||
|
WinError );
|
||
|
}
|
||
|
|
||
|
free( RegistryStrings );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
printf( "Failed to allocate %hs buffer (0x%x)\n",
|
||
|
ValueName,
|
||
|
RegistrySize );
|
||
|
|
||
|
}
|
||
|
} else if ( WinError == ERROR_FILE_NOT_FOUND ) {
|
||
|
|
||
|
/* The key doesn't exist-- no mappings. */
|
||
|
|
||
|
// WinError = ERROR_SUCCESS;
|
||
|
ret = TRUE;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
/* an actual error. */
|
||
|
|
||
|
printf( "Failed to query %ws: 0x%x\n",
|
||
|
ValueName,
|
||
|
WinError );
|
||
|
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*++**************************************************************
|
||
|
NAME: WriteToRegistry
|
||
|
|
||
|
dumps the string vector to a REG_MULTI_SZ in the registry
|
||
|
|
||
|
MODIFIES: the registry only
|
||
|
|
||
|
TAKES: hKey -- handle to open parent key
|
||
|
ValueName -- value to write
|
||
|
|
||
|
RETURNS: TRUE when the function succeeds.
|
||
|
FALSE otherwise.
|
||
|
LOGGING: printf on failure
|
||
|
CREATED: Dec 29, 1999
|
||
|
LOCKING: none
|
||
|
CALLED BY: anyone
|
||
|
FREE WITH: n/a -- no resources are allocated
|
||
|
|
||
|
**************************************************************--*/
|
||
|
|
||
|
|
||
|
BOOL CMULTISTRING::
|
||
|
WriteToRegistry( IN HKEY hKey,
|
||
|
IN LPWSTR ValueName ) {
|
||
|
|
||
|
LPWSTR StringVector;
|
||
|
ULONG StringIndex, EntryIndex, Length, VectorLength;
|
||
|
DWORD dwErr;
|
||
|
BOOL ret = FALSE;
|
||
|
|
||
|
VectorLength = ( this->TotalStringCount + // string characters
|
||
|
this->cEntries + // null characters
|
||
|
2 // trailing nulls
|
||
|
) * sizeof( WCHAR );
|
||
|
|
||
|
|
||
|
StringVector = (LPWSTR) malloc( VectorLength );
|
||
|
|
||
|
if ( !StringVector ) {
|
||
|
|
||
|
printf( "Failed to allocate string blob to write %ws.\n",
|
||
|
ValueName );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
for ( StringIndex = EntryIndex = 0 ;
|
||
|
EntryIndex < this->cEntries ;
|
||
|
EntryIndex++ ) {
|
||
|
|
||
|
Length = wcslen( this->pEntries[ EntryIndex ] ) +1; /* include the
|
||
|
null */
|
||
|
|
||
|
memcpy( StringVector + StringIndex, // to
|
||
|
this->pEntries[ EntryIndex ], // from
|
||
|
Length * sizeof( WCHAR ) ); // byte count
|
||
|
|
||
|
StringIndex += Length;
|
||
|
|
||
|
}
|
||
|
|
||
|
StringVector[ StringIndex ] = L'\0';
|
||
|
StringVector[ StringIndex+1 ] = L'\0';
|
||
|
|
||
|
dwErr = RegSetValueExW( hKey,
|
||
|
ValueName,
|
||
|
0, // mbz
|
||
|
REG_MULTI_SZ,
|
||
|
(PBYTE) StringVector,
|
||
|
VectorLength );
|
||
|
|
||
|
free( StringVector );
|
||
|
|
||
|
if ( dwErr != ERROR_SUCCESS ) {
|
||
|
|
||
|
printf( "Failed to write %ws value to registry: 0x%x.\n",
|
||
|
ValueName,
|
||
|
dwErr );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
ret = TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
|
||
|
}
|