Unity3d(C#) 枚举串口名称

Unity3d中枚举串口名称的坑

一、Unity版本
我使用版本2017.f.3
5.6以后的Unity版本都不再采用32位模式,统一为64为模式。
使用.net 4.6框架才能使用System.IO.Ports
在这个框架下要枚举串口名称,有以下尝试。
使用System.Management.dll 均以失败告终,Unity读取不了该Dll,如有大神知晓,欢迎告知。
使用SetupApi,可行,但是仅能在32位下进行,选取折衷办法,输出为32位,即BuildSetting里面选择32位框架,输出的项目可行,但是直接编译器play不行。少废话,上代码。

// --------------------------------------------------------------------------------------------------------------------
// 
//   pp
// 
// 
//   Defines the Program type.
// 
// --------------------------------------------------------------------------------------------------------------------

namespace ConsoleAppCs
{
    using System;
    using System.Runtime.InteropServices;

    class Program
    {
        static void Main(string[] args)
        {
            SetupDiWrap.ComPortNameFromFriendlyNamePrefix("COM");
            Console.ReadKey();
        }
    }

    /// 
    /// The setup di wrap.
    /// 
    public class SetupDiWrap
    {
        public static  string ComPortNameFromFriendlyNamePrefix(string friendlyNamePrefix)
        {
            const string className = "Ports";
            Guid[] guids = GetClassGUIDs(className);
            
            System.Text.RegularExpressions.Regex friendlyNameToComPort =
                new System.Text.RegularExpressions.Regex(@".? \((COM\d+)\)$");  // "..... (COMxxx)" -> COMxxxx
            foreach (Guid guid in guids)
            {
                // We start at the "root" of the device tree and look for all
                // devices that match the interface GUID of a disk
                Guid guidClone = guid;
                IntPtr h = SetupDiGetClassDevs(ref guidClone, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_PROFILE);
                if (h.ToInt64() != INVALID_HANDLE_VALUE)
                {
                    int nDevice = 0;
                    while (true)
                    {
                        SP_DEVINFO_DATA da = new SP_DEVINFO_DATA();
                        da.cbSize = (uint)Marshal.SizeOf(da);
                        if (0 == SetupDiEnumDeviceInfo(h, nDevice++, ref da))
                        {
                            break;
                        }
                            
                        uint RegType;
                        byte[] ptrBuf = new byte[BUFFER_SIZE];
                        uint RequiredSize;
                        if (SetupDiGetDeviceRegistryProperty(h, ref da,
                            (uint)SPDRP.FRIENDLYNAME, out RegType, ptrBuf,
                            BUFFER_SIZE, out RequiredSize))
                        {
                            const int utf16terminatorSize_bytes = 2;
                            string friendlyName = System.Text.UnicodeEncoding.Unicode.GetString(ptrBuf, 0, (int)RequiredSize - utf16terminatorSize_bytes);
                            if (!friendlyName.StartsWith(friendlyNamePrefix))
                                continue;

                            if (!friendlyNameToComPort.IsMatch(friendlyName))
                                continue;

                            return friendlyNameToComPort.Match(friendlyName).Groups[1].Value;
                        }
                    } // devices
                    //SetupDiDestroyDeviceInfoList(h);
                }
            } // class guids

            return null;
        }

        /// 
        /// The SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set.
        /// 
        [StructLayout(LayoutKind.Sequential)]
        private struct SP_DEVINFO_DATA
        {
            /// Size of the structure, in bytes.
            public uint cbSize;
            /// GUID of the device interface class.
            public Guid ClassGuid;
            /// Handle to this device instance.
            public uint DevInst;
            /// Reserved; do not use.
            public uint Reserved;
        }

        const int BUFFER_SIZE = 1024;


        private enum SPDRP
        {
            FRIENDLYNAME = 0x0000000C,
        }

        [DllImport("setupapi.dll", SetLastError = true)]
        static extern bool SetupDiClassGuidsFromName(string ClassName,
                                                     ref Guid ClassGuidArray1stItem, UInt32 ClassGuidArraySize,
                                                     out UInt32 RequiredSize);

        [DllImport("setupapi.dll")]
        private static extern Int32 SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet,
                                                          Int32 MemberIndex, ref SP_DEVINFO_DATA DeviceInterfaceData);
 

        //p
        [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SetupDiGetClassDevs(           // 1st form using a ClassGUID only, with null Enumerator
            ref Guid ClassGuid,
            IntPtr Enumerator,
            IntPtr hwndParent,
            int Flags
        );

        /// 
        /// The SetupDiGetDeviceRegistryProperty function retrieves the specified device property.
        /// This handle is typically returned by the SetupDiGetClassDevs or SetupDiGetClassDevsEx function.
        /// 
        /// Handle to the device information set that contains the interface and its underlying device.
        /// Pointer to an SP_DEVINFO_DATA structure that defines the device instance.
        /// Device property to be retrieved. SEE MSDN
        /// Pointer to a variable that receives the registry data Type. This parameter can be NULL.
        /// Pointer to a buffer that receives the requested device property.
        /// Size of the buffer, in bytes.
        /// Pointer to a variable that receives the required buffer size, in bytes. This parameter can be NULL.
        /// If the function succeeds, the return value is nonzero.
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool SetupDiGetDeviceRegistryProperty(
            IntPtr DeviceInfoSet,
            ref SP_DEVINFO_DATA DeviceInfoData,
            uint Property,
            out UInt32 PropertyRegDataType,
            byte[] PropertyBuffer,
            uint PropertyBufferSize,
            out UInt32 RequiredSize);


        const int DIGCF_DEFAULT = 0x1;
        const int DIGCF_PRESENT = 0x2;
        const int DIGCF_ALLCLASSES = 0x4;
        const int DIGCF_PROFILE = 0x8;
        const int DIGCF_DEVICEINTERFACE = 0x10;
        const int INVALID_HANDLE_VALUE = -1;

        private static Guid[] GetClassGUIDs(string className)
        {
            UInt32 requiredSize = 0;
            Guid[] guidArray = new Guid[1];

            bool status = SetupDiClassGuidsFromName(className, ref guidArray[0], 1, out requiredSize);
            if (true == status)
            {
                if (1 < requiredSize)
                {
                    guidArray = new Guid[requiredSize];
                    SetupDiClassGuidsFromName(className, ref guidArray[0], requiredSize, out requiredSize);
                }
            }
            else
                throw new System.ComponentModel.Win32Exception();

            return guidArray;
        }
    }

}

这个方法会选择包含“string friendlyNamePrefix”的串口号,看官可自行替换。~


reference:https://stackoverflow.com/questions/2937585/how-to-open-a-serial-port-by-friendly-name/2937588#2937588

你可能感兴趣的:(Unity3d(C#) 枚举串口名称)