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


Comments

  • Great code but printing of the input key is missing

    Posted by Legacy on 02/10/2003 12:00am

    Originally posted by: Roland van Rijswijk

    I love this code, but there is one thing missing: if the key specified in cstrKeyName has values of its own, these are not exported. The following modifications will fix this (make the modifications under the "RvR fix printing of base key" comments):
    
    

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

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

    // RvR: fix printing of base key
    //fprintf(fp, "[%s]\n", cstrFullPathStr);

    // RvR: fix printing of base key
    EnumerateValues(
    hKeyRootName,
    cstrKeyName,
    fp,
    cstrFullPathStr);

    ...

    Reply
  • Great!!!

    Posted by Legacy on 01/14/2003 12:00am

    Originally posted by: beinerror

    It do exactly what I searches for. Thank you.
    By the way... RegSaveKey did NOT work yet in W2K an XP there is a Error, well known by microsoft, but still not fixed.

    Reply
  • There is one small error...

    Posted by Legacy on 06/12/2002 12:00am

    Originally posted by: Kane Miller

    I love this code, but when it runs out of subkeys to traverse and has to go back up one level in the registry tree, it prints out the last key and its values again.
    
    

    All that needs to be removed is EnumerateValues() in the following 'if' statement:

    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;

    // CUT HERE
    EnumerateValues( hCurKey, strCurString, fp, cstrFullPathStr);
    // STOP CUTTING HERE

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

    Thanks for the code! I modified it to output into XML format and it has become very useful!

    Reply
  • Use the Win32 RegSaveKey

    Posted by Legacy on 02/11/2002 12:00am

    Originally posted by: Scott

    Calling RegSaveKey and passing the destination file will do exactly what you want. It is supported on all os flavors.

    Reply
  • Why not just call regedit directly from your code ?

    Posted by Legacy on 02/09/2002 12:00am

    Originally posted by: Jase Jennings

    This is much simpler :
    
    

    [ccode]
    //
    // build a .REG file that contains the tuning guide
    CString strTempFile = _T("C:\\Temp\\SafeToDelete.REG");
    //
    // build a regedit command line
    // /s silent
    // /e export
    //
    //
    CString strTemp;
    strTemp.Format(_T(" /s /e \"%s\" HKEY_CURRENT_USER\\Software\\Microsoft"),

    strTempFile);

    // execute
    SHELLEXECUTEINFO se={0};
    se.cbSize = sizeof(se);
    se.lpFile = _T("regedit");
    se.lpParameters = strTemp;
    se.nShow = SW_SHOWDEFAULT;
    se.fMask = SEE_MASK_NOCLOSEPROCESS;
    ShellExecuteEx( &se );

    // wait for process to finish
    if (se.hProcess)
    {
    WaitForSingleObject(se.hProcess, INFINITE);
    CloseHandle(se.hProcess);
    }

    if (DWORD(se.hInstApp) < 33)
    {
    // Display error
    MessageBox(_T("display get last error msg here"), _T("Error"),

    MB_OK|MB_ICONINFORMATION );
    }
    [/ccode]

    Thanks to Gabriel Fleseriu for posting this code in the VC++ forum ...

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • Due to internal controls and regulations, the amount of long term archival data is increasing every year. Since magnetic tape does not need to be periodically operated or connected to a power source, there will be no data loss because of performance degradation due to the drive actuator. Read this white paper to learn about a series of tests that determined magnetic tape is a reliable long-term storage solution for up to 30 years.

Most Popular Programming Stories

More for Developers

RSS Feeds