locked
IO.Ports.SerialPort.GetPortNames / RegistryKey.GetValue corruption with usbser.sys driver on Windows 10 RRS feed

  • Question

  • Using Windows 10 with a USB CDC serial device and the usbser.sys driver, a call to IO.Ports.SerialPort.GetPortNames() will more often than not have a random extra character on the end of the serial port's name.

    Requirements:

    • Windows 10 (I've tried 64-bit professional and 32-bit home)
    • A USB CDC serial device.  In my case, it is a Microchip PIC32MX695F512H microprocessor, that I've written the firmware for, using Microchip-provided code for the USB device.
    • Windows 10's usbser.sys driver

    Our device's USB descriptor includes the following, which allows automatic use of the usbser.sys driver:

    • Class Code: CDC_DEVICE
    • Subclass: 2
    • Protocol: 0

    The screenshot below shows Device Manager with the correct port name, and my testing program using different methods to read the available serial port names.  It should be saying "COM3", but this is what I get:

    

    The problem initially seemed to be with GetPortNames(), however I found the source code for that routine and manually compiled and stepped through it.  The problem is when it comes to reading values out of the registry.  Other things I've noticed are:

    • Other registry reads are OK (e.g. the "ColourName" one in the example above)
    • Reads of the serial port name key are corrupted.  These, I assume, are provided by the usbser.sys driver.
    • Looking at the same registry key with regedit.exe works correctly.
    • The random character appears at least 80% of the time, is always at the end of the string, and is only ever a single character.
    • The random character can be anything.  Letters, Chinese characters, or (worst of all) digits.
    • Repeated calls will often (but not always) vary presence and value of the junk characters.
    • The call to SerialPort.Open() needs the correct port name.  Using the corrupted one doesn't work.
    • The problem occurs on every Windows 10 I have tested it on over the last 6 monts, on two real PCs, and a VirtualBox VM.
    • The C:\Windows\System32\drivers\usbser.sys file is dated 30 October 2015, version 10.0.10586.0
    • The same program runs OK on Windows XP, 7 and 8.
    • I have tried various versions of .NET as well (2.0, 3.0 and 3.5).
    • FTDI and Prolific USB-serial adapters are OK (they don't use usbser.sys, though).
    • Fresh install of Windows 10, with all Windows Updates applied (as of 10 December 2015), .NET framework installed, my app, and nothing else.
    • The usbser.sys driver was rewritten for Windows 10, and this is the first version of Windows that has this problem.

    The shortest snippet of code to demonstrate the problem is:

    RegistryKey k2 = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DEVICEMAP\SERIALCOMM");
    string corrupt = (string)k2.GetValue(@"\Device\USBSER000"); // more often than not, will have extra characters on the end
    System.Diagnostics.Debug.Print(corrupt);

    I reported the problem some time ago through the Windows 10 Preview's built-in bug reporting app, but I haven't heard anything back.

    This is a major problem for our product, as our hardware uses the usbser.sys driver, and our C# program needs to find out which ports are present, before it connects to it.

    So, my questions are:

    • Am I doing something stupid, and just need to change/do something to fix it?
    • Otherwise, is there any way to escalate this to get it fixed?
    • If this isn't the right forum to ask in, where should I take this issue?
    • Does anyone have any clever ideas to work around the problem, or other words of wisdom?

    A ZIP file with source and compiled EXE is available here: https://www.dropbox.com/s/yvixzzhldm6eygr/PortList.zip?dl=0

    Let me know if I can provide and more information, or try anything.  Christmas holidays allowing, I'll do whatever I can to work towards a fix or workaround for this problem.

    Thanks!
     - Steve.





    • Edited by sstteevvee1 Thursday, December 10, 2015 4:38 AM
    Thursday, December 10, 2015 4:12 AM

Answers

  • Lost the link to original article I'd like to link, but the following provides similar information.

    https://msdn.microsoft.com/en-us/library/windows/hardware/jj649944%28v=vs.85%29.aspx

    Together with the following key:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\serenum\Enum


    • Edited by cheong00Editor Tuesday, December 15, 2015 7:10 AM
    • Marked as answer by sstteevvee1 Monday, January 11, 2016 3:15 AM
    Tuesday, December 15, 2015 7:10 AM
    Answerer
  • Hi Everyone,

    Thanks for your suggestions, and patience in waiting for me to get back from my holidays.

    I'm pleased to report that using the usbser\Enum and Device Parameters\Portname registry keys from C# have been a success!

    Here is the new function I'm using.  Initial tests on Windows XP, 7 and 10 all worked.


     /// <summary>
            /// Get a list of attached usbser COM ports.  Note that this does not return all serial ports on the machine.
            /// </summary>
            private static string[] GetUsbSerDevices()
            {
                // HKLM\SYSTEM\CurrentControlSet\services\usbser\Enum -> Device IDs of what is plugged in
                // HKLM\SYSTEM\CurrentControlSet\Enum\{Device_ID}\Device Parameters\PortName -> COM port name.

                List<string> ports = new List<string>();

                RegistryKey k1 = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\services\usbser\Enum");
                if (k1 == null)
                {
                    Debug.Fail("Unable to open Enum key");
                }
                else
                {
                    int count = (int)k1.GetValue("Count");
                    for (int i = 0; i < count; i++)
                    {
                        object deviceID = k1.GetValue(i.ToString("D", CultureInfo.InvariantCulture));
                        Debug.Assert(deviceID != null && deviceID is string);
                        RegistryKey k2 = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum\" + (string)deviceID + @"\Device Parameters");
                        if (k2 == null)
                        {
                            continue;
                        }
                        object portName = k2.GetValue("PortName");
                        Debug.Assert(portName != null && portName is string);
                        ports.Add((string)portName);
                    }
                }
                return ports.ToArray();
            }

    Thanks again, everyone.  Until the original bug is fixed in Windows 10, this seems to be a good workaround that works on all the versions of Windows that our software is used on.

    - Steve.


    • Edited by sstteevvee1 Monday, January 11, 2016 3:17 AM
    • Marked as answer by sstteevvee1 Wednesday, January 13, 2016 5:38 AM
    Monday, January 11, 2016 3:15 AM

All replies

  • win10 is breaking stuffs left and right, if u browse that forum 

    https://social.technet.microsoft.com/Forums/en-US/home?forum=win10itprogeneral

    ppl already found out certain .Net ver is broken on win10

    if u can consistently reproduce this issue on more than 1 pc with about same setup, post this to m$ connect to report the bug

    Thursday, December 10, 2015 6:00 AM
  • If the name is always COM port, you can try to get the first 4 chars from the value as your name be passed to SerialPort.Open(), and if the string is longer than 4, use Char.IsDigit(corrupt[4]) to check whether it's numeric and append to the 4 char string gathered as workaround.

    Say:

    corrupt = corrupt.Length > 3 ? String.Format("{0}{1}", corrupt.SubString(0,4), ((corrupt.Length > 4) && Char.IsDigit(corrupt[4])) ? corrupt[4] : String.Empty) : String.Empty;

    Btw, have you tried to take a look in Enum hive as suggested in here and see if the name is also corrupted?

    EDIT: Please use the method provided in this blog post to report the problem if it affects you, so Microsoft can know what to do to fix it.
    Friday, December 11, 2015 2:13 AM
    Answerer
  • Hi Steve,

    >>Otherwise, is there any way to escalate this to get it fixed?

    Based on your description, I think you have already to report this bug to Microsoft. The only thing we can do is waiting for the Product team to fix it. There might be some time delay. Appreciate your patience and thanks for your understanding.Now If your issue is very urgent, I would suggest you to open one phone support ticket, but this is a paid service.

    Phone support channel: https://msdn.microsoft.com/en-us/library/bb266240.aspx

    Have a nice day!

    Kristin


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Friday, December 11, 2015 2:49 AM
  • Thanks for your suggestions.

    Can you check the link to the Enum hive?  It seems to come back to this page.

    That blog post is helpful, I'll definitely follow that up and report the problem that way.

    I think your workaround will help somewhat, but it will still fail if the random character is a digit, which happens fairly often. e.g. "COM44" instead of "COM4", and may also have problems if the computer has got into two (or three) digit COM ports.  (One machine at our office is up to COM230).

    Tuesday, December 15, 2015 6:10 AM
  • Lost the link to original article I'd like to link, but the following provides similar information.

    https://msdn.microsoft.com/en-us/library/windows/hardware/jj649944%28v=vs.85%29.aspx

    Together with the following key:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\serenum\Enum


    • Edited by cheong00Editor Tuesday, December 15, 2015 7:10 AM
    • Marked as answer by sstteevvee1 Monday, January 11, 2016 3:15 AM
    Tuesday, December 15, 2015 7:10 AM
    Answerer
  • This looks really promising!

    By using HKLM\SYSTEM\CurrentControlSet\services\usbser\Enum, I can see the device IDs of what is plugged in, and then from HKLM\SYSTEM\CurrentControlSet\Enum\{Device_ID}\Device Parameters\PortName I can find out the COM port name.

    It probably won't be until January that I get a chance to try this out, but I'll report back then.  Hopefully neither of those two keys have problems being read in .NET.

    Thursday, December 17, 2015 3:11 AM
  • Hi Steve,

    What's the problem now? Do you have any updates?


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, December 22, 2015 1:53 AM
  • Still have a few weeks to go though, as the followup is expected to wait until January.
    Tuesday, December 22, 2015 2:23 AM
    Answerer
  • Hi Everyone,

    Thanks for your suggestions, and patience in waiting for me to get back from my holidays.

    I'm pleased to report that using the usbser\Enum and Device Parameters\Portname registry keys from C# have been a success!

    Here is the new function I'm using.  Initial tests on Windows XP, 7 and 10 all worked.


     /// <summary>
            /// Get a list of attached usbser COM ports.  Note that this does not return all serial ports on the machine.
            /// </summary>
            private static string[] GetUsbSerDevices()
            {
                // HKLM\SYSTEM\CurrentControlSet\services\usbser\Enum -> Device IDs of what is plugged in
                // HKLM\SYSTEM\CurrentControlSet\Enum\{Device_ID}\Device Parameters\PortName -> COM port name.

                List<string> ports = new List<string>();

                RegistryKey k1 = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\services\usbser\Enum");
                if (k1 == null)
                {
                    Debug.Fail("Unable to open Enum key");
                }
                else
                {
                    int count = (int)k1.GetValue("Count");
                    for (int i = 0; i < count; i++)
                    {
                        object deviceID = k1.GetValue(i.ToString("D", CultureInfo.InvariantCulture));
                        Debug.Assert(deviceID != null && deviceID is string);
                        RegistryKey k2 = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum\" + (string)deviceID + @"\Device Parameters");
                        if (k2 == null)
                        {
                            continue;
                        }
                        object portName = k2.GetValue("PortName");
                        Debug.Assert(portName != null && portName is string);
                        ports.Add((string)portName);
                    }
                }
                return ports.ToArray();
            }

    Thanks again, everyone.  Until the original bug is fixed in Windows 10, this seems to be a good workaround that works on all the versions of Windows that our software is used on.

    - Steve.


    • Edited by sstteevvee1 Monday, January 11, 2016 3:17 AM
    • Marked as answer by sstteevvee1 Wednesday, January 13, 2016 5:38 AM
    Monday, January 11, 2016 3:15 AM