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