Thread: Extracting data from byte buffers

  1. #1
    Tha 1 Sick RAT
    Join Date
    Dec 2003
    Posts
    271

    Extracting data from byte buffers

    Hello. This is a P/Invoke question which, quite frankly is doing my head in.

    I need to get a string from a []byte because calling the object.Tostring() methond on he variable doesn't yield the correct information.

    given the following (which was extracted from p/invoke.net:

    Code:
    public static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData,
                                                                       uint Property, out uint PropertyRegDataType,
                                                                      byte[] PropertyBuffer, uint PropertyBufferSize,
                                                                       out uint RequiredSize);
    
    result = SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref tBuff, (uint)SPDRP.HARDWAREID, out RegType, null, 0, out RequiredSize);
                    
    ptrBuf = new byte[RequiredSize];
    buffersize = RequiredSize;
    
    result = SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref tBuff, (uint)SPDRP.HARDWAREID, out RegType, ptrBuf, buffersize, out RequiredSize);
    I need to retrieve the string returned in that variable but unfortunately the closest thing/way I know of doesn't work: string tmp = Marshal.PtrToStringAuto(ptrBuf) although this is the way it's used in the p/invoke.net example.
    Can anyone put a sign post up pointing me in the right direction pls? At the moment I'm reading through several MarshalAs texts but to be honest for such a simple thing, I don't want to over-complicate the task at hand by getting into convoluted code(s).

    Thank you very much.
    A hundred Elephants can knock down the walls of a fortress... One diseased rat can kill everyone inside

  2. #2
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Code:
    System.Text.Encoding.UTF8.GetString(ptrBuf);
    Assuming the string is encoded as utf8 (there are others to use as well).
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  3. #3
    Tha 1 Sick RAT
    Join Date
    Dec 2003
    Posts
    271
    Thanks Magos for that sliver of light in the grey clouds. Now it's turned out to be a laser light. Burning through
    It worked just fine except that it now seems to hang my loop after displaying the string:
    Code:
    if (!result)
                    {
                        errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
                        statusLabel.Text += "\nSetupDiGetDeviceRegistryProperty failed because " + errorMessage.ToString();
                    }
                    else
                    {
                        string tmp = Encoding.Unicode.GetString(ptrBuf);
    
                        statusLabel.Text += "\nDevice is: " + tmp + ".\n";
                    }
    That's the I have a problem with. I honestly don't know what's going on here. I can actually output anything before that highlighted variable but nothing after. Trying other encodings give me different outputs. With UTF32 I get junk but my loop works fine. With others I get just the 1st letter and it stops (seemingly hangs I presume) I don't get to the output marker I have outside the loop.
    A hundred Elephants can knock down the walls of a fortress... One diseased rat can kill everyone inside

  4. #4
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    SetupDiGetDeviceRegistryProperty is not an actual function - it's a #define to one of SetupDiGetDeviceRegistryPropertyA or SetupDiGetDeviceRegistryPropertyW. I'm wondering if the Unicode-ness of the function is biting you. The result might be in ASCII or UTF-16.
    (Although the function doesn't exist, P/Invoke will choose one for you... depending on Unicode settings for the app. I suspect it's choosing the W one.)

    You could try outputting the contents of the byte array, as if they where ASCII, which exceptions for nulls:
    Code:
    foreach(byte b in ptrBuf)
    {
        Console.Write("{0} ", b == 0 ? "\0" : Char.ConvertFromUtf32(b));
    }
    Then, from whatever that outputs, deduct the encoding. ASCII would look something like:
    Code:
    H e l l o   W o r l d.
    Whereas UTF-16 would look like:
    Code:
    H \0 e \0 l \0 l \0   \0 W \0...
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  5. #5
    Tha 1 Sick RAT
    Join Date
    Dec 2003
    Posts
    271
    Thank you very much for that piece of information. I never thought it'd be this hard just to extract a string form a byte buffer. However the problem is still ongoing. Given theoutput from your piece of code It looks like it's ascii. But I now have a weird behaviour on going. Or at least I think I'm now seeing what has been going on in the background. I decided to modify that section of code again to watch the output to console and the output to the windows control in my form, both of which have different outputs. Here's the section of code:
    Code:
                    if (!result)
                    {
                        errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
                        statusLabel.Text += "\nSetupDiGetDeviceRegistryProperty failed because " + errorMessage.ToString();
                    }
                    else
                    {
                        statusLabel.Text += "\nPtr buffer length is: " + ptrBuf.Length.ToString();
    
                        foreach (byte b in ptrBuf)
                            sw.Write("{0} ", b == 0 ? "\0" : Char.ConvertFromUtf32(b));
    
                        sw.WriteLine("\n");
                        string tmp = Encoding.Unicode.GetString(ptrBuf); //This is the only encoding that will give any legible output. Others only show the first character "U"
                    
                        statusLabel.Text += "\nDevice is: " + tmp + ".\n";                    
                    }
    sw happens to be a stream writer to a file. For purposes of posting the output to console here:
    Code:
    U   S   B   \   R   O   O   T   _   H   U   B   &   V   I   D   1   0   D   E   &   P   I   D   0   2   6   D   &   R   E   V   0   0   A   3       U   S   B   \   R   O   O   T   _   H   U   B   &   V   I   D   1   0   D   E   &   P   I   D   0   2   6   D       U   S   B   \   R   O   O   T   _   H   U   B           
    
    U   S   B   \   R   O   O   T   _   H   U   B   2   0   &   V   I   D   1   0   D   E   &   P   I   D   0   2   6   E   &   R   E   V   0   0   A   3       U   S   B   \   R   O   O   T   _   H   U   B   2   0   &   V   I   D   1   0   D   E   &   P   I   D   0   2   6   E       U   S   B   \   R   O   O   T   _   H   U   B   2   0           
    
    U   S   B   \   V   I   D   _   0   5   5   6   &   P   I   D   _   0   0   0   1   &   R   E   V   _   0   0   0   1       U   S   B   \   V   I   D   _   0   5   5   6   &   P   I   D   _   0   0   0   1           
    
    U   S   B   \   V   I   D   _   0   5   5   6   &   P   I   D   _   0   0   0   1   &   R   E   V   _   0   0   0   1   &   M   I   _   0   0       U   S   B   \   V   I   D   _   0   5   5   6   &   P   I   D   _   0   0   0   1   &   M   I   _   0   0           
    
    U   S   B   \   V   I   D   _   0   5   A   C   &   P   I   D   _   0   2   2   1   &   R   E   V   _   0   0   6   7       U   S   B   \   V   I   D   _   0   5   A   C   &   P   I   D   _   0   2   2   1           
    
    U   S   B   \   V   I   D   _   0   5   A   C   &   P   I   D   _   0   2   2   1   &   R   E   V   _   0   0   6   7   &   M   I   _   0   0       U   S   B   \   V   I   D   _   0   5   A   C   &   P   I   D   _   0   2   2   1   &   M   I   _   0   0           
    
    U   S   B   \   V   I   D   _   0   5   A   C   &   P   I   D   _   0   2   2   1   &   R   E   V   _   0   0   6   7   &   M   I   _   0   1       U   S   B   \   V   I   D   _   0   5   A   C   &   P   I   D   _   0   2   2   1   &   M   I   _   0   1           
    
    U   S   B   \   V   I   D   _   0   5   A   C   &   P   I   D   _   1   0   0   6   &   R   E   V   _   9   4   1   5       U   S   B   \
    (Sorry about that. I hate long postings myself)
    the output in statusLabel is:
    Code:
    Ptr buffer Length is: 160
    Device is: USB\ROOT_HUBVID10DEPID026DREV00A3
    I think you're right cactus however I don't know how to remedy this at the moment.
    On one hand it would seem I was wrong and the loop actually ends normally as expected (the posted code sits at the end of a for loop) but looking at the windows form output says different. Any ideas?
    A hundred Elephants can knock down the walls of a fortress... One diseased rat can kill everyone inside

  6. #6
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    Code:
    // This is the only encoding that will give any legible output. Others only show the first character "U"
    string tmp = Encoding.Unicode.GetString(ptrBuf);
    The poorly-named "Unicode" property of the Encoding class is a UTF-16 decoder. It's the one that works because your data is indeed in UTF-16.

    We can tell this from the output that my little segment of code gives.
    Code:
    sw.Write("{0} ", b == 0 ? "\0" : Char.ConvertFromUtf32(b));
    That outputs each by as if it were an ASCII character (unless above 127) or a '\0' if it is a null. Unfortunately, I made a small error -- the part in blue should be "\\0". The important thing is that each byte is followed by 1 space, but in the output, we see three, oddly. (I'm guessing the null got output somehow, and converted to a space.)

    There's still the matter that your DllImport attribute on SetupDiGetDeviceRegistryProperty might be selecting automatically. This might fail on systems where is selects ASCII (WinMe and down, but those are pretty unsupported nowadays. This might be a non-issue.) Read http://msdn.microsoft.com/en-us/library/7b93s42f.aspx for more info on character sets.
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  7. #7
    Tha 1 Sick RAT
    Join Date
    Dec 2003
    Posts
    271
    Thanks. I wasn't having a problem with the output to file using Unicode encoding (I "fixed it" by outputting the string that was to go to my win32 control), just the Output to the Win32 control.
    After asking around I found out that Win32 control stop recieving input after encountering the first null character. So I just replaced every null in the string with something else
    Last edited by WDT; 05-15-2009 at 08:20 AM.
    A hundred Elephants can knock down the walls of a fortress... One diseased rat can kill everyone inside

  8. #8
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    Quote Originally Posted by WDT View Post
    Thanks. I wasn't having a problem with the output to file using Unicode encoding (I "fixed it" by outputting the string that was to go to my win32 control), just the Output to the Win32 control.
    What? English, please. Are you saying that instead of doing: string --> file, you're doing string --> control --> file?

    Quote Originally Posted by WDT View Post
    After asking around I found out that Win32 control stop recieving input after encountering the first null character. So I just replaced every null in the string with something else
    This statement worries me that you do not fully understand what is going on in your program. The above string, from what I can see here, had no nulls, except for the trailing one at the end - if you interpret it as UTF-16.
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  9. #9
    Tha 1 Sick RAT
    Join Date
    Dec 2003
    Posts
    271
    I meant I wasn't having any problems out putting the resulting strings to file. Just to the Win32 control.

    The above string has multiple nulls as the function returns an array of null terminated strings that itself is terminated by 2 consecutive nulls... The original problem was I was getting two different outputs. The output to Win32 control was just one string where as my output to file contained all the data I requested. Once I found out that win32 controls stop at the first null I just simply replaced all the nulls in my string.
    A hundred Elephants can knock down the walls of a fortress... One diseased rat can kill everyone inside

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Extracting data from a laptop hard drive
    By DavidP in forum Tech Board
    Replies: 6
    Last Post: 06-13-2009, 07:02 AM
  2. BYTE, char data corruption
    By Denethor2000 in forum C++ Programming
    Replies: 45
    Last Post: 11-12-2005, 06:39 PM
  3. Binary Tree, couple questions
    By scoobasean in forum C Programming
    Replies: 3
    Last Post: 03-12-2005, 09:09 PM
  4. error: identifier "byte" is undefined.
    By Hulag in forum C++ Programming
    Replies: 4
    Last Post: 12-10-2003, 05:46 PM
  5. C diamonds and perls :°)
    By Carlos in forum A Brief History of Cprogramming.com
    Replies: 7
    Last Post: 05-16-2003, 10:19 PM