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