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. Windows API
  4. Bizarre behavior of RegQueryValueEx(), please advise.

Bizarre behavior of RegQueryValueEx(), please advise.

Scheduled Pinned Locked Moved Windows API
questioncsswindows-admindata-structureshelp
26 Posts 2 Posters 99 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.
  • L Lost User

    You're talking about the values, not the complete key. You might want to verify the size using a tool[^].

    Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]

    S Offline
    S Offline
    SMD111
    wrote on last edited by
    #5

    Done it, for the sake of discussion... The size of the key is 6588 bytes. Still far from the 64K limit.

    1 Reply Last reply
    0
    • S SMD111

      I am using registry to store a set of binary values under the same key, each value is a data structure 88 bytes long. In my application a user chooses a value and supplies a name for it, and the following (almost) code gets executed:

      DWORD N = sizeof(MyDataStructure); // 88 bytes
      BYTE tmp = new BYTE[N];
      BOOL Status = TRUE;

      dwError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_QUERY_VALUE, &hkResult);

      if(dwError != ERROR_SUCCESS) Status = FALSE;

      if(Status) {
      dwError = RegQueryValueEx(hkResult, szValueName, NULL, &dwDataType, NULL, &dwDataSize);
      if(dwError != ERROR_SUCCESS || datatype != REG_BINARY || datasize != N) Status = FALSE;
      if(Status) {
      dwError = RegQueryValueEx(hkResult, szValueName, NULL, &dwDataType, tmp, &dwDataSize);
      if(dwError != ERROR_SUCCESS) Status = FALSE;
      if(Status) {
      // Now the "tmp" array holds my data, and I process it...
      }
      }
      }
      delete[] tmp;

      I have discovered by accident that everything works as expected only for a certain number of values. For example, if I have 55 values stored in registry, I can retrieve only 52 of them. Whenever I try to get data for the 53rd value, RegQueryValueEx reads one of the lower-numbered ones! The "magic number" (here 52) is different on different computers, but is the same for the same computer type. For example, 52 was obtained on HP Mini running Win7 Starter, but the cutoff value equaled to 98 on Dell(s) Latitude under Win7 Pro. According to MSDN article KB256986,

      Quote:

      There is a 64K limit for the total size of all values of a key.

      However, 88 bytes times 52 is much less than 64K. What is going on? Thanks for your attention to this! SD

      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #6

      I am confused by your description, it does not seem to match your code. You have a single value of 88 bytes which you read by passing in a value name. Where does the 55 or 52 come into it?

      S 2 Replies Last reply
      0
      • L Lost User

        I am confused by your description, it does not seem to match your code. You have a single value of 88 bytes which you read by passing in a value name. Where does the 55 or 52 come into it?

        S Offline
        S Offline
        SMD111
        wrote on last edited by
        #7

        If I have 52 values of 88 bytes each stored in a key, I can read any of those values and get a correct result. If I add more values (and have say 55) then try to read the "last" ones, the returned value is not the one being requested but one stored earlier. In other words, // If there are 52 values: RegQueryValueEx("hMyKey, "Value50", NULL, &dwDataType, bDataBuffer, &dwDataSize); // After this call bDataBuffer contains Value50. // If there are 55 values: RegQueryValueEx("hMyKey, "Value53", NULL, &dwDataType, bDataBuffer, &dwDataSize); // There is no error, but bDataBuffer contains Value48 (or Value44), not Value53

        L 1 Reply Last reply
        0
        • L Lost User

          I am confused by your description, it does not seem to match your code. You have a single value of 88 bytes which you read by passing in a value name. Where does the 55 or 52 come into it?

          S Offline
          S Offline
          SMD111
          wrote on last edited by
          #8

          Sorry for the typo with "hMyKey...

          L 1 Reply Last reply
          0
          • S SMD111

            If I have 52 values of 88 bytes each stored in a key, I can read any of those values and get a correct result. If I add more values (and have say 55) then try to read the "last" ones, the returned value is not the one being requested but one stored earlier. In other words, // If there are 52 values: RegQueryValueEx("hMyKey, "Value50", NULL, &dwDataType, bDataBuffer, &dwDataSize); // After this call bDataBuffer contains Value50. // If there are 55 values: RegQueryValueEx("hMyKey, "Value53", NULL, &dwDataType, bDataBuffer, &dwDataSize); // There is no error, but bDataBuffer contains Value48 (or Value44), not Value53

            L Offline
            L Offline
            Lost User
            wrote on last edited by
            #9

            Have you checked the registry to make sure the values are stored correctly? Have you run it with the debugger to ensure the value names are correct?

            S 1 Reply Last reply
            0
            • S SMD111

              Sorry for the typo with "hMyKey...

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #10

              I have created a simple program to add 150 values to a key, and then read them out, in sequence or randomly. In every case I get the correct value returned. There must be something else in your code that causes the error.

              S 1 Reply Last reply
              0
              • L Lost User

                Have you checked the registry to make sure the values are stored correctly? Have you run it with the debugger to ensure the value names are correct?

                S Offline
                S Offline
                SMD111
                wrote on last edited by
                #11

                Yes, I have. That was done 10 years ago. I've been using this registry storage approach since 2004. There is nothing to debug, the application has always worked flawlessly - until the number of values exceeded certain computer-specific limit, which is much lower than the officially documented one.

                L 2 Replies Last reply
                0
                • L Lost User

                  I have created a simple program to add 150 values to a key, and then read them out, in sequence or randomly. In every case I get the correct value returned. There must be something else in your code that causes the error.

                  S Offline
                  S Offline
                  SMD111
                  wrote on last edited by
                  #12

                  I have included the essential code example with my original post. You are welcome to comment on it or let me know if I should give more details.

                  L 2 Replies Last reply
                  0
                  • S SMD111

                    Yes, I have. That was done 10 years ago. I've been using this registry storage approach since 2004. There is nothing to debug, the application has always worked flawlessly - until the number of values exceeded certain computer-specific limit, which is much lower than the officially documented one.

                    L Offline
                    L Offline
                    Lost User
                    wrote on last edited by
                    #13

                    That something worked for 10 years does not mean that it is flawless. It is also not an argument to skip debugging. You could use below code to verify whether it is a limit or not. If there's a limit, below code should run into the same problem.

                    using Microsoft.Win32;
                    using System;
                    using System.Collections.Generic;
                    using System.Runtime.InteropServices;
                    using System.Text;

                    namespace ConsoleApplication5
                    {
                    class Program
                    {
                    static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
                    const int LOOPS = 200;

                        enum RegistryRights: int
                        {
                            ReadKey = 131097,
                            WriteKey = 131078
                        }
                    
                        \[DllImport("advapi32.dll", CharSet = CharSet.Auto)\]
                        public static extern int RegOpenKeyEx(
                          UIntPtr hKey,
                          string subKey,
                          int ulOptions,
                          int samDesired,
                          out UIntPtr hkResult);
                        \[DllImport("advapi32.dll", SetLastError = true)\]
                        static extern uint RegQueryValueEx(
                            UIntPtr hKey,
                            string lpValueName,
                            int lpReserved,
                            ref uint lpType,
                            IntPtr lpData,
                            ref uint lpcbData);
                        \[DllImport("advapi32.dll", SetLastError = true)\]
                        public static extern int RegCloseKey(
                            UIntPtr hKey);
                    
                        private static string ReadRegKey(UIntPtr rootKey, string keyPath, string valueName)
                        {
                            UIntPtr hKey = UIntPtr.Zero;
                            string keyValue = "";
                    
                            if (RegOpenKeyEx(rootKey, keyPath, (int)0, (int)RegistryRights.ReadKey, out hKey) == 0)
                            {
                                uint size = 1024;
                                uint type = 0;
                                IntPtr pResult = IntPtr.Zero;
                    
                                pResult = Marshal.AllocHGlobal((int)size);
                                if (RegQueryValueEx(hKey, valueName, 0, ref type, pResult, ref size) == 0)
                                    keyValue = Convert.ToString(Marshal.ReadByte(pResult)); // takes only first byte, for test
                                Marshal.FreeHGlobal(pResult);
                    
                                RegCloseKey(hKey);
                            }
                    
                            return keyValue;
                        }
                    
                        static void Prepare()
                        {
                            byte\[\] bytes = new byte\[88\];
                            for (byte b = 0; b < 88; b++)
                                bytes\[b\] = b;
                    
                            RegistryKey rkey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
                            RegistryKey tkey = rkey.OpenSubKey("Test", true);
                            for (byte i = 0; i < LOOPS; i++)
                            {
                    
                    L S 2 Replies Last reply
                    0
                    • S SMD111

                      Yes, I have. That was done 10 years ago. I've been using this registry storage approach since 2004. There is nothing to debug, the application has always worked flawlessly - until the number of values exceeded certain computer-specific limit, which is much lower than the officially documented one.

                      L Offline
                      L Offline
                      Lost User
                      wrote on last edited by
                      #14

                      SMD111 wrote:

                      the application has always worked flawlessly - until

                      Then it hasn't worked flawlessly. You really need to do some serious debugging to find out why this is happening. Rather than just assuming that it's a Microsoft error, you should look deeper into your code.

                      S 1 Reply Last reply
                      0
                      • L Lost User

                        That something worked for 10 years does not mean that it is flawless. It is also not an argument to skip debugging. You could use below code to verify whether it is a limit or not. If there's a limit, below code should run into the same problem.

                        using Microsoft.Win32;
                        using System;
                        using System.Collections.Generic;
                        using System.Runtime.InteropServices;
                        using System.Text;

                        namespace ConsoleApplication5
                        {
                        class Program
                        {
                        static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
                        const int LOOPS = 200;

                            enum RegistryRights: int
                            {
                                ReadKey = 131097,
                                WriteKey = 131078
                            }
                        
                            \[DllImport("advapi32.dll", CharSet = CharSet.Auto)\]
                            public static extern int RegOpenKeyEx(
                              UIntPtr hKey,
                              string subKey,
                              int ulOptions,
                              int samDesired,
                              out UIntPtr hkResult);
                            \[DllImport("advapi32.dll", SetLastError = true)\]
                            static extern uint RegQueryValueEx(
                                UIntPtr hKey,
                                string lpValueName,
                                int lpReserved,
                                ref uint lpType,
                                IntPtr lpData,
                                ref uint lpcbData);
                            \[DllImport("advapi32.dll", SetLastError = true)\]
                            public static extern int RegCloseKey(
                                UIntPtr hKey);
                        
                            private static string ReadRegKey(UIntPtr rootKey, string keyPath, string valueName)
                            {
                                UIntPtr hKey = UIntPtr.Zero;
                                string keyValue = "";
                        
                                if (RegOpenKeyEx(rootKey, keyPath, (int)0, (int)RegistryRights.ReadKey, out hKey) == 0)
                                {
                                    uint size = 1024;
                                    uint type = 0;
                                    IntPtr pResult = IntPtr.Zero;
                        
                                    pResult = Marshal.AllocHGlobal((int)size);
                                    if (RegQueryValueEx(hKey, valueName, 0, ref type, pResult, ref size) == 0)
                                        keyValue = Convert.ToString(Marshal.ReadByte(pResult)); // takes only first byte, for test
                                    Marshal.FreeHGlobal(pResult);
                        
                                    RegCloseKey(hKey);
                                }
                        
                                return keyValue;
                            }
                        
                            static void Prepare()
                            {
                                byte\[\] bytes = new byte\[88\];
                                for (byte b = 0; b < 88; b++)
                                    bytes\[b\] = b;
                        
                                RegistryKey rkey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
                                RegistryKey tkey = rkey.OpenSubKey("Test", true);
                                for (byte i = 0; i < LOOPS; i++)
                                {
                        
                        L Offline
                        L Offline
                        Lost User
                        wrote on last edited by
                        #15

                        Take a look at OP's original code - looks more like C/C++ to me. :rolleyes:

                        L 1 Reply Last reply
                        0
                        • S SMD111

                          I have included the essential code example with my original post. You are welcome to comment on it or let me know if I should give more details.

                          L Offline
                          L Offline
                          Lost User
                          wrote on last edited by
                          #16

                          Yes, but it does not tell us anything much that helps to identify why it is not working. [edit] Removed redundant comment. [/edit]

                          S 1 Reply Last reply
                          0
                          • L Lost User

                            Take a look at OP's original code - looks more like C/C++ to me. :rolleyes:

                            L Offline
                            L Offline
                            Lost User
                            wrote on last edited by
                            #17

                            That's why my example doesn't use the managed api. The dll will hardly care whether the calling code is in C, Delphi or managed. Or am I wrong on that concept? :rolleyes:

                            Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]

                            L 1 Reply Last reply
                            0
                            • L Lost User

                              That something worked for 10 years does not mean that it is flawless. It is also not an argument to skip debugging. You could use below code to verify whether it is a limit or not. If there's a limit, below code should run into the same problem.

                              using Microsoft.Win32;
                              using System;
                              using System.Collections.Generic;
                              using System.Runtime.InteropServices;
                              using System.Text;

                              namespace ConsoleApplication5
                              {
                              class Program
                              {
                              static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
                              const int LOOPS = 200;

                                  enum RegistryRights: int
                                  {
                                      ReadKey = 131097,
                                      WriteKey = 131078
                                  }
                              
                                  \[DllImport("advapi32.dll", CharSet = CharSet.Auto)\]
                                  public static extern int RegOpenKeyEx(
                                    UIntPtr hKey,
                                    string subKey,
                                    int ulOptions,
                                    int samDesired,
                                    out UIntPtr hkResult);
                                  \[DllImport("advapi32.dll", SetLastError = true)\]
                                  static extern uint RegQueryValueEx(
                                      UIntPtr hKey,
                                      string lpValueName,
                                      int lpReserved,
                                      ref uint lpType,
                                      IntPtr lpData,
                                      ref uint lpcbData);
                                  \[DllImport("advapi32.dll", SetLastError = true)\]
                                  public static extern int RegCloseKey(
                                      UIntPtr hKey);
                              
                                  private static string ReadRegKey(UIntPtr rootKey, string keyPath, string valueName)
                                  {
                                      UIntPtr hKey = UIntPtr.Zero;
                                      string keyValue = "";
                              
                                      if (RegOpenKeyEx(rootKey, keyPath, (int)0, (int)RegistryRights.ReadKey, out hKey) == 0)
                                      {
                                          uint size = 1024;
                                          uint type = 0;
                                          IntPtr pResult = IntPtr.Zero;
                              
                                          pResult = Marshal.AllocHGlobal((int)size);
                                          if (RegQueryValueEx(hKey, valueName, 0, ref type, pResult, ref size) == 0)
                                              keyValue = Convert.ToString(Marshal.ReadByte(pResult)); // takes only first byte, for test
                                          Marshal.FreeHGlobal(pResult);
                              
                                          RegCloseKey(hKey);
                                      }
                              
                                      return keyValue;
                                  }
                              
                                  static void Prepare()
                                  {
                                      byte\[\] bytes = new byte\[88\];
                                      for (byte b = 0; b < 88; b++)
                                          bytes\[b\] = b;
                              
                                      RegistryKey rkey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
                                      RegistryKey tkey = rkey.OpenSubKey("Test", true);
                                      for (byte i = 0; i < LOOPS; i++)
                                      {
                              
                              S Offline
                              S Offline
                              SMD111
                              wrote on last edited by
                              #18

                              Thank you for the code example. I cannot compile it because I use plain C, such as in Microsoft Windows Help (Win32 Online Help, version 1.00.178) or on MSDN pages, or such as this one: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911%28v=vs.85%29.aspx[^]

                              L 1 Reply Last reply
                              0
                              • L Lost User

                                SMD111 wrote:

                                the application has always worked flawlessly - until

                                Then it hasn't worked flawlessly. You really need to do some serious debugging to find out why this is happening. Rather than just assuming that it's a Microsoft error, you should look deeper into your code.

                                S Offline
                                S Offline
                                SMD111
                                wrote on last edited by
                                #19

                                Quote:

                                You really need to do some serious debugging to find out why this is happening.

                                Why do you assume I have not done “some serious debugging”? Please teach me how to debug a single RTL function call that does not generate an error.

                                Quote:

                                Rather than just assuming that it's a Microsoft error…

                                Do you work for Microsoft? You see, I came to this forum in order to share with people some very strange findings, in order to get somebody interested in finding what is really going on, and not to get a write-off along the lines “It works on my computer!” If you don’t have interest in this problem, you don’t have to post to this thread, I thank you very much for looking into this.

                                Quote:

                                you should look deeper into your code

                                You have my code, above.

                                L 1 Reply Last reply
                                0
                                • L Lost User

                                  Yes, but it does not tell us anything much that helps to identify why it is not working. [edit] Removed redundant comment. [/edit]

                                  S Offline
                                  S Offline
                                  SMD111
                                  wrote on last edited by
                                  #20

                                  That is the question I wanted to get others interested in!

                                  1 Reply Last reply
                                  0
                                  • S SMD111

                                    I have included the essential code example with my original post. You are welcome to comment on it or let me know if I should give more details.

                                    L Offline
                                    L Offline
                                    Lost User
                                    wrote on last edited by
                                    #21

                                    Try your code again, but isolate it in a console-app. Have it fill the array, save it, and read it as the C# example I posted. Have it output the first byte. That way it should be easy to determine whether something is wrong with the code you posted, or whether it is going wrong in another place. If it is something in the QueryValueEx call, then it should be reproducable with a few lines of code.

                                    Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]

                                    1 Reply Last reply
                                    0
                                    • L Lost User

                                      That's why my example doesn't use the managed api. The dll will hardly care whether the calling code is in C, Delphi or managed. Or am I wrong on that concept? :rolleyes:

                                      Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]

                                      L Offline
                                      L Offline
                                      Lost User
                                      wrote on last edited by
                                      #22

                                      Eddy Vluggen wrote:

                                      Or am I wrong

                                      No, I think you are probably correct.

                                      1 Reply Last reply
                                      0
                                      • S SMD111

                                        Quote:

                                        You really need to do some serious debugging to find out why this is happening.

                                        Why do you assume I have not done “some serious debugging”? Please teach me how to debug a single RTL function call that does not generate an error.

                                        Quote:

                                        Rather than just assuming that it's a Microsoft error…

                                        Do you work for Microsoft? You see, I came to this forum in order to share with people some very strange findings, in order to get somebody interested in finding what is really going on, and not to get a write-off along the lines “It works on my computer!” If you don’t have interest in this problem, you don’t have to post to this thread, I thank you very much for looking into this.

                                        Quote:

                                        you should look deeper into your code

                                        You have my code, above.

                                        L Offline
                                        L Offline
                                        Lost User
                                        wrote on last edited by
                                        #23

                                        SMD111 wrote:

                                        Why do you assume I have not done “some serious debugging”?

                                        I assume nothing; I respond only to the information you have provided.

                                        SMD111 wrote:

                                        Do you work for Microsoft?

                                        No, but experience has taught me that in situations such as this it is most likely a user error.

                                        SMD111 wrote:

                                        If you don’t have interest in this problem

                                        I do have interest, which is why I wrote a program to try and identify why this situation occurs.

                                        SMD111 wrote:

                                        You have my code, above.

                                        Which, as I said elsewhere, tells us very little.

                                        1 Reply Last reply
                                        0
                                        • S SMD111

                                          Thank you for the code example. I cannot compile it because I use plain C, such as in Microsoft Windows Help (Win32 Online Help, version 1.00.178) or on MSDN pages, or such as this one: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911%28v=vs.85%29.aspx[^]

                                          L Offline
                                          L Offline
                                          Lost User
                                          wrote on last edited by
                                          #24

                                          SMD111 wrote:

                                          I cannot compile it because I use plain C,

                                          Download a compiler? Translating it to C would not help very much in proving that the api-call works as intended. Or in another wording, I'm simply trying to prove that SELECT is not broken. If I can prove that, then the error must be somewhere else in the code.

                                          Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]

                                          S 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