Exporting the Registry Through the Program

-->

Environment: Visual C++ 6.0, Windows 2000 / Windows NT 4.0.

At present we have an option to export the registry only through the RegEdit UI by selecting the menu option. RegEdit doesn't have command line parameters to export. This tool helps developers to export the registry within a program when given the root key name and the file where the values should be stored. The exported file can imported directly into the registry with minimal header changes depends on the version of Windows which you are using.

Sample output is shown below:

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER]

[HKEY_CURRENT_USER\AppEvents]
"Migrated Schemes" = "1"

[HKEY_CURRENT_USER\AppEvents\EventLabels]

[HKEY_CURRENT_USER\AppEvents\EventLabels\.Default]
@ = "Default Beep"

[HKEY_CURRENT_USER\AppEvents\EventLabels\ActivatingDocument]
@ = "Complete Navigation"

Source code:

/////////////////////////////////////////////////////////////////////////
//// Imputs : 1. Rootkey name as CString i.e 
////             HKEY_LOCAL_MACHINE, HKEY_CURRENT_USERS...etc
////          2. Subkey name as CString i.e Software\Microsoft, 
////             Software\Fonts
////          3. Filename to store the values.
////         example: ExportRegistry(_T("HKEY_CURRENT_USER"),
////                                 _T(""), 
////                                 _T("C:\\temp\\test.reg"));   
//////////////////////////////////////////////////////////////////////////
void ExportRegistry( CString cstrKeyRootName, 
                     CString cstrKeyName, 
                     CString cstrFileName)
{
   FILE *fp;

   HKEY hKeyRootName;

   CString cstrFullPathStr(_T(""));
   int iDepth = 0;

   HKEY hParentKey[100];
   TCHAR strParentString[1024][100];
   DWORD dwParentIndex[100];

   HKEY hCurKey, hPrevKey;
   TCHAR strCurString[1024], strPrevString[1024];
   DWORD dwCurIndex = 0, dwPrevIndex = 0;
   LONG lResult;

   if(cstrKeyRootName == _T("HKEY_CLASSES_ROOT"))
      hKeyRootName = HKEY_CLASSES_ROOT;

   if(cstrKeyRootName == _T("HKEY_CURRENT_USER"))
      hKeyRootName = HKEY_CURRENT_USER;

   if(cstrKeyRootName == _T("HKEY_LOCAL_MACHINE"))
      hKeyRootName = HKEY_LOCAL_MACHINE;

   if(cstrKeyRootName == _T("HKEY_USERS"))
      hKeyRootName = HKEY_USERS;

   if(cstrKeyRootName == _T("HKEY_PERFORMANCE_DATA"))
      hKeyRootName = HKEY_PERFORMANCE_DATA;

   if(cstrKeyRootName == _T("HKEY_CURRENT_CONFIG"))
      hKeyRootName = HKEY_CURRENT_CONFIG;

   if(cstrKeyRootName == _T("HKEY_DYN_DATA"))
      hKeyRootName = HKEY_DYN_DATA;

   //// 
   fp = fopen(cstrFileName, "w+");
   if(fp == NULL)
   {
      MessageBox(NULL, 
                 _T("Error while creating the file"), 
                 _T("Registry export"), 
                 MB_OK);
      return;
   }
   //// first open the root key to get the handle...
   lResult = RegOpenKeyEx(hKeyRootName, 
                          cstrKeyName, 
                          0, 
                          KEY_ENUMERATE_SUB_KEYS, 
                          &hCurKey);

   if(cstrKeyName.IsEmpty())
      cstrFullPathStr = cstrKeyRootName;
   else
      cstrFullPathStr = cstrKeyRootName + 
                        _T("\\") + 
                        cstrKeyName;

   //// First print the header ..... this may be 
   ////   different for some version of Windows... 
   ////   do manually change if required

   fprintf(fp, 
           "%s\n", 
           _T("Windows Registry Editor Version 5.00"));

   fprintf(fp, "[%s]\n", cstrFullPathStr);

   do
   {
      lResult = RegEnumKey( hCurKey, 
                            dwCurIndex, 
                            strCurString,  
                            sizeof(strCurString));

      ///// assign current to previous to traverse back...
      hPrevKey = hCurKey;
      dwPrevIndex = dwCurIndex;
      _tcscpy(strPrevString, strCurString);

      ///// sometimes we maynot be able to open the 
      ///// registry key and it may return 
      ///// ERROR_INVALID_HANDLE, 
      ///// in that case you just ignore and proceed ...

      if((lResult == ERROR_NO_MORE_ITEMS) || 
         (lResult == ERROR_INVALID_HANDLE))
      {
         if(lResult == ERROR_INVALID_HANDLE)
            fprintf(fp, "\n%s\n", "Error");
         iDepth--;
         if(iDepth < 0)
            break;

         EnumerateValues( hCurKey, 
                          strCurString, 
                          fp, 
                          cstrFullPathStr);

         ////// take the values for the current depth...
         hCurKey = hParentKey[iDepth];
         dwCurIndex = dwParentIndex[iDepth] + 1;
         _tcscpy(strCurString, strParentString[iDepth]);

         int i = cstrFullPathStr.ReverseFind(_T('\\'));
         CString cstrTemp;
         cstrTemp = cstrFullPathStr.Left(i);
         cstrFullPathStr = cstrTemp;

         continue;
      }
      else
      {
         //// Copy values to parent
         //// make current as a parent and traverse down...
         hParentKey[iDepth] = hCurKey;
         dwParentIndex[iDepth] = dwCurIndex;
         _tcscpy(strParentString[iDepth], strCurString);

         cstrFullPathStr += _T("\\");
         cstrFullPathStr += strCurString;

         EnumerateValues( hCurKey, 
                          strCurString, 
                          fp,  
                          cstrFullPathStr);

         lResult = RegOpenKeyEx( hCurKey, 
                                 strCurString, 
                                 0, 
                                 KEY_ENUMERATE_SUB_KEYS, 
                                 &hCurKey);

         iDepth ++;
         dwCurIndex = 0;
      }

   }while(TRUE);

   fclose(fp);
}

//////////////////////////////////////////////////////////////
//// Enumerates through the values of the given key 
////   and store the values into the file.
//// Invokes "FormatDataWithDataType" function to format 
////   the data
//// 
//// Inputs: 1. Handle to the key
////         2. Key name
////         3. File pointer
////         4. Full path of the key to store in the file
/////////////////////////////////////////////////////////////////
void EnumerateValues( HKEY hKey, 
                      CString cstrKey, 
                      FILE *fp, 
                      CString cstrFullPath)
{
   static HKEY hLastKey = hKey;

   LONG lResult;
   DWORD dwIndex = 0;

   HKEY hCurKey = hKey;

   DWORD dwKeyType; 
   DWORD dwKeyDataLength, dwKeyNameLen;

   LPBYTE pbbinKeyData = NULL; 
   TCHAR *tcKeyName = NULL;
   TCHAR tcDataType[1024] = _T("");

   lResult = RegOpenKeyEx( hCurKey, 
                           cstrKey, 
                           0, 
                           KEY_QUERY_VALUE , 
                           &hKey);
   if(lResult != ERROR_SUCCESS)
      return;

   DWORD lNoOfValues = 0;
   DWORD lLongestKeyNameLen = 1;
   DWORD lLongestDataLen = 1;

   lResult = RegQueryInfoKey( hKey, 
                              NULL, 
                              NULL, 
                              NULL, 
                              NULL, 
                              NULL, 
                              NULL,
                              &lNoOfValues, 
                              &lLongestKeyNameLen, 
                              &lLongestDataLen,
                              NULL, 
                              NULL);
   
   if(lResult != ERROR_SUCCESS)
      return;

   fprintf(fp, "\n[%s]\n", cstrFullPath);

   hLastKey = hKey;

   lLongestKeyNameLen++;
   lLongestDataLen++;

   tcKeyName =   new TCHAR[lLongestKeyNameLen];
   pbbinKeyData = new BYTE[lLongestDataLen];

   CString cstrFinalData, cstrTemp;

   while(TRUE)
   {
      memset(pbbinKeyData, 0, lLongestDataLen);
      memset(tcKeyName, 0, lLongestKeyNameLen);
      dwKeyType = dwKeyDataLength = dwKeyNameLen = 0;

      dwKeyNameLen = lLongestKeyNameLen;
      dwKeyDataLength = lLongestDataLen;

      lResult = RegEnumValue( hKey, 
                              dwIndex, 
                              tcKeyName, 
                              &dwKeyNameLen,
                              NULL, 
                              &dwKeyType, 
                              pbbinKeyData, 
                              &dwKeyDataLength);
      if(lResult == ERROR_NO_MORE_ITEMS)
         break;

      FormatDataWithDataType( dwKeyType, 
                              pbbinKeyData, 
                              dwKeyDataLength,
                              cstrFinalData);
   
      //// For (default) key names the tcKeyName is 
      //// empty and dwKeyNameLen is zero ...in such 
      //// case we need to have assignment like @ = "value"
      CString cstrTest;
      cstrTest = tcKeyName;
      if(cstrTest.IsEmpty())
      {
         cstrTemp.Format(_T("@ = "));
      }
      else
      {
         cstrTemp.Format(_T("\"%s\" = "), tcKeyName);
      }
      cstrTemp += cstrFinalData;

      fprintf(fp, "%s", (LPCTSTR)cstrTemp);
      dwIndex++;
   }

   delete tcKeyName;
   delete pbbinKeyData;
}

////////////////////////////////////////////////////
//// Format the value with the actual data as the 
////     same way the REGEDIT does....
//// Inputs: 1. Data type of the key
////         2. Data to be formatted
////         3. Length of the data
//// Output: 4. Formatted string
////////////////////////////////////////////////////
void FormatDataWithDataType( DWORD dwKeyType, 
                             LPBYTE pbbinKeyData, 
                             DWORD dwKeyDataLength, 
                             CString &cstrOutput)   
{
   CString cstrTemp, cstrTemp1;
   switch(dwKeyType)
   {
      case REG_SZ:
      {
         cstrTemp.Format(_T("\"%s\"\n"), pbbinKeyData);
         cstrOutput = cstrTemp;
         break;
      }

      case REG_DWORD: /// same is for REG_DWORD_LITTLE_ENDIAN
      {
         DWORD dwValue;
         memcpy(&dwValue, pbbinKeyData, sizeof DWORD);
         cstrTemp.Format(_T("dword:%08x\n"), dwValue);
         cstrOutput = cstrTemp;
         break;
      }

      case REG_BINARY:
      case REG_MULTI_SZ:
      case REG_EXPAND_SZ:
      case REG_FULL_RESOURCE_DESCRIPTOR:
      case REG_RESOURCE_LIST:
      case REG_RESOURCE_REQUIREMENTS_LIST:
      {
         if(dwKeyType != REG_BINARY)
            cstrOutput.Format(_T("hex(%d):"), dwKeyType);
         else
            cstrOutput.Format(_T("hex:"));

         for(DWORD dwIndex = 0; dwIndex < dwKeyDataLength; 
             dwIndex++)
         {
            cstrTemp1.Format( _T("%02x,"), pbbinKeyData[dwIndex]);
                              cstrTemp += cstrTemp1;
            if(dwIndex != 0 && (dwIndex % 0x15 == 0))
               cstrTemp += _T("\\\n");
         }

         cstrTemp += _T("\n");
         cstrOutput += cstrTemp;
         break;
      }

      case REG_NONE:
      case REG_DWORD_BIG_ENDIAN:
      case REG_LINK:
         //// TODO : add code for these types...
         break;

   }
}

Downloads

Download source - 6 KB