"It was a blazing hot day in August. Baker Street was like an oven, and the glare of the sunlight upon the yellow brickwork of the house across the road was painful to the eye. It was hard to believe that these were the same walls which loomed so gloomily through the fogs of winter." I don't live in Baker Street actually, but the weather here has been similar to Watson's description from Sir Arthur Conan Doyle's The Adventure Of The Cardboard Box, collected in His Last Bow. Excellent reading for when it's too hot to do anything that requires more than turning a page now and then. Fortunately, like Holmes in the story, there's also been some time for me to do an investigation.
I'm still working on software related to the serial communications described in my previous post and when testing I ran into something strange. The drivers that come with the 3Com 3CREB96B Bluetooth device add some entries to the hkey_local_machine\hardware\devicemap\serialcomm key. Basically a bunch of virtual serial ports. In turn, I enumerate the entries in this key to find the available serial ports for use in my application. I use Microsoft.Win32.Registry.LocalMachine.OpenSubKey to get a RegistryKey object and then query it using its GetValues and GetValue methods.
Nothing out of the ordinary so far. However, on one of the machines that was tested on, the Bluetooth's drivers' COM3 to COM7 showed up all with a 0 suffixed, i.e. COM30 to COM70. When looking closer I discovered that this behaviour is related to the order that values are returned from the registry: if there was a COM10 returned before the 3Com values, the problem would occur. If there was a COM100 (created to see if my assumption was correct) the values would come back as COM300 to COM700.
So then I had a look at the registry. It turns out the values inserted by the 3Com driver are not zero-terminated. So what's probably happening is that in the Win32-implementation of the .NET registry API I'm using, the buffer to hold values coming out of the registry is reused and there are no zero-terminator checks (or not correct ones anyway). I'm not sure if it's appropriate to do those checks there though so I'm not saying that's a bug. However, when looking at the Win32 documentation for writing to the registry, I noticed that going from the original RegSetValue to the new RegSetValueEx function, cbData's requirement for including the terminator in the length has changed (in the former it should be excluded and in the latter included). Perhaps someone at 3Com has been a bit sloppy porting from the old to the new?
One of the things I'm very excited about in the 2.0 release of the .NET Framework is the new System.IO.Ports.SerialPort class. I have to deal with serial communications a lot and right now I'm using my own implementation, which is about 600 lines of c# (350 lines of actual code and 250 lines of P/Invoke declarations).
What surprised me the most when testing the Whidbey SerialPort is that it appears to work well with virtual COM-ports. I had a lot of problems opening these ports exposed by Bluetooth and IrDA serial drivers: for instance, 3Com's bluetooth USB device comes with a bunch of software, including a virtual serial port application. The software creates a COM10 and COM11 for this purpose (on my machine at least, numbers will probably vary), but whenever I attempted to call CreateFile on one of these names I'd receive a file not found error. Some other software I tried that should normally work with serial ports didn't either, except for one application that somehow managed to work with every type of virtual or real serial port I threw at it: hyperterminal.
I ended up using API Monitor to find out that instead of opening "COM10", hyperterminal actually uses the string "\\.\COM10" when opening the port. By that time I had tried just about everything, so I decided to prefix all devicename strings used in CreateFile calls with "\\.\" and voila, works like a charm! Later on I found the entry describing this in the Platform SDK documentation ofcourse, but by that time I had already spent way too much time figuring it out. The main reason I didn't expect the issue to be related to the devicename string itself was because none of the sample code using the serial port I was using as references used this notation. Goes to show that you shouldn't depend on examples as documentation.
So besides being happy that I can shortly use an implementation created by people that are closer to the inner workings of it all, I'm also happy with the design: exposing the serial port as a stream will make it very easy to integrate with existing code!