tags:

views:

276

answers:

4

I have a bit of a weird problem. I have a form with a Label in it for outputting text at certain points in the program instead of console output. Given the following code:

result = SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref tBuff, 
                                          (uint)SPDRP.DEVICEDESC,
                                          out RegType, ptrBuf, 
                                          buffersize, out RequiredSize); 

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();

    sw.WriteLine(tCode.GetString(ptrBuf) );

    sw.WriteLine("\n");
    // This is the only encoding that will give any legible output.
    // Others only show the first character "U"
    string tmp = tCode.GetString(ptrBuf) + "\n"; 

    statusLabel.Text += "\nDevice is: " + tmp + ".\n";                    
}

I get just the one hardware ID output on the label. This piece of code is at the end of my loop. at 1st this made me think that my loop was some how hanging, but when I decided to direct output to a file I get almost what I want and the output outside the loop. Can anyone tell me what's going on here? All I want is to get the string representing the hardware ID from the []byte (ptrBuf). Can some explain what's going on here, please? My working environment is MSVstudio 2008 express. In windows 7.

Thanks

+2  A: 

You need to specify an encoding:

// C# to convert a byte array to a string.
byte [] dBytes = ...
string str;
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
str = enc.GetString(dBytes);
Stormenet
If ASCII is indeed the right encoding (which I suspect it's not) it's simpler to use Encoding.ASCII than to create a new instance.
Jon Skeet
+1 to this comment, it is completely correct. As an aside, this is completely confusing and an odd choice on behalf of the Framework developers. You would not expect an object called *Encoding to, well, decode. You would think it would be a property of the array. Oh well, it works.
Serapth
Makes sense to me. I suppose you could call it ByteEncodingManager or something instead if you were fond of verbose names.
mquander
@Serapth: No, I wouldn't expect that at all. An Encoding is responsible for encoding and decoding, converting between character data and binary data. I certainly wouldn't expect the array to know how to do that. We also don't know this works...
Jon Skeet
@Jon. This I suppose is suppose where we disagree. I view encoding and decoding as completely seperate tasks and view an Encoder as being responsible for the Encoding process only. I suppose I agree regarding arrays, on further thought, If I was the framework designer, I would have put the functionality in System.Convert
Serapth
I don't think they're very separate; if you ever change how something is encoded, you will have to go make the "same" change to how it's decoded, and vice versa.
mquander
In this case, the term Encoding refers to the "encoding scheme". Note that the class isn't called "Encoder" - it's called "Encoding" because it represents a particular encoding scheme.
Dave Cluderay
They're *somewhat* separate, which is why the Encoder and Decoder classes are distinct. However, the concept of an *Encoding* is one concept. You don't talk about "UTF-8 encoding" and "UTF-8 decoding" separately, do you?
Jon Skeet
@Jon I know the ASCII encoding could be the wrong encoding, but this is a google "byte array to string c#" question, so I like to only set the poster on the right path and make him think :)
Stormenet
+2  A: 

You haven't shown what tCode is, unfortunately.

Looking at the docs for the API call it looks like it should be populated with a REG_SZ. I suspect that's Unicode, i.e.

string property = Encoding.Unicode.GetString(ptrBuf, 0, RequiredSize);

should convert it.

However, if you're expecting multiple values, I wonder if it's a '\0'-separated string: trying to output that in a Win32 control will indeed stop at the first '\0'.

Try this:

string property = Encoding.Unicode.GetString(ptrBuf, 0, RequiredSize);
                                  .Replace('\0', ' ');

That should (if I'm guessing correctly) space-separate the values.

Jon Skeet
If the intention was to pass SPDRP_HARDWAREID instead of SPDRP_DEVICEDESC, then this is certainly true because that property is a 'REG_MULTI_SZ'.
Dave Cluderay
Yes, that would make a lot of sense.
Jon Skeet
I'm only mentioning this now for people who have the same problem. The issue was that Win32 control was indeed stopping at the first '\0' hence the reason why I was getting the full output in the text file.
Dark Star1
A: 

You cannot implicitly convert a byte to a string. You must choose an encoding method (perhaps Unicode or ASCII) for the conversion. A byte stores a numerical value which can represent a character (or some other data), but inherently does not mean anything. It is the philosophical equivalent to converting an integer to a string. You can decide to do a direct conversion of the value or you can derive some meaning from the value (i.e. using an ASCII table: 13 = TAB).

The value being returned by the function you listed most likely returned a byte array that represents some string value, however it is up to you to find the relevant encoding method to convert it to a usable string.

Hope that helped!

Eric

Eric
+1  A: 

sorry I should've said. UnicodeEncoding tCode = new UnicodeEncoding(); and thanks skeet, I didn't know about that little info on Win32 controls. I'll make an effort to correct for that. I wasn't implicitly trying to convert the bytes into characters (or strings). I'll make an effort to be more detailed in the future.

Thanks all for replying.

Dark Star1