2011-03-12 64 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上測試過它。