Q:

Finding USB serial ports from a .NET application under Windows 7

I have an application that looks for a specific FTDI serial port with customised USB descriptors. My current code uses the example from Code Project, which searches the MSSerial_PortName WMI table under root\WMI, and pulls out extra USB information from root\CIMV2\WIN32_PnPEntity.
This worked well under XP, but the application must also run under a standard user onWindows 7. In this environment access of root\WMI results in an "Access Denied" ManagementException.
Can anybody suggest a way to cross reference the DOS device name of a serial port to the USB information, while running as a standard user? So far I've looked at the root\CIMV2\WIN32_SerialPort* tables, but they only contain motherboard ports. I've also considered using SetupAPI, but I haven't found a complete and working PInvoke template for this.

A:

I've discovered an answer suitable for our case, though not a generic one. Our USB converters are all FTDI, and FTDI provide a DLL that handles this. My code using the DLL is below:
UInt32 count = 0;
FTDI.FT_STATUS status = ftdi.GetNumberOfDevices(ref count);
if (status != FTDI.FT_STATUS.FT_OK)
{
    log.Warn("Unable to access FTDI");
    return ports;
}
FTDI.FT_DEVICE_INFO_NODE[] list = new FTDI.FT_DEVICE_INFO_NODE[count];
status = ftdi.GetDeviceList(list);
if (status != FTDI.FT_STATUS.FT_OK)
{
    log.Warn("Unable to access FTDI");
    return ports;
}
foreach (FTDI.FT_DEVICE_INFO_NODE node in list)
{
    if ((status = ftdi.OpenByLocation(node.LocId)) == FTDI.FT_STATUS.FT_OK)
    {
        try
        {
            string comport;
            ftdi.GetCOMPort(out comport);
            ports.Add(new Port(comport, node.Description, node.SerialNumber));
        }
        finally
        {
            ftdi.Close();
        }
    }
}

A:

This looks promising. 
From the FDTI site on can download the application "Reassign COMNo Utility". This application shows on all Windows platforms which FTDI device is available. It helps a lot to check which FDTI devices are available.
When I tried to use your code within my own applications I discovered that I had some issues with getting it up an running. If possible extend your code so anybody can use it as an sample project without any struggle to get it compiled first.
But still a great contribution.
Thanks.
Below the sample code that worked for me.
using FTD2XX_NET;
private List<FDTIPort> FindFdtiUsbDevices()
    {
    ///////////////////////
    // Requires 
    // FTD2XX_NET.dll
    ///////////////////////

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

    FTDI _ftdi = new FTDI();

    UInt32 count = 0;
    FTDI.FT_STATUS status = _ftdi.GetNumberOfDevices(ref count);
    if (status != FTDI.FT_STATUS.FT_OK)
    {
        Console.WriteLine("log.Warn: Unable to access FTDI");
        return ports;
    }

    FTDI.FT_DEVICE_INFO_NODE[] list = new FTDI.FT_DEVICE_INFO_NODE[count];
    status = _ftdi.GetDeviceList(list);
    if (status != FTDI.FT_STATUS.FT_OK)
    {
        Console.WriteLine("log.Warn: Unable to access FTDI");
        return ports;
    }

    foreach (FTDI.FT_DEVICE_INFO_NODE node in list)
    {
        if ((status = _ftdi.OpenByLocation(node.LocId)) == FTDI.FT_STATUS.FT_OK)
        {
            try
            {
                string comport;
                _ftdi.GetCOMPort(out comport);

                if (comport != null && comport.Length > 0)
                {
                    ports.Add(new FDTIPort(comport, node.Description.ToString(), node.SerialNumber.ToString()));
                }
             }
             finally
             {
                 _ftdi.Close();
             }
        }
    }

    _ftdi.Dispose();
    return ports;
}

public class FDTIPort
{
     private string _nodeComportName = "";
     private string _nodeDescription = "";
     private string _nodeSerialNumber = "";

    // Constructor
    public FDTIPort()
    {
        _nodeComportName = "";
        _nodeDescription = "";
        _nodeSerialNumber = "";
    }
    // Constructor

    public FDTIPort ( string nodeComportName, string nodeDescription, string nodeSerialNumber )
    {
        _nodeComportName = nodeComportName;
        _nodeDescription = nodeDescription;
        _nodeSerialNumber = nodeSerialNumber;
    }

    public string nodeComportName {
        get { return this._nodeComportName; }
    }

    public string nodeDescription
    {
        get { return this._nodeDescription; }
    }

    public string nodeSerialNumber
    {
        get { return this._nodeSerialNumber; }
    }

}

