How To Implement a RegRestoreKey() Function for Windows 95, Windows 98, and Windows Me (175329)



The information in this article applies to:

  • Microsoft Win32 Application Programming Interface (API), when used with:
    • the operating system: Microsoft Windows 95
    • the operating system: Microsoft Windows 98
    • the operating system: Microsoft Windows Millennium Edition

This article was previously published under Q175329

SUMMARY

This article demonstrates how to implement a RegRestoreKey() function under Microsoft Windows 95, Windows 98, and Windows Millennium Edition (Me). This process involves several steps that require that you delete both the descendant subkeys and their values before you add the new subkeys and values.

MORE INFORMATION

Step 1: Initialization

To avoid a conflict between two applications that are trying to restore to the same registry key, use a mutex to prevent a second restore from occurring before the first one is completed.
   hMutex = CreateMutex( NULL, TRUE, REG_RESTORE);
   if ( !hMutex )

     return GetLastError();

   if (GetLastError() == ERROR_ALREADY_EXISTS)
   {

     if ((lRet=WaitForSingleObject(hMutex, INFINITE)) != WAIT_OBJECT_0)
         return lRet;

   }
				

Step 2: Delete Key Values

First you must delete the specified key's values. To do this, you must first enumerate the key values using RegEnumValue() and then delete them using RegDeleteValue().
   for (;;)
   {

     cbValue = REGSTR_MAX_VALUE_LENGTH;        // reset value length
     // remove this keys old values
     lRet  = RegEnumValue(hStartKey,   // handle of key to query
                0,     // index of value to query
                szValue,  // address of buffer for value string
                &cbValue, // address for size of value buffer
                NULL,     // reserved
                NULL,     // address of buffer for type code
                NULL,     // address of buffer for value data
                NULL     // address for size of data buffer
            );

     if ( ERROR_NO_MORE_ITEMS == lRet ) // all values deleted
     {
            lRet = ERROR_SUCCESS;
            break;
     }
     else if ( ERROR_SUCCESS == lRet )
     {
        if ((lRet = RegDeleteValue(
                              hStartKey,  // handle of key
                              szValue     // address of value name
                              )) != ERROR_SUCCESS)
                return lRet;
     }
     else
       return lRet;

   }  // end for loop
				

Step 3: Delete Subkeys

After you have deleted the current values you must delete the specified key's subkeys. Do this by enumerating the subkeys using RegEnumKeyEx and then deleting them using RegDeleteKey. This deletes the current subkeys and all descendant subkeys. After you have completed the deletion, you can add the new subkeys and values.
   // delete all subkeys
   for(;;)
   {

       dwSubKeyLength = MAX_PATH;
       lRet=RegEnumKeyEx(
                   hStartKey,
                   0,
                   szSubKey,
                       &dwSubKeyLength,
                        NULL,
                        NULL,
                        NULL,
                        NULL
                        );
        if(lRet == ERROR_NO_MORE_ITEMS)
        {
            lRet = ERROR_SUCCESS;
            break;
        }
        else if(lRet == ERROR_SUCCESS)
        {
          if((lRet = RegDeleteKey(hStartKey, szSubKey)) != ERROR_SUCCESS)
              return lRet;
        }
        else
            return lRet;

   }  // end for loop
				

Step 4: Restore New Subkeys

To add the new values and subkeys, use RegLoadKey to duplicate and load the registry hive into the registry. Once the hive has been loaded, all values and subkeys are enumerated and copied to the specified restore key.
   // Load new hive
   lRet = RegLoadKey(HKEY_USERS, "TEMP_HIVE", szNewHive );

   DWORD RegCreateTree(HKEY hTree, HKEY hReplacement)
   {

     DWORD   cdwClass, dwSubKeyLength, dwDisposition, dwKeyIndex = 0;
     LPTSTR  pSubKey = NULL;
     TCHAR   szSubKey[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
     TCHAR   szClass[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
     HKEY    hNewKey, hKey;
     DWORD   lRet;

     for(;;)
     {
       dwSubKeyLength = REGSTR_MAX_VALUE_LENGTH;
       cdwClass = REGSTR_MAX_VALUE_LENGTH;
       lRet=RegEnumKeyEx(
                   hReplacement,
                   dwKeyIndex,
                   szSubKey,
                   &dwSubKeyLength,
                   NULL,
                   szClass,
                   &cdwClass,
                   NULL
                   );
       if(lRet == ERROR_NO_MORE_ITEMS)
       {
          lRet = ERROR_SUCCESS;
          break;
       }
       else if(lRet == ERROR_SUCCESS)
       {
          if ((lRet=RegCreateKeyEx(hTree, szSubKey,0, szClass,
                      REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
                      &hNewKey, &dwDisposition)) != ERROR_SUCCESS )
                break;
          else  // add key values and recurse
          {
            if ((lRet=RegCreateValues( hReplacement, szSubKey, hNewKey))
                    != ERROR_SUCCESS)
            {
                CloseHandle(hNewKey);
                break;
            }
            if ( (lRet=RegOpenKeyEx(hReplacement, szSubKey, 0,
                              KEY_ALL_ACCESS, &hKey )) == ERROR_SUCCESS )
            {
                lRet=RegCreateTree(hNewKey, hKey);
                CloseHandle(hKey);
                CloseHandle(hNewKey);
                if ( lRet != ERROR_SUCCESS )
                        break;
             }
             else
             {
                CloseHandle(hNewKey);
                break;
             }
          }
       }
       else
         break;
       ++dwKeyIndex;
     } // end for loop
    return lRet;

   }  // end RegCreateTree function

   DWORD RegCreateValues(HKEY hReplacement, LPCTSTR lpSubKey, HKEY hNewKey)
   {

     DWORD    cbValue, dwSubKeyIndex=0, dwType, cdwBuf;
     DWORD    dwValues, cbMaxValueData, i;
     LPTSTR   pSubKey = NULL;
     TCHAR    szValue[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
     HKEY     hKey;
     DWORD    lRet = ERROR_SUCCESS;
     LPBYTE   pBuf;

     if ((lRet=RegOpenKeyEx(hReplacement, lpSubKey, 0,
                    KEY_ALL_ACCESS, &hKey )) == ERROR_SUCCESS)
     {
        if ((lRet=RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, NULL,
                       NULL, &dwValues,NULL, &cbMaxValueData,
                       NULL, NULL)) == ERROR_SUCCESS)
        {
            if ( dwValues )
            {
                if ((pBuf=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                              cbMaxValueData )))
                {
                    for (i = 0; i < dwValues ; i++)
                    {
                       //  get values to create
                       cbValue = REGSTR_MAX_VALUE_LENGTH;
                       cdwBuf = cbMaxValueData;
                       lRet = RegEnumValue(
                                hKey,     // handle of key to query
                                i,        // index of value to query
                                szValue,  // buffer for value string
                                &cbValue, // address for size of buffer
                                NULL,     // reserved
                                &dwType,  // buffer address for type code
                                pBuf,   // address of buffer for value data
                                &cdwBuf   // address for size of buffer
                                );

                        if ( ERROR_SUCCESS == lRet )
                        {
                            if( (lRet=RegSetValueEx(hNewKey, szValue, 0,
                                       dwType, (CONST BYTE *)pBuf,
                                       cdwBuf))!= ERROR_SUCCESS)
                                break;
                        }
                        else
                            break;

                    }  // for loop
                }
                HeapFree(GetProcessHeap(), 0, pBuf);
            }
        }
        CloseHandle(hKey);
     }
     return lRet;

   }  // end of RegCreateValues function
				

Step 5: Clean Up

When all operations have been completed, the registry hive that was loaded is unloaded and the mutex is released to allow other restores to begin.
   // UnLoad user hive
   lRet = RegUnLoadKey(HKEY_USERS, "TEMP_HIVE");
   ReleaseMutex(hMutex);
				

Modification Type:MinorLast Reviewed:9/27/2004
Keywords:kbhowto kbKernBase kbRegistry KB175329