Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Annoying RegEnumKeyEx Problem

Annoying RegEnumKeyEx Problem

Scheduled Pinned Locked Moved C / C++ / MFC
helpcsharpvisual-studiocomwindows-admin
8 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    Baltoro
    wrote on last edited by
    #1

    I am writing an application that enumerates all the subkeys in HKEY_CLASSES_ROOT\CLSID, and then writes all the names of subkeys to an XML file for reference. It's pretty simple stuff, really. This registry location stores configuration information for all the registered COM classes on my machine, and there are about 4.000 subkeys. Each subkeys Name is the hexadecimal string representation of a 128-bit number known as a Globally Unique Identifier (GUID). When represented textually, GUIDs are always displayed in the following canonical form:

    BDA4A270-A1B1-11D0-8C2C-0080C73925BA    
    

    The HKEY_CLASSES_ROOT\CLSID subkeys are named exactly like this, except that they begin and end with curly braces. I enumerate the subkeys with a simple for loop, saving the GUID to a TCHAR buffer (size, 128 bytes) and everyting works OK, until I hit a subkey about a third of the way down that is a GUID with one of the integers missing. Then the RegEnumKeyEx function stops writing the GUIDs to the TCHAR buffer, but continues on without generating an error code. The program code then writes the GUID text strings to my XML file (this part works great). I had to write another function that uses RegEnumKeyEx in a for loop again, but indexes the enumeration to begin at the subkey immediately after the truncated GUID that caused the problem initially, and runs to the final key (total subkey count obtained with RegQueryInfoKey). This works successfully. but the entire process of the determining the source of the error, and writing a seperate enumeration function was quite time consuming (I initially thought it was insufficient memory.). I'm wondering if anyone knows why RegEnumKeyEx behaves like this. Surely, it doesn't check the text GUID values for validity. I used Registry Editor to search for other keys and associated values for that one malformed GUID, and found about a dozen entries, all with the same exact truncated format (weirdly enough, it's a Visual Studio component!). Any useful comments are appreciated,...thanks.

    D 1 Reply Last reply
    0
    • B Baltoro

      I am writing an application that enumerates all the subkeys in HKEY_CLASSES_ROOT\CLSID, and then writes all the names of subkeys to an XML file for reference. It's pretty simple stuff, really. This registry location stores configuration information for all the registered COM classes on my machine, and there are about 4.000 subkeys. Each subkeys Name is the hexadecimal string representation of a 128-bit number known as a Globally Unique Identifier (GUID). When represented textually, GUIDs are always displayed in the following canonical form:

      BDA4A270-A1B1-11D0-8C2C-0080C73925BA    
      

      The HKEY_CLASSES_ROOT\CLSID subkeys are named exactly like this, except that they begin and end with curly braces. I enumerate the subkeys with a simple for loop, saving the GUID to a TCHAR buffer (size, 128 bytes) and everyting works OK, until I hit a subkey about a third of the way down that is a GUID with one of the integers missing. Then the RegEnumKeyEx function stops writing the GUIDs to the TCHAR buffer, but continues on without generating an error code. The program code then writes the GUID text strings to my XML file (this part works great). I had to write another function that uses RegEnumKeyEx in a for loop again, but indexes the enumeration to begin at the subkey immediately after the truncated GUID that caused the problem initially, and runs to the final key (total subkey count obtained with RegQueryInfoKey). This works successfully. but the entire process of the determining the source of the error, and writing a seperate enumeration function was quite time consuming (I initially thought it was insufficient memory.). I'm wondering if anyone knows why RegEnumKeyEx behaves like this. Surely, it doesn't check the text GUID values for validity. I used Registry Editor to search for other keys and associated values for that one malformed GUID, and found about a dozen entries, all with the same exact truncated format (weirdly enough, it's a Visual Studio component!). Any useful comments are appreciated,...thanks.

      D Offline
      D Offline
      David Crow
      wrote on last edited by
      #2

      Baltoro wrote:

      I enumerate the subkeys with a simple for loop...

      What does this loop look like? Something like:

      if (RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
      {
      while (! bDone)
      {
      dwSize = 128;

          lResult = RegEnumKeyEx(hKey, dwIndex, szBuffer, &dwSize, NULL, NULL, NULL, &fileTime);
          if (lResult == ERROR\_MORE\_DATA || lResult == ERROR\_SUCCESS)
          {
              cout << szBuffer << endl;
              
              dwIndex++;
          }
          else
              bDone = TRUE;
      }
      
      RegCloseKey(hKey);
      

      }

      "Old age is like a bank account. You withdraw later in life what you have deposited along the way." - Unknown

      "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

      B 1 Reply Last reply
      0
      • D David Crow

        Baltoro wrote:

        I enumerate the subkeys with a simple for loop...

        What does this loop look like? Something like:

        if (RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
        {
        while (! bDone)
        {
        dwSize = 128;

            lResult = RegEnumKeyEx(hKey, dwIndex, szBuffer, &dwSize, NULL, NULL, NULL, &fileTime);
            if (lResult == ERROR\_MORE\_DATA || lResult == ERROR\_SUCCESS)
            {
                cout << szBuffer << endl;
                
                dwIndex++;
            }
            else
                bDone = TRUE;
        }
        
        RegCloseKey(hKey);
        

        }

        "Old age is like a bank account. You withdraw later in life what you have deposited along the way." - Unknown

        "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

        B Offline
        B Offline
        Baltoro
        wrote on last edited by
        #3

        The for loop that enumerates the HKEY_CLASSES_ROOT\CLSID key is as follows:

        DWORD dwRetVal = 0 ;    
        

        // ERROR_SUCCESS = 0 ERROR_MORE_DATA = 234
        // There is an error at number 1488. The CLSID entry is missing an integer.
        // The following loop fails to write GUIDs after that point. Reason unknown.

        for (DWORD dwClsidIndx = 1 ; dwClsidIndx <= 1488 ; dwClsidIndx++)    
        {    
        TCHAR ComClssGuid \[128\] ;    
        ZeroMemory (&ComClssGuid, 128) ;     
        LPTSTR pComClsid = ComClssGuid ;    
        dwRetVal = RegEnumKeyEx (hRootKey, dwClsidIndx, ComClssGuid, &dwSize, NULL, NULL, NULL, &ftLastWrtTime) ;       
        if ((dwRetVal != ERROR\_SUCCESS) && (dwRetVal != ERROR\_MORE\_DATA))    
        {    
        dwRetErrorVal = dwRetVal ;    
        dwErrNumClsid = dwClsidIndx ;    
        dwClsidErrors++ ;    
        TCHAR ErrorMessage \[192\] ;   
        wsprintf (ErrorMessage, TEXT("    ERROR: Number of Errors: %lu. ERROR: CLSID %lu. Error Code: %lu"), dwClsidErrors, dwErrNumClsid, dwRetErrorVal) ;    
        SetStatusMessage (ErrorMessage) ;    
        return FALSE ;    
        }    
        WriteClsidNodesAlpha (ClsidDomDoc, pDocRtElment, pComClsid, dwClsidIndx) ;     
        }    
        

        Explanation: dwRetErrorVal, dwErrNumClsid, and dwClsidErrors, are all DWORD variables declared outside of the function, used just to store the error code, CLSID subkey number, and the total number of such errors. WriteClsidNodesAlpha is the function that writes the data to a Node in an XML file. ...and SetStatusMessage merely displays text in the application's status bar.

        B K 2 Replies Last reply
        0
        • B Baltoro

          The for loop that enumerates the HKEY_CLASSES_ROOT\CLSID key is as follows:

          DWORD dwRetVal = 0 ;    
          

          // ERROR_SUCCESS = 0 ERROR_MORE_DATA = 234
          // There is an error at number 1488. The CLSID entry is missing an integer.
          // The following loop fails to write GUIDs after that point. Reason unknown.

          for (DWORD dwClsidIndx = 1 ; dwClsidIndx <= 1488 ; dwClsidIndx++)    
          {    
          TCHAR ComClssGuid \[128\] ;    
          ZeroMemory (&ComClssGuid, 128) ;     
          LPTSTR pComClsid = ComClssGuid ;    
          dwRetVal = RegEnumKeyEx (hRootKey, dwClsidIndx, ComClssGuid, &dwSize, NULL, NULL, NULL, &ftLastWrtTime) ;       
          if ((dwRetVal != ERROR\_SUCCESS) && (dwRetVal != ERROR\_MORE\_DATA))    
          {    
          dwRetErrorVal = dwRetVal ;    
          dwErrNumClsid = dwClsidIndx ;    
          dwClsidErrors++ ;    
          TCHAR ErrorMessage \[192\] ;   
          wsprintf (ErrorMessage, TEXT("    ERROR: Number of Errors: %lu. ERROR: CLSID %lu. Error Code: %lu"), dwClsidErrors, dwErrNumClsid, dwRetErrorVal) ;    
          SetStatusMessage (ErrorMessage) ;    
          return FALSE ;    
          }    
          WriteClsidNodesAlpha (ClsidDomDoc, pDocRtElment, pComClsid, dwClsidIndx) ;     
          }    
          

          Explanation: dwRetErrorVal, dwErrNumClsid, and dwClsidErrors, are all DWORD variables declared outside of the function, used just to store the error code, CLSID subkey number, and the total number of such errors. WriteClsidNodesAlpha is the function that writes the data to a Node in an XML file. ...and SetStatusMessage merely displays text in the application's status bar.

          B Offline
          B Offline
          Baltoro
          wrote on last edited by
          #4

          David Crow, Sorry, I can't get at the edit control to change the last post. You're probably laughing, it's such a ridiculous post. You will notice that the test expression in the for loop is: dwClsidIndx <= 1488 Well, I changed that value after the loop initially failed (at CLSID number 1488). it originally was 3965 (which is the value returned from RegQueryInfoKey, dwNumSubKeys). You will also notice that I begin the enumeration at value 1, instead of zero, as recommended by the documentation. This is because, I was getting the same name "CLSID" written to the TCHAR ComClssGuid [128] buffer, 3965 times (each time the loop executed). The code just preceeding the loop, where I obtain the hKey value is here:

          DWORD dwNumBubKeys = 0 ;    
          DWORD dwMaxSubLen = 0 ;    
          DWORD dwSize = 128 ;   
          FILETIME ftLastWrtTime ;  
          HKEY hRootKey = NULL ;    
          const TCHAR ComClsidEntrs \[\] = TEXT("CLSID") ;   
          LPCTSTR ClsidKeys = ComClsidEntrs ;    
          RegOpenKeyEx (HKEY\_CLASSES\_ROOT, ClsidKeys, 0, KEY\_ALL\_ACCESS, &hRootKey) ;    
          RegQueryInfoKey (hRootKey, NULL, NULL, NULL, &dwNumBubKeys, &dwMaxSubLen, NULL, NULL, NULL, NULL, NULL, NULL) ;   
          DWORD dwRetVal = 0 ;    
          

          // ERROR_SUCCESS = 0 ERROR_MORE_DATA = 234
          // There is an error at number 1488. The CLSID entry is missing an integer.
          // The following loop fails to write GUIDs after that point. Reason unknown.

          for (DWORD dwClsidIndx = 1 ; dwClsidIndx <= 3965 ; dwClsidIndx++)    
          {    
          TCHAR ComClssGuid \[128\] ;    
          ZeroMemory (&ComClssGuid, 128) ;     
          LPTSTR pComClsid = ComClssGuid ;    
          dwRetVal = RegEnumKeyEx (hRootKey, dwClsidIndx, ComClssGuid, &dwSize, NULL, NULL, NULL, &ftLastWrtTime) ;       
          if ((dwRetVal != ERROR\_SUCCESS) && (dwRetVal != ERROR\_MORE\_DATA))    
          {    
          dwRetErrorVal = dwRetVal ;    
          dwErrNumClsid = dwClsidIndx ;    
          dwClsidErrors++ ;    
          TCHAR ErrorMessage \[192\] ;   
          wsprintf (ErrorMessage, TEXT("    ERROR: Number of Errors: %lu. ERROR: CLSID %lu. Error Code: %lu"), dwClsidErrors, dwErrNumClsid, dwRetErrorVal) ;    
          SetStatusMessage (ErrorMessage) ;    
          return FALSE ;    
          }    
          WriteClsidNodesAlpha (ClsidDomDoc, pDocRtElment, pComClsid, dwClsidIndx) ;     
          }    
          

          Really, it's more of an annoyance than anything, since I was able to correct the problem. I'm just curious as to why it happened.

          B 1 Reply Last reply
          0
          • B Baltoro

            David Crow, Sorry, I can't get at the edit control to change the last post. You're probably laughing, it's such a ridiculous post. You will notice that the test expression in the for loop is: dwClsidIndx <= 1488 Well, I changed that value after the loop initially failed (at CLSID number 1488). it originally was 3965 (which is the value returned from RegQueryInfoKey, dwNumSubKeys). You will also notice that I begin the enumeration at value 1, instead of zero, as recommended by the documentation. This is because, I was getting the same name "CLSID" written to the TCHAR ComClssGuid [128] buffer, 3965 times (each time the loop executed). The code just preceeding the loop, where I obtain the hKey value is here:

            DWORD dwNumBubKeys = 0 ;    
            DWORD dwMaxSubLen = 0 ;    
            DWORD dwSize = 128 ;   
            FILETIME ftLastWrtTime ;  
            HKEY hRootKey = NULL ;    
            const TCHAR ComClsidEntrs \[\] = TEXT("CLSID") ;   
            LPCTSTR ClsidKeys = ComClsidEntrs ;    
            RegOpenKeyEx (HKEY\_CLASSES\_ROOT, ClsidKeys, 0, KEY\_ALL\_ACCESS, &hRootKey) ;    
            RegQueryInfoKey (hRootKey, NULL, NULL, NULL, &dwNumBubKeys, &dwMaxSubLen, NULL, NULL, NULL, NULL, NULL, NULL) ;   
            DWORD dwRetVal = 0 ;    
            

            // ERROR_SUCCESS = 0 ERROR_MORE_DATA = 234
            // There is an error at number 1488. The CLSID entry is missing an integer.
            // The following loop fails to write GUIDs after that point. Reason unknown.

            for (DWORD dwClsidIndx = 1 ; dwClsidIndx <= 3965 ; dwClsidIndx++)    
            {    
            TCHAR ComClssGuid \[128\] ;    
            ZeroMemory (&ComClssGuid, 128) ;     
            LPTSTR pComClsid = ComClssGuid ;    
            dwRetVal = RegEnumKeyEx (hRootKey, dwClsidIndx, ComClssGuid, &dwSize, NULL, NULL, NULL, &ftLastWrtTime) ;       
            if ((dwRetVal != ERROR\_SUCCESS) && (dwRetVal != ERROR\_MORE\_DATA))    
            {    
            dwRetErrorVal = dwRetVal ;    
            dwErrNumClsid = dwClsidIndx ;    
            dwClsidErrors++ ;    
            TCHAR ErrorMessage \[192\] ;   
            wsprintf (ErrorMessage, TEXT("    ERROR: Number of Errors: %lu. ERROR: CLSID %lu. Error Code: %lu"), dwClsidErrors, dwErrNumClsid, dwRetErrorVal) ;    
            SetStatusMessage (ErrorMessage) ;    
            return FALSE ;    
            }    
            WriteClsidNodesAlpha (ClsidDomDoc, pDocRtElment, pComClsid, dwClsidIndx) ;     
            }    
            

            Really, it's more of an annoyance than anything, since I was able to correct the problem. I'm just curious as to why it happened.

            B Offline
            B Offline
            Baltoro
            wrote on last edited by
            #5

            Thanks, Davis Crow, You know, it's probably something internal,...something that I can't access programmatically. Don't worry about it. Maybe even it's corruption in the registry storage copy. My machine is old (running Windows XP, SP1). Now, I know how to keep my code blocks from causing the displayed text to run off the page (here in the forum). Unfortunately, I can't even delete the post and repair the version. I know it looks confusing.

            D 1 Reply Last reply
            0
            • B Baltoro

              The for loop that enumerates the HKEY_CLASSES_ROOT\CLSID key is as follows:

              DWORD dwRetVal = 0 ;    
              

              // ERROR_SUCCESS = 0 ERROR_MORE_DATA = 234
              // There is an error at number 1488. The CLSID entry is missing an integer.
              // The following loop fails to write GUIDs after that point. Reason unknown.

              for (DWORD dwClsidIndx = 1 ; dwClsidIndx <= 1488 ; dwClsidIndx++)    
              {    
              TCHAR ComClssGuid \[128\] ;    
              ZeroMemory (&ComClssGuid, 128) ;     
              LPTSTR pComClsid = ComClssGuid ;    
              dwRetVal = RegEnumKeyEx (hRootKey, dwClsidIndx, ComClssGuid, &dwSize, NULL, NULL, NULL, &ftLastWrtTime) ;       
              if ((dwRetVal != ERROR\_SUCCESS) && (dwRetVal != ERROR\_MORE\_DATA))    
              {    
              dwRetErrorVal = dwRetVal ;    
              dwErrNumClsid = dwClsidIndx ;    
              dwClsidErrors++ ;    
              TCHAR ErrorMessage \[192\] ;   
              wsprintf (ErrorMessage, TEXT("    ERROR: Number of Errors: %lu. ERROR: CLSID %lu. Error Code: %lu"), dwClsidErrors, dwErrNumClsid, dwRetErrorVal) ;    
              SetStatusMessage (ErrorMessage) ;    
              return FALSE ;    
              }    
              WriteClsidNodesAlpha (ClsidDomDoc, pDocRtElment, pComClsid, dwClsidIndx) ;     
              }    
              

              Explanation: dwRetErrorVal, dwErrNumClsid, and dwClsidErrors, are all DWORD variables declared outside of the function, used just to store the error code, CLSID subkey number, and the total number of such errors. WriteClsidNodesAlpha is the function that writes the data to a Node in an XML file. ...and SetStatusMessage merely displays text in the application's status bar.

              K Offline
              K Offline
              krmed
              wrote on last edited by
              #6

              Baltoro wrote:

              for (DWORD dwClsidIndx = 1 ; dwClsidIndx <= 1488 ; dwClsidIndx++) { TCHAR ComClssGuid [128] ; ZeroMemory (&ComClssGuid, 128) ; LPTSTR pComClsid = ComClssGuid ; dwRetVal = RegEnumKeyEx (hRootKey, dwClsidIndx, ComClssGuid, &dwSize, NULL, NULL, NULL, &ftLastWrtTime) ;

              The problem is most likely that the dwSize variable is changed every time you call RegEnumKeyEx. Since most of the keys returned have 128 characters, you're ok. However the key with the missing digit causes dwSize to be set to 127, so from that point on, the value is too small to hold the rest of the keys. The solution is to simply set dwSize to 128 at at the top of your for loop. Hope that helps.

              Karl - WK5M PP-ASEL-IA (N43CS) PGP Key: 0xDB02E193 PGP Key Fingerprint: 8F06 5A2E 2735 892B 821C 871A 0411 94EA DB02 E193

              B 1 Reply Last reply
              0
              • K krmed

                Baltoro wrote:

                for (DWORD dwClsidIndx = 1 ; dwClsidIndx <= 1488 ; dwClsidIndx++) { TCHAR ComClssGuid [128] ; ZeroMemory (&ComClssGuid, 128) ; LPTSTR pComClsid = ComClssGuid ; dwRetVal = RegEnumKeyEx (hRootKey, dwClsidIndx, ComClssGuid, &dwSize, NULL, NULL, NULL, &ftLastWrtTime) ;

                The problem is most likely that the dwSize variable is changed every time you call RegEnumKeyEx. Since most of the keys returned have 128 characters, you're ok. However the key with the missing digit causes dwSize to be set to 127, so from that point on, the value is too small to hold the rest of the keys. The solution is to simply set dwSize to 128 at at the top of your for loop. Hope that helps.

                Karl - WK5M PP-ASEL-IA (N43CS) PGP Key: 0xDB02E193 PGP Key Fingerprint: 8F06 5A2E 2735 892B 821C 871A 0411 94EA DB02 E193

                B Offline
                B Offline
                Baltoro
                wrote on last edited by
                #7

                krmed, That was it, EXACTLY! Thanks to both you and David Crow, I appreciate it. I'm SO embarrassed! I can't believe that I made such an idiotic mistake. Anyway, thanks again.

                modified on Saturday, March 28, 2009 5:19 PM

                1 Reply Last reply
                0
                • B Baltoro

                  Thanks, Davis Crow, You know, it's probably something internal,...something that I can't access programmatically. Don't worry about it. Maybe even it's corruption in the registry storage copy. My machine is old (running Windows XP, SP1). Now, I know how to keep my code blocks from causing the displayed text to run off the page (here in the forum). Unfortunately, I can't even delete the post and repair the version. I know it looks confusing.

                  D Offline
                  D Offline
                  David Crow
                  wrote on last edited by
                  #8

                  Baltoro wrote:

                  Unfortunately, I can't even...repair the version. I know it looks confusing.

                  Actually you can. Go to one of your other posts and click the Edit button. Change the number in the URL to 2983307.

                  "Old age is like a bank account. You withdraw later in life what you have deposited along the way." - Unknown

                  "Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

                  1 Reply Last reply
                  0
                  Reply
                  • Reply as topic
                  Log in to reply
                  • Oldest to Newest
                  • Newest to Oldest
                  • Most Votes


                  • Login

                  • Don't have an account? Register

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • World
                  • Users
                  • Groups