2011-03-12 30 views

回答

2

这是1〜255最快的,你可以做到这一点是使用QueryDosDevice这样

Option Explicit 

'--- for CreateFile 
Private Const GENERIC_READ     As Long = &H80000000 
Private Const GENERIC_WRITE     As Long = &H40000000 
Private Const OPEN_EXISTING     As Long = 3 
Private Const INVALID_HANDLE_VALUE   As Long = -1 
'--- error codes 
Private Const ERROR_ACCESS_DENIED   As Long = 5& 
Private Const ERROR_GEN_FAILURE    As Long = 31& 
Private Const ERROR_SHARING_VIOLATION  As Long = 32& 
Private Const ERROR_SEM_TIMEOUT    As Long = 121& 

Private Declare Function QueryDosDevice Lib "kernel32" Alias "QueryDosDeviceA" (ByVal lpDeviceName As Long, ByVal lpTargetPath As String, ByVal ucchMax As Long) As Long 
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long 
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long 

Private Function PrintError(sFunc As String) 
    Debug.Print sFunc; ": "; Error 
End Function 

Public Function IsNT() As Boolean 
    IsNT = True 
End Function 

Public Function EnumSerialPorts() As Variant 
    Const FUNC_NAME  As String = "EnumSerialPorts" 
    Dim sBuffer   As String 
    Dim lIdx   As Long 
    Dim hFile   As Long 
    Dim vRet   As Variant 
    Dim lCount   As Long 

    On Error GoTo EH 
    ReDim vRet(0 To 255) As Variant 
    If IsNT Then 
     sBuffer = String$(100000, 1) 
     Call QueryDosDevice(0, sBuffer, Len(sBuffer)) 
     sBuffer = Chr$(0) & sBuffer 
     For lIdx = 1 To 255 
      If InStr(1, sBuffer, Chr$(0) & "COM" & lIdx & Chr$(0), vbTextCompare) > 0 Then 
       vRet(lCount) = "COM" & lIdx 
       lCount = lCount + 1 
      End If 
     Next 
    Else 
     For lIdx = 1 To 255 
      hFile = CreateFile("COM" & lIdx, GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0) 
      If hFile = INVALID_HANDLE_VALUE Then 
       Select Case Err.LastDllError 
       Case ERROR_ACCESS_DENIED, ERROR_GEN_FAILURE, ERROR_SHARING_VIOLATION, ERROR_SEM_TIMEOUT 
        hFile = 0 
       End Select 
      Else 
       Call CloseHandle(hFile) 
       hFile = 0 
      End If 
      If hFile = 0 Then 
       vRet(lCount) = "COM" & lIdx 
       lCount = lCount + 1 
      End If 
     Next 
    End If 
    If lCount = 0 Then 
     EnumSerialPorts = Split(vbNullString) 
    Else 
     ReDim Preserve vRet(0 To lCount - 1) As Variant 
     EnumSerialPorts = vRet 
    End If 
    Exit Function 
EH: 
    PrintError FUNC_NAME 
    Resume Next 
End Function 

的片段回落到CreateFile在Windows 9x。为简洁起见,函数被stubbed。

+0

我如何获得COM的名称?你的脚本只列出了没有名字的可用COM端口。 – 2016-05-21 04:16:23

+0

这不是一个脚本。 OP没有请求COM端口“名称”。如果您需要关于该主题的更多指导,请另外提问。 – wqw 2016-05-21 12:21:36

+0

对于Windows 10下的VSP不起作用 – zax 2017-07-24 21:54:50

3

我相信在现代Windows环境下,你可以在注册表中找到它们,下面的键HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM。我不确定指定注册表项的正确方法。不过,我只有在Windows XP上测试过它。