//-----------------------------------------------------------------------// // // File: delete.cpp // Created: April 1997 // By: Martin Holladay (a-martih) // Purpose: Registry Delete Support for REG.CPP // Modification History: // Copied from Update.cpp and modificd - April 1997 (a-martih) // April 1999 Zeyong Xu: re-design, revision -> version 2.0 // //------------------------------------------------------------------------// #include "stdafx.h" #include "reg.h" // // function prototypes // LONG DeleteValues( PTREG_PARAMS pParams ); LONG RecursiveDeleteKey( HKEY hKey, LPCWSTR pwszName, DWORD dwDepth, PTREG_PARAMS pParams ); BOOL ParseDeleteCmdLine( DWORD argc, LPCWSTR argv[], PTREG_PARAMS pParams, BOOL* pbUsage ); // // implementation // //-----------------------------------------------------------------------// // // DeleteRegistry() // //-----------------------------------------------------------------------// LONG DeleteRegistry( DWORD argc, LPCWSTR argv[] ) { // local variables LONG lResult = 0; BOOL bUsage = FALSE; BOOL bResult = TRUE; TREG_PARAMS params; LPCWSTR pwszList = NULL; LPCWSTR pwszFormat = NULL; // check the input if( argc == 0 || argv == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); ShowLastErrorEx( stderr, SLE_INTERNAL ); return 1; } // initialize the global data structure InitGlobalData( REG_DELETE, ¶ms ); // // Parse the cmd-line // bResult = ParseDeleteCmdLine( argc, argv, ¶ms, &bUsage ); if( bResult == FALSE ) { ShowLastErrorEx( stderr, SLE_INTERNAL ); FreeGlobalData( ¶ms ); return 1; } // check whether we need to display the usage if ( bUsage == TRUE ) { Usage( REG_DELETE ); FreeGlobalData( ¶ms ); return 0; } // // Connect to the Remote Machine(s) - if applicable // bResult = RegConnectMachine( ¶ms ); if( bResult == FALSE ) { SaveErrorMessage( -1 ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); } // if delete a value or delete all values under this key else if( params.pwszValueName != NULL || params.bAllValues == TRUE ) { lResult = DeleteValues( ¶ms ); } // // if delete the key else { pwszFormat = GetResString2( IDS_DELETE_PERMANENTLY, 0 ); pwszList = GetResString2( IDS_CONFIRM_CHOICE_LIST, 1 ); do { lResult = Prompt( pwszFormat, params.pwszFullKey, pwszList, params.bForce ); } while ( lResult > 2 ); if ( lResult == 1 ) { lResult = RecursiveDeleteKey( params.hRootKey, params.pwszSubKey, 0, ¶ms ); } else { SaveErrorMessage( ERROR_CANCELLED ); ShowLastErrorEx( stdout, SLE_INTERNAL ); lResult = ERROR_SUCCESS; } } // return FreeGlobalData( ¶ms ); return ((lResult == ERROR_SUCCESS) ? 0 : 1); } //------------------------------------------------------------------------// // // ParseDeleteCmdLine() // //------------------------------------------------------------------------// BOOL ParseDeleteCmdLine( DWORD argc, LPCWSTR argv[], PTREG_PARAMS pParams, BOOL* pbUsage ) { // local variables DWORD dw = 0; LONG lResult = 0; DWORD dwLength = 0; BOOL bResult = FALSE; BOOL bHasValue = FALSE; // check the input if ( argc == 0 || argv == NULL || pParams == NULL || pbUsage == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return FALSE; } // check whether this function is being called for // valid operation or not if ( pParams->lOperation < 0 || pParams->lOperation >= REG_OPTIONS_COUNT ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return FALSE; } if( argc < 3 || argc > 6 ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_DELETE ] ); return FALSE; } else if ( StringCompareEx( argv[ 1 ], L"DELETE", TRUE, 0 ) != 0 ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return FALSE; } else if ( InString( argv[ 2 ], L"-?|/?|-h|/h", TRUE ) == TRUE ) { if ( argc == 3 ) { *pbUsage = TRUE; return TRUE; } else { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_DELETE ] ); return FALSE; } } // Machine Name and Registry key // bResult = BreakDownKeyString( argv[ 2 ], pParams ); if( bResult == FALSE ) { return FALSE; } // parsing bResult = TRUE; lResult = ERROR_SUCCESS; for( dw = 3; dw < argc; dw++ ) { if( StringCompareEx( argv[ dw ], L"/v", TRUE, 0 ) == 0 ) { if( bHasValue == TRUE ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } dw++; if( dw < argc ) { dwLength = StringLength( argv[ dw ], 0 ) + 1; pParams->pwszValueName = (LPWSTR) AllocateMemory( (dwLength + 5) * sizeof( WCHAR ) ); if ( pParams->pwszValueName == NULL ) { lResult = ERROR_OUTOFMEMORY; break; } bHasValue = TRUE; StringCopy( pParams->pwszValueName, argv[ dw ], dwLength ); } else { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } } else if( StringCompareEx( argv[ dw ], L"/ve", TRUE, 0 ) == 0 ) { if( bHasValue == TRUE ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } pParams->pwszValueName = (LPWSTR) AllocateMemory( 2 * sizeof( WCHAR ) ); if ( pParams->pwszValueName == NULL ) { lResult = ERROR_OUTOFMEMORY; break; } bHasValue = TRUE; } else if( StringCompareEx( argv[ dw ], L"/va", TRUE, 0 ) == 0 ) { if( bHasValue == TRUE ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } bHasValue = TRUE; pParams->bAllValues = TRUE; } else if( StringCompareEx( argv[ dw ], L"/f", TRUE, 0 ) == 0 ) { if ( pParams->bForce == TRUE ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } pParams->bForce = TRUE; } else { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } } if( lResult != ERROR_SUCCESS ) { if( bResult == FALSE ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_DELETE ] ); } else { SaveErrorMessage( lResult ); } } return (lResult == ERROR_SUCCESS); } //-----------------------------------------------------------------------// // // RecursiveDeleteKey() - Recursive registry key delete // //-----------------------------------------------------------------------// LONG RecursiveDeleteKey( HKEY hKey, LPCWSTR pwszName, DWORD dwDepth, PTREG_PARAMS pParams ) { // local variables LONG lResult = 0; DWORD dw = 0; DWORD dwIndex = 0; DWORD dwCount = 0; HKEY hSubKey = NULL; LONG lLastResult = 0; DWORD dwNumOfSubkey = 0; DWORD dwLenOfKeyName = 0; LPWSTR pwszNameBuf = NULL; TARRAY arrValues = NULL; LPCWSTR pwszTemp = NULL; if( hKey == NULL || pwszName == NULL || pParams == NULL ) { lResult = ERROR_INVALID_PARAMETER; goto exitarea; } // // Open the SubKey // lResult = RegOpenKeyEx( hKey, pwszName, 0, KEY_ALL_ACCESS, &hSubKey ); if( lResult != ERROR_SUCCESS ) { goto exitarea; } // query key info lResult = RegQueryInfoKey( hSubKey, NULL, NULL, NULL, &dwNumOfSubkey, &dwLenOfKeyName, NULL, NULL, NULL, NULL, NULL, NULL ); if( lResult != ERROR_SUCCESS ) { SafeCloseKey( &hSubKey ); goto exitarea; } else if ( dwNumOfSubkey == 0 ) { SafeCloseKey( &hSubKey ); lResult = RegDeleteKey( hKey, pwszName ); goto exitarea; } // // SPECIAL CASE: // ------------- // For HKLM\SYSTEM\CONTROLSET002 it is found to be API returning value 0 for dwMaxLength // though there are subkeys underneath this -- to handle this, we are doing a workaround // by assuming the max registry key length // if ( dwLenOfKeyName == 0 ) { dwLenOfKeyName = 256; } else if ( dwLenOfKeyName < 256 ) { // always assume 100% more length that what is returned by the API dwLenOfKeyName *= 2; } // create the dynamic array arrValues = CreateDynamicArray(); if ( arrValues == NULL ) { SafeCloseKey( &hSubKey ); lResult = ERROR_OUTOFMEMORY; goto exitarea; } // create buffer // // bump the length to take into account the terminator. dwLenOfKeyName++; pwszNameBuf = (LPWSTR) AllocateMemory( (dwLenOfKeyName + 2) * sizeof( WCHAR ) ); if ( pwszNameBuf == NULL ) { SafeCloseKey( &hSubKey ); DestroyDynamicArray( &arrValues ); lResult = ERROR_OUTOFMEMORY; goto exitarea; } // Now Enumerate all of the keys dwIndex = 0; lResult = ERROR_SUCCESS; lLastResult = ERROR_SUCCESS; while( dwIndex < dwNumOfSubkey ) { dw = dwLenOfKeyName; SecureZeroMemory( pwszNameBuf, dw * sizeof( WCHAR ) ); lResult = RegEnumKeyEx( hSubKey, dwIndex, pwszNameBuf, &dw, NULL, NULL, NULL, NULL); // check the result if ( lResult == ERROR_SUCCESS ) { if ( DynArrayAppendString( arrValues, pwszNameBuf, 0 ) == -1 ) { lResult = lLastResult = ERROR_OUTOFMEMORY; break; } } else if ( lLastResult == ERROR_SUCCESS ) { lLastResult = lResult; } dwIndex++; } // free memory FreeMemory( &pwszNameBuf ); dwCount = DynArrayGetCount( arrValues ); if ( lResult != ERROR_OUTOFMEMORY && dwCount != 0 ) { // // start recurise delete // dw = 0; lResult = ERROR_SUCCESS; lLastResult = ERROR_SUCCESS; for( dwIndex = 0; dwIndex < dwCount; dwIndex++ ) { // get the item pwszTemp = DynArrayItemAsString( arrValues, dwIndex ); // try to delete the sub key lResult = RecursiveDeleteKey( hSubKey, pwszTemp, dwDepth + 1, pParams ); if ( lResult != ERROR_SUCCESS ) { if ( lLastResult == ERROR_SUCCESS ) { lLastResult = lResult; } } else { dw++; } } if ( dw == 0 ) { lResult = lLastResult; } else if ( dwCount != dwNumOfSubkey || dw != dwCount ) { lResult = STG_E_INCOMPLETE; } else { lResult = ERROR_SUCCESS; } } else { lResult = lLastResult; } // release the memory allocate for dynamic array DestroyDynamicArray( &arrValues ); // close this subkey and delete it SafeCloseKey( &hSubKey ); // delete the key if the result is success if ( lResult == ERROR_SUCCESS ) { lResult = RegDeleteKey( hKey, pwszName ); } exitarea: // check the result and display the error message // NOTE: error message display should be done only at the exit point if ( dwDepth == 0 ) { if ( lResult != ERROR_SUCCESS ) { if ( lResult == STG_E_INCOMPLETE ) { SetReason( ERROR_DELETEPARTIAL ); } else { SaveErrorMessage( lResult ); } // display the error ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); } else { SaveErrorMessage( ERROR_SUCCESS ); ShowLastErrorEx( stdout, SLE_INTERNAL ); } } // return return lResult; } LONG DeleteValues( PTREG_PARAMS pParams ) { // local variables DWORD dw = 0; DWORD dwCount = 0; DWORD dwIndex = 0; LONG lResult = 0; HKEY hSubKey = NULL; LONG lLastResult = 0; LPCWSTR pwszTemp = NULL; LPCWSTR pwszList = NULL; LPCWSTR pwszFormat = NULL; DWORD dwNumOfValues = 0; DWORD dwLengthOfValueName = 0; LPWSTR pwszNameBuf = NULL; TARRAY arrValues = NULL; // check the input if ( pParams == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); ShowLastErrorEx( stderr, SLE_INTERNAL ); return ERROR_INVALID_PARAMETER; } pwszList = GetResString2( IDS_CONFIRM_CHOICE_LIST, 1 ); if( pParams->bAllValues == TRUE ) { pwszTemp = pParams->pwszFullKey; pwszFormat = GetResString2( IDS_DELETEALL_CONFIRM, 0 ); } else if ( pParams->pwszValueName != NULL ) { if ( StringLength( pParams->pwszValueName, 0 ) == 0 ) { pwszTemp = GetResString2( IDS_NONAME, 0 ); } else { pwszTemp = pParams->pwszValueName; } // ... pwszFormat = GetResString2( IDS_DELETE_CONFIRM, 2 ); } else { SaveErrorMessage( ERROR_INVALID_PARAMETER ); ShowLastErrorEx( stderr, SLE_INTERNAL ); return ERROR_INVALID_PARAMETER; } do { lResult = Prompt( pwszFormat, pwszTemp, pwszList, pParams->bForce ); } while ( lResult > 2 ); if ( lResult == 2 ) { SaveErrorMessage( ERROR_CANCELLED ); ShowLastErrorEx( stdout, SLE_INTERNAL ); return ERROR_CANCELLED; } // Open the registry key lResult = RegOpenKeyEx( pParams->hRootKey, pParams->pwszSubKey, 0, KEY_ALL_ACCESS, &hSubKey ); if( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); return lResult; } // create the dynamic array arrValues = CreateDynamicArray(); if ( arrValues == NULL ) { SafeCloseKey( &hSubKey ); SaveErrorMessage( ERROR_OUTOFMEMORY ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); return ERROR_OUTOFMEMORY; } if( pParams->pwszValueName != NULL ) // delete a single value { lResult = RegDeleteValue( hSubKey, pParams->pwszValueName ); } else if( pParams->bAllValues == TRUE ) // delete all values { // query source key info lResult = RegQueryInfoKey( hSubKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwNumOfValues, &dwLengthOfValueName, NULL, NULL, NULL); if( lResult == ERROR_SUCCESS && dwNumOfValues != 0 ) { // create buffer // bump the length to take into account the terminator. dwLengthOfValueName++; pwszNameBuf = (LPWSTR) AllocateMemory( (dwLengthOfValueName + 2) * sizeof(WCHAR) ); if ( pwszNameBuf == NULL ) { lResult = ERROR_OUTOFMEMORY; } else { // Now Enumerate all values dwIndex = 0; lResult = ERROR_SUCCESS; lLastResult = ERROR_SUCCESS; while( dwIndex < dwNumOfValues ) { dw = dwLengthOfValueName; SecureZeroMemory( pwszNameBuf, dw * sizeof( WCHAR ) ); lResult = RegEnumValue( hSubKey, dwIndex, pwszNameBuf, &dw, NULL, NULL, NULL, NULL); if ( lResult == ERROR_SUCCESS ) { if ( DynArrayAppendString( arrValues, pwszNameBuf, 0 ) == -1 ) { lResult = lLastResult = ERROR_OUTOFMEMORY; break; } } else if ( lLastResult == ERROR_SUCCESS ) { lLastResult = lResult; } dwIndex++; } // free memory FreeMemory( &pwszNameBuf ); dwCount = DynArrayGetCount( arrValues ); if ( lResult != ERROR_OUTOFMEMORY && dwCount != 0 ) { dw = 0; dwIndex = 0; lResult = ERROR_SUCCESS; lLastResult = ERROR_SUCCESS; for( dwIndex = 0; dwIndex < dwCount; dwIndex++ ) { // delete the value pwszTemp = DynArrayItemAsString( arrValues, dwIndex ); lResult = RegDeleteValue( hSubKey, pwszTemp ); if ( lResult != ERROR_SUCCESS ) { if ( lLastResult == ERROR_SUCCESS ) { lLastResult = lResult; } } else { dw++; } } if ( dw == 0 ) { lResult = lLastResult; } else if ( dwCount != dwNumOfValues || dw != dwCount ) { lResult = STG_E_INCOMPLETE; } else { lResult = ERROR_SUCCESS; } } else { lResult = lLastResult; } } } } // close the sub key SafeCloseKey( &hSubKey ); // check the result if ( lResult != ERROR_SUCCESS ) { if ( lResult == STG_E_INCOMPLETE ) { SetReason( ERROR_DELETEPARTIAL ); } else { SaveErrorMessage( lResult ); } // display the error ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); } else { SaveErrorMessage( ERROR_SUCCESS ); ShowLastErrorEx( stdout, SLE_INTERNAL ); } return lResult; }