Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как нормальным кодом получить список всех модемов и COM-портов в системе? / 25 сообщений из 25, страница 1 из 1
29.05.2014, 21:35
    #38656412
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Надо:

Про модемы знать:
1) Имя модема (Name)
2) COM-порт (AttachedTo)
3) DeviceID

Про порты (интересуют только установленные) знать:
1) имя порта (оно не обязательно COM#)

Решение через WMI мне известно.
На языке WMI то что мне надо:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
'модемы
"Select * From Win32_POTSModem"
oItem.AttachedTo
oItem.Name
oItem.DeviceID

'порты
"Select * from Win32_SerialPort"
oItem.DeviceID т.е. COM1,... COM100, возможны нестандартные имена
oItem.Caption (не обязательно)
oItem.PNPDeviceID (не обязательно, но желательно)



WMI меня не очень устраивает, хотя решение и полностью рабочее (ну почти, там есть тонкие глюки).
И кстати долго , если скажем 100 модемов.

Т.е. нужно взрослое решение типа API-ф-ций SetupDi...
Думаю дорос уже, чтоб разобраться.
Но никак не могу пока уверенно найти.
М.б. кто знает?

Решения типа чтения реестра нежелательно. Опрос через AT команды, TAPI и т.п.- не годится.

Т.е. речь идет об установленных в системе ДЕВАЙСАХ и именно с этой позиции хочу решить задачу.
Поясню еще:
модем например может быть установлен и приаттачен к COM33 -это установленный девайс и он должен присутствовать в списке модемов (присутствует на вкладке Модемы в панели управления).
А вот сам COM33 при этом может быть НЕ установлен в системе. И в этом случае COM33 не должен присутствовать в списке портов (и его при этом нельзя найти в диспетчере устройств ни в классе "порты", ни в каком-либо другом, здесь замечу что виртуальные порты не всегда в классе "Ports").
...
Рейтинг: 0 / 0
29.05.2014, 22:28
    #38656444
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Обычно их в системе не больше четырёх. Можно сделать 4 вызова CreateFile("Com"+n,....) и
посмотреть коды возврата.
...
Рейтинг: 0 / 0
29.05.2014, 22:33
    #38656446
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Насчёт модемов. Можно посмотреть функцию
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363259(v=vs.85).aspx
...
Рейтинг: 0 / 0
29.05.2014, 23:11
    #38656477
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
На, разбирайся:
http://www.codeproject.com/Articles/14412/Enumerating-windows-device
Там есть исходник так чта...
...
Рейтинг: 0 / 0
29.05.2014, 23:15
    #38656483
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
mayton,

не то все.

>не больше четырёх. ... вызова CreateFile("Com"+n
Забываешь про виртуальные порты.
В приложении com0com и аналогичных для пар портов например по умолчанию используются имена:
"CNCA"+n <> "CNCB"+n
И портов этих в системе может быть десятки и сотни.

И никто не мешает установить модем на CNCA35. Попробуй.
Возможно ли программно установить модем?
Там приложен мой пример. VB6 проект но exe-шник есть. Код почти полностью приведен там же.
Он установится даже без наличия в системе самого порта, увидишь модем и AttachedTo=CNCA35 в панели управления в "модемах".

Задача про которую спрашиваю давно мной решена на WMI -лет 5 назад.
Прилакладываю пример (опять же VB6 но с exe-шником).
Мне нужна Enum-ерация, список всех портов (включая тех что не из класса Ports и со "странными" именами) и модемов в системе.

Мне надо сделать то же самое но "по-серьезному", WMI долго работает.
Скорее всего это SetupDi...

По поводу GetCommProperties - не то. Мне нужно имя модема, AttachedTo (имя порта) и DeviceID.
А приведенная тобой ф-ция не об этом.
Причем метод которым я назначаю AttachedTo в своей проге установки модема:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
  hKeyDev = SetupDiOpenDevRegKey(hDeviceInfoSet, m_DeviceInfoData, _
   DICS_FLAG_GLOBAL, 0&, DIREG_DRV, KEY_ALL_ACCESS)
  If (hKeyDev = INVALID_HANDLE_VALUE) Then 'This call fails....
    hKeyDev = SetupDiCreateDevRegKey(hDeviceInfoSet, m_DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, 0, vbNullString)
...
  Debug.Print "hKeyDev=" & hKeyDev
  
  dwRet = RegSetValueEx(hKeyDev, "AttachedTo", 0&, REG_SZ, COM_Port, CLng(Len(COM_Port) + 1))
  RegCloseKey hKeyDev
...


-он кривой, должно быть что-то другое.
...
Рейтинг: 0 / 0
30.05.2014, 00:37
    #38656525
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
White OwlНа, разбирайся:
http://www.codeproject.com/Articles/14412/Enumerating-windows-device..
Спасибо, вроде теплее.
Скомпилировать с ходу не сумел, ну бог с ним, попробуем чего-нибудь полезное выдернуть.

Но, судя по тому что отображает exe-шник...

По модемам: только DeviceID,
AttachedTo и даже Name не выводит.
Ну enum-ерацию сделать очевидно можно (посмотреть как в коде делается).
Здесь как вариант
SetupDiGetDeviceRegistryProperty ("FriendlyName") -это ладно - будет "Name"
А вот с AttachedTo остается только
SetupDiOpenDevRegKey
RegGetValueEx(hKeyDev, "AttachedTo"
И вот не нравится мне этот "метод" прямого чтения реестра, пусть даже hKeyDev через API получен,
а через RegistryProperty -никак не получить, уже пробовал в лоб причем, перебором всех GetDeviceRegistryProperty
Должно что-то быть в API на тему Set/Get AttachedTo (название COM порта)!!!

А вот по портам пока совсем непонятно.
Потому что у виртуальных портов GUID м.б. другой (свой класс, свой раздел).
А WMI, медленная гадина, ведь что интересно это как-то делает, т.е. enum-ерует все в одну кучу через "Select * from Win32_SerialPort", в том числе туда же нестандартные классы с нестандартными именами портов.

Ладно, попробую пока с модемами помухлевать.
...
Рейтинг: 0 / 0
30.05.2014, 01:05
    #38656534
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
maytonОбычно их в системе не больше четырёх. Можно сделать 4 вызова CreateFile("Com"+n,....) и
посмотреть коды возврата.

Сейчас каждый USB-девайс может создавать COM-порт виртуальный, на сколько я знаю.
А их столько может быть...
...
Рейтинг: 0 / 0
30.05.2014, 01:07
    #38656535
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
И портов этих в системе может быть десятки и сотни.
И зачем тебе столько модемов на Винде? Что с ними делаешь?
...
Рейтинг: 0 / 0
30.05.2014, 05:38
    #38656573
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
maytonИ зачем тебе столько модемов на Винде? Что с ними делаешь?
Ну, мог бы уже догадаться по моим топикам.
Моя тема - VOIP телефония, в частности факсы через VOIP.
Стандартная факс прога коннектится к VOIP через виртуальную пару портов.
Внутренний порт смотрит в VOIP, внешний в факс прогу, на внешний порт целесообразно вешать драйвер стандартного модема.
В продакшн системах ну реально скажем так до 60 портов, умножь на 2 (пара) -имеем 120.
Естественно при таких количествах тормозное WMI бесит, списка модемов надо ждать несколько секунд. Плюс если в реестре в классе модемов есть по каким-то причинам бракованный entry "0000", а "0001", "0002"... -нормальные и работоспособные, то WMI вообще модемов не покажет (в этом глюк).

Если по делу, вроде как с модемами все получилось. Единственное, что бесит - "AttachedTo" приходится доставать "ручками из реестра"-ничего умнее не нашел/не придумал (хотя это вполне надежно).
М.б. есть идеи?
А с портами ("Select * from Win32_SerialPort") я счас глянул в свои коды - оказывается могу не париться - я это не использую.
Т.е. по логике программы я таки использую нормальные имена COM# для внешних портов куда вешаются модемы, и Enum-ерация делается через GetDefaultCommConfig function -она возвращает false при отсутствии порта. Проверяется естественно не COMDB а наличие порта как девайса (с повешенным на него драйвером порта). И да, я перебираю, но даже для сотни портов это быстрая процедура.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
Public Function EnumSerPortsFull(portname As String) As Long
  'если порт существует, то функция возвращает ненулевое значение
  Dim cc As COMMCONFIG, ccsize As Long
  '
  ccsize = LenB(cc) 'получаем размер структуры COMMCONFIG
  '
  EnumSerPortsFull = GetDefaultCommConfig(Trim(portname) + Chr(0), cc, ccsize)
  '
End Function



А с модемами код такой родил. Что самое приятное, SetupDi... в данном случае корректно работает на x64 из-под 32-битного приложения. Т.е. драйвера устанавливать нельзя(нужно компилировать x64 код), а опрашивать -без проблем.

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
Public Function GetModemsList() As String
  Dim m_size As Long
  Dim i As Long
  Dim bResult As Boolean
  Dim m_ClassGUID() As GUID
  Dim hDeviceInfoSet As Long
  Dim wIndex As Long
  Dim m_DeviceInfoData As SP_DEVINFO_DATA
  Dim ReqSize As Long
  Dim strPropertyName As String
  Dim strDevInstanceID As String
  Dim strAttachedTo As String
  Dim hKeyDev As Long
  Dim str_modems As String
  
  bResult = SetupDiClassGuidsFromName("Modem", 0&, 0&, m_size)
  If (bResult = False) And (Err.LastDllError = ERROR_INSUFFICIENT_BUFFER) Then
    'Debug.Print "m_size=" & CStr(m_size)
    ReDim m_ClassGUID(0 To m_size - 1)
    bResult = SetupDiClassGuidsFromName("Modem", VarPtr(m_ClassGUID(0).Data1), m_size, 0&)
  Else
    If bResult Then
      'Debug.Print "SetupDiClassGuidsFromName Error. GUID not found."
    Else
      'Debug.Print "SetupDiClassGuidsFromName Error " & RaiseAPIErrorByNumber(Err.LastDllError)
    End If
    Exit Function
  End If
  
  For i = 0 To m_size - 1
    hDeviceInfoSet = SetupDiGetClassDevs(m_ClassGUID(i), vbNullString, 0&, _
     DIGCF_PROFILE) 'DIGCF_PRESENT Or 'Or DIGCF_ALLCLASSES
    If hDeviceInfoSet = INVALID_HANDLE_VALUE Then
      'Debug.Print "SetupDiGetClassDevs Error " & RaiseAPIErrorByNumber(Err.LastDllError)
    Else
      'Debug.Print "hDeviceInfoSet=" & hDeviceInfoSet
    
      wIndex = 0
      m_DeviceInfoData.cbSize = LenB(m_DeviceInfoData)
      Do
        bResult = SetupDiEnumDeviceInfo(hDeviceInfoSet, wIndex, m_DeviceInfoData)
        If (bResult = False) And (Err.LastDllError = ERROR_NO_MORE_ITEMS) Then Exit Do
        
        'Отображаемое имя модема
        strPropertyName = ""
        bResult = SetupDiGetDeviceRegistryProperty(hDeviceInfoSet, m_DeviceInfoData, _
         SPDRP_FRIENDLYNAME, 0, strPropertyName, 0, ReqSize)
        If (bResult = False) And (Err.LastDllError = ERROR_INSUFFICIENT_BUFFER) Then
          strPropertyName = String(ReqSize, Chr(0))
          SetupDiGetDeviceRegistryProperty hDeviceInfoSet, m_DeviceInfoData, SPDRP_FRIENDLYNAME, 0, _
           strPropertyName, ReqSize, 0
          If InStr(strPropertyName, Chr(0)) > 0 Then _
           strPropertyName = Left(strPropertyName, InStr(strPropertyName, Chr(0)) - 1)
        End If
        
        'InstanceID-уникальный идентификатор девайса
        strDevInstanceID = ""
        bResult = SetupDiGetDeviceInstanceId(hDeviceInfoSet, m_DeviceInfoData, strDevInstanceID, 0, ReqSize)
        If (bResult = False) And (Err.LastDllError = ERROR_INSUFFICIENT_BUFFER) Then
          strDevInstanceID = String(ReqSize, Chr(0))
          SetupDiGetDeviceInstanceId hDeviceInfoSet, m_DeviceInfoData, strDevInstanceID, ReqSize
          If InStr(strDevInstanceID, Chr(0)) > 0 Then _
           strDevInstanceID = Left(strDevInstanceID, InStr(strDevInstanceID, Chr(0)) - 1)
        End If
        
        'COM port (AttachedTo)
        strAttachedTo = ""
        hKeyDev = SetupDiOpenDevRegKey(hDeviceInfoSet, m_DeviceInfoData, _
         DICS_FLAG_GLOBAL, 0&, DIREG_DRV, KEY_QUERY_VALUE)
        If (hKeyDev = INVALID_HANDLE_VALUE) Then
          'Debug.Print "SetupDiOpenDevRegKey Error " & RaiseAPIErrorByNumber(Err.LastDllError)
        Else
          'Debug.Print "hKeyDev=" & hKeyDev
          strAttachedTo = GetRegValue(hKeyDev, "", "AttachedTo", "", False)
          RegCloseKey hKeyDev
        End If
        
        str_modems = str_modems & strAttachedTo & ": " & strPropertyName & " " & strDevInstanceID & vbCrLf
        
        wIndex = wIndex + 1
      Loop
    
      SetupDiDestroyDeviceInfoList hDeviceInfoSet
    End If
  Next
  GetModemsList = str_modems
End Function
...
Рейтинг: 0 / 0
30.05.2014, 11:05
    #38656776
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Дмитрий77,
Если по делу, вроде как с модемами все получилось. Единственное, что бесит - "AttachedTo" приходится доставать "ручками из реестра"-ничего умнее не нашел/не придумал (хотя это вполне надежно).
Думаю что всё ОК. Другого источника информации ты не найдёшь.
WMI скорее всего является просто интерфейсом к тому-же реестру.
...
Рейтинг: 0 / 0
30.05.2014, 13:20
    #38656967
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
maytonДмитрий77,
бесит - "AttachedTo" приходится доставать "ручками из реестра"Думаю что всё ОК.
Понимаешь, когда я читаю название порта:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
        hKeyDev = SetupDiOpenDevRegKey(hDeviceInfoSet, m_DeviceInfoData, _
         DICS_FLAG_GLOBAL, 0&, DIREG_DRV, KEY_QUERY_VALUE)
        If (hKeyDev = INVALID_HANDLE_VALUE) Then
          'Debug.Print "SetupDiOpenDevRegKey Error " & RaiseAPIErrorByNumber(Err.LastDllError)
        Else
          'Debug.Print "hKeyDev=" & hKeyDev
          strAttachedTo = GetRegValue(hKeyDev, "", "AttachedTo", "", False)


-это еще более менее прилично выглядит.

А когда я назначаю название порта в процессе установки нового модема,
16072864
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
  hKeyDev = SetupDiOpenDevRegKey(hDeviceInfoSet, m_DeviceInfoData, _
   DICS_FLAG_GLOBAL, 0&, DIREG_DRV, KEY_ALL_ACCESS)
  If (hKeyDev = INVALID_HANDLE_VALUE) Then 'This call fails....
    hKeyDev = SetupDiCreateDevRegKey(hDeviceInfoSet, m_DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, 0, vbNullString)
    If hKeyDev = INVALID_HANDLE_VALUE Then
      Debug.Print "SetupDiCreateDeviceInfoList Error " & RaiseAPIErrorByNumber(Err.LastDllError)
      bRemove = True
      GoTo Cleanup
    End If
  End If
  Debug.Print "hKeyDev=" & hKeyDev
  
  dwRet = RegSetValueEx(hKeyDev, "AttachedTo", 0&, REG_SZ, COM_Port, CLng(Len(COM_Port) + 1))
  RegCloseKey hKeyDev
  If dwRet <> ERROR_SUCCESS Then
    Debug.Print "RegSetValueEx Error " & RaiseAPIErrorByNumber(dwRet)
    bRemove = True
    GoTo Cleanup
  End If


то попахивает какой-то подтасовкой.
Смотри, SetupDiOpenDevRegKey всегда ошибается (драйвер пока не установлен и ветка реестра на этот момент отсутствует - я проверял, останавливая код через MsgBox-ы),
поэтому я создаю пустую ветку SetupDiCreateDevRegKey и бухаю туда в лоб единственный параметр "AttachedTo", все остальное дописывается туда позже - при установке драйвера.

Если я не допишу "AttachedTo", т.е. не пропишу его в реестр и установлю драйвер модема, то модем установится, но в "AttachedTo" будет "набор китайских иероглифов". То бишь он эти иероглифы из какого-то элемента какой-то структуры (который не проинициализирован и поэтому там мусор) откуда-то берет.
Опять же, эта билиберда (с дописыванием"AttachedTo" извините через задницу) надежно работает, и в оригинальном примере "с Microsoft", 16055031 , автор использует именно этот кривой на мой взгляд метод.
Я довольно много искал поиском по инету, не я первый задаю этот вопрос, но все кто задавали ответа не нашли.

'=====
Далее, меня немного смущает мой метод получения m_ClassGUID() и цикл с GUID-ами.
Т.е. я выясняю к-во GUID-ов для класса "Modem", и при втором вызове SetupDiClassGuidsFromName подсовываю указатель на первый элемент .Data1 первой GUID-структуры
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
Public Type GUID
  Data1 As Long
  Data2 As Integer
  Data3 As Integer
  Data4(0 To 7) As Byte
End Type

Public Declare Function SetupDiClassGuidsFromName _
 Lib "setupapi.dll" Alias "SetupDiClassGuidsFromNameA" _
 (ByVal ClassName As String, _
 ByVal pClassGuidList As Long, _
 ByVal ClassGuidListSize As Long, _
 ByRef RequiredSize As Long) As Boolean

...
Dim m_ClassGUID() As GUID

  bResult = SetupDiClassGuidsFromName("Modem", 0&, 0&, m_size)
  If (bResult = False) And (Err.LastDllError = ERROR_INSUFFICIENT_BUFFER) Then
    ReDim m_ClassGUID(0 To m_size - 1)
    bResult = SetupDiClassGuidsFromName("Modem", VarPtr(m_ClassGUID(0).Data1), m_size, 0&)



В C++ в SetupDiGetClassDevs надо было сразу бы подсунуть GUID_CLASS_MODEM , вернее GUID_DEVINTERFACE_MODEM , думаю так и сделаю через CoCreateGUID.
Просто с моим кодом с GUID-массивами я не уверен, что он полностью безупречен в общем случае (т.е. если GUID-ов несколько, то будут ли они корректно заполнены).
'=====

Ну, и хотелось бы все таки сделать Enum-ератор для портов "Select * from Win32_SerialPort" по WMI (с учетом нестандартных классов и имен), коль скоро эта кухня сейчас в голове. GetDefaultCommConfig- это не Enum-ератор -это просто проверка конкретного порта по принципу сподкнулся/не споткнулся.
По идее вот это
Device Interface Classes for Serial and Parallel Port Devices , но фишка в том что порты от com0com например находятся не в группе "Порты (COM и LTP)" а создают свою группу (Class, GUID...?) "com0com - serial ports emulators" в диспетчере устройств -при этом WMI->Win32_SerialPort их включает в enum-ерацию, а если я воспользуюсь вышеприведенными Device Interface Classes for Serial and Parallel Port Devices GUID-ами, то я боюсь их не увижу (почти очевидно) - а заранее GUID для com0com подобного эмулятора я в общем случае не знаю (будем так считать).
...
Рейтинг: 0 / 0
30.05.2014, 15:23
    #38657167
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Дмитрий77... меня немного смущает мой метод получения m_ClassGUID() и цикл с GUID-ами.
Т.е. я выясняю к-во GUID-ов для класса "Modem", и при втором вызове SetupDiClassGuidsFromName подсовываю указатель на первый элемент .Data1 первой GUID-структуры
...Просто с моим кодом с GUID-массивами я не уверен, что он полностью безупречен в общем случае (т.е. если GUID-ов несколько, то будут ли они корректно заполнены).
Ну, здесь (в случае модемов) вроде как проще делается - единым GUID-ом и без GUID-массивов.
Правда долго мудохался с SetupDiGetClassDevs пока не доперло перечитать документацию и подставить DIGCF_DEVICEINTERFACE - в предыдущем случае (когда генерировал GUID по имени класса "Modem" этого не требовалось).

GUID_DEVINTERFACE_MODEM
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
Public Const GUID_DEVINTERFACE_MODEM As String = _
 "{2C7089AA-2E0E-11D1-B114-00C04FC2AAE4}"

Public Declare Function CLSIDFromString Lib "ole32" _
(ByVal lpsz As Long, ByRef pclsid As GUID) As Long 'pclsid As Clsid
Public Declare Function IIDFromString Lib "ole32.dll" _
 (ByVal lpszIID As Long, ByRef IID As GUID) As Long

...
  Dim m_ClassGUID As GUID 'единый GUID, а не массив
  
  'можно CLSIDFromString вместо IIDFromString -пофиг
  dwRes = IIDFromString(StrPtr(GUID_DEVINTERFACE_MODEM), m_ClassGUID)
  If dwRes <> S_OK Then
    Debug.Print "IIDFromString Error " & RaiseAPIErrorByNumber(dwRes)
    Exit Function
  End If

  'DIGCF_DEVICEINTERFACE для этого m_ClassGUID -существенно!!!
  hDeviceInfoSet = SetupDiGetClassDevs(m_ClassGUID, vbNullString, 0&, _
   DIGCF_PROFILE Or DIGCF_DEVICEINTERFACE)
  If hDeviceInfoSet = INVALID_HANDLE_VALUE Then
    'Debug.Print "SetupDiGetClassDevs Error " & RaiseAPIErrorByNumber(Err.LastDllError)
  Else
    'Debug.Print "hDeviceInfoSet=" & hDeviceInfoSet
  
    wIndex = 0
    m_DeviceInfoData.cbSize = LenB(m_DeviceInfoData)
    Do
      bResult = SetupDiEnumDeviceInfo(hDeviceInfoSet, wIndex, m_DeviceInfoData)
...


==
А по поводу портов (с учетом нестандартных классов), думаю должен быть какой-то единый GUID, надо в реестре порыться на тему из какой ветки WMI таскает Win32_SerialPort, потому что она их таскает как раз правильно, но не думаю что при этом сильно умничает. Счас WMI-Tools попробую глянуть.
...
Рейтинг: 0 / 0
30.05.2014, 17:16
    #38657330
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Дас, с портами похоже полный бардак.

У меня например на рабочем компе есть:
COM1 -обычный
COM3, COM4 - PCI-платы железных модемов
COM7, COM8 -PCI-плата расширения COM портов
CNC и т.п. -виртуальные, части которых правда присвоены нормальные COM# имена

Если брать enum-ератор
GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR , то видим только
COM1 -обычный
COM7, COM8 -PCI-плата расширения COM портов
(ну собственно они только и сидят в "Порты(COM и LTP)" в диспетчере)

Если брать enum-ератор
GUID_CLASS_COMPORT , то видим
COM1 -обычный
COM7, COM8 -PCI-плата расширения COM портов
CNC и т.п. -виртуальные, части которых правда присвоены нормальные COM# имена
Причем COM3, COM4 - PCI-платы железных модемов -не вижу!!!

А с WMI "Select * from Win32_SerialPort" видим:
COM1 -обычный
COM3, COM4 - PCI-платы железных модемов
CNC и т.п. -виртуальные, части которых правда присвоены нормальные COM# имена
Причем COM7, COM8 -PCI-плата расширения COM портов -не вижу!!! (ток счас обратил внимание)

Получается, что надежно только использовать COM# и перебирать заданный диапазон например COM1-COM100 через GetDefaultCommConfig function.
Она по крайней мере дает четкий ответ ЕСТЬ/НЕТ в не зависимости от природы порта.
Видимо по этой причине я ее и использовал изначально.

Есть еще понятие PortInUse -берется из COMDB - но оно крайне ненадежно по причине того что многие проги/драйвера откровенно следят за собой - т.е. ни проги ни девайса ни драйвера уж нет, а арендованный ею когда-то порт значится как InUse.
Чистка делается через вызов GetDefaultCommConfig и при false вызовом ComDBReleasePort.
Обычный алгоритм проги которая ищет для себя свободный COM#:
вызвать ComDBClaimNextFreePort, после чего использовать возвращаемый номер порта (который эта же ф-ция параллельно метит как InUse).

Я поступаю по другому: вывожу список свободных номеров (GetDefaultCommConfig=false), и когда порт выбран для страховки делаю этому порту ComDBReleasePort, чтоб установщик порта не ругался на ошибочное InUse.
...
Рейтинг: 0 / 0
30.05.2014, 19:42
    #38657457
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Дмитрий77и Enum-ерация делается через GetDefaultCommConfig function -она возвращает false при отсутствии порта...И да, я перебираю, но даже для сотни портов это быстрая процедура.
Я ОШИБСЯ. Начал копать и понял что это ДОЛГАЯ процедура. И на 8-ке именно она занимает несколько секунд при опросе а не WMI.

maytonМожно сделать... CreateFile("Com"+n,....) и
посмотреть коды возврата.
Однако ты прав. Очевидно GetDefaultCommConfig использует CreateFile + пытается узнать что-то про порты, что мне не надо.
Я воспользовался советом:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
Public Function CheckCOMPort(ByVal i As Long) As Boolean
  Dim hPort As Long
  Dim m_tSA As SECURITY_ATTRIBUTES
  hPort = CreateFile("\\.\COM" & CStr(i), _
                     0, _
                     0, _
                     m_tSA, _
                     OPEN_EXISTING, _
                     0)
  CheckCOMPort = (hPort <> INVALID_HANDLE_VALUE)
  If hPort <> INVALID_HANDLE_VALUE Then CloseHandle hPort
End Function

Private Sub CommandGetPortsCreate_Click()
  Dim strPorts As String
  Dim i As Integer
  For i = 1 To 100
    If CheckCOMPort(i) Then
      strPorts = strPorts & "COM" & CStr(i) & vbCrLf
    End If
  Next
  MsgBox strPorts
End Sub



Отрабатывает гораздо быстрее чем GetDefaultCommConfig (почти мгновенно).
Но если в "опросном диапазоне" есть COM порты, ассоциированные с PCI-модемами (железными),
то на них она тормозит еще больше чем GetDefaultCommConfig (GetDefaultCommConfig тормозит и без PCI-модемов).

Надо гарантированно составить "список портов" быстро
Что можно сделать? М.б. какие флаги в CreateFile поменять? Я использую 0-access (для опроса).
Мне надо знать только наличие порта (как состоявшегося в системе девайса).

SetupDi... работают мгновенно, но есть проблемы с возвратом ВСЕХ портов как я описал выше. И надо еще копаться, получать их имена и т.п..
...
Рейтинг: 0 / 0
30.05.2014, 21:49
    #38657504
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Читаю я все эти изыски и не понимаю одной простой вещи ...
Если в системе существуют десятки COM-портов, то некто устанавливает реальные железки или делает настройку виртуальных портов.
Этот некто непрофессионален настолько, что не может делать свою работу?
...
Рейтинг: 0 / 0
30.05.2014, 22:05
    #38657512
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Basil A. Sidorov,

Некто - это программа. И она это должна делать хорошо и безошибочно (чтоб некто произвольный юзер не парил мозги себе и разработчику). И она это уже 5 лет делает.
Но какие-то вещи мне не нравятся (чисто эстетически).
Например ожидание в 3-5 сек при выводе списка портов и модемов на них.

С модемами я считай доразобрался.

Теперь разбираюсь с enum-ератором портов.
Есть кстати еще очень быстрый способ прочитать
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
надо смотреть.
...
Рейтинг: 0 / 0
30.05.2014, 23:12
    #38657536
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Дмитрий77Например ожидание в 3-5 сек при выводе списка портов и модемов на них.
можно подумать модемы какаой-то вредитель постоянно включает и выключает.
если других проблем нет - можно и этим заняться
...
Рейтинг: 0 / 0
02.06.2014, 05:50
    #38658225
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Изопропилможно подумать модемы какаой-то вредитель постоянно включает и выключает.
Ну, виртуальный модем включен тогда, когда запущена программа его эмулирующая.
Но это отнюдь не означает, что он отсутствует в системе, если эта программа не запущена.
Присутствие модема (как и порта) определяется наличием его как устройства (с установленным драйвером естественно).

Смысл решаемой задачи вполне понятен.
Пользователю надо вывести список checkbox-ов COM1-COMn, при этом надо 1) исключить любые COM-ы занятые и не связанные с прогой (физические COM, железные модемы, usb-шнуры и т.п) 2) проставить в этом списке галки против COM, которые уже задействованы прогой (свои COM прога понятно знает).
От пользователя требуется снять/поставить галки против требуемых COM, после чего нажать OK.
В зависимости от выбора пользователя прога удаляет/устанавливает СOM-ы.
То же с привязанными модемами.
Понятно, что тек. карта портов и модемов должна быть выведена безошибочно, чтобы варианты пользовательского выбора исключали ошибки.
===
Если по сути вопроса (про порты), то похоже самый грамотный метод enum-ерации портов QueryDosDevice function

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
'проверяем от COM1 до COM100
Private Sub CommandGetPortsQueryDOS_Click()
  Dim strPorts As String
  Dim i As Long
  For i = 1 To 100
    If CheckCOMPortDOS(i) Then
      strPorts = strPorts & "COM" & CStr(i) & vbCrLf
    End If
  Next
  MsgBox strPorts
End Sub

Public Declare Function QueryDosDevice Lib "kernel32" Alias "QueryDosDeviceA" _
 (ByVal lpDeviceName As String, ByVal lpTargetPath As String, ByVal ucchMax As Long) As Long

Public Function CheckCOMPortDOS(ByVal i As Long) As Boolean
  If QueryDosDevice("COM" & CStr(i), vbNullString, 0) = 0 Then
    If Err.LastDllError = ERROR_INSUFFICIENT_BUFFER Then CheckCOMPortDOS = True
  End If
End Function


Возвращает мгновенно. Ей плевать на то к какому классу относится порт. Она видит порты по имени. Она не пытается влезть в порт как это делают GetDefaultCommConfig и CreateFile, что исключает временные задержки из-за кривости драйверов. Для ответа ЕСТЬ/НЕТ достаточно скормить ей нулевой буфер и получить ERROR_INSUFFICIENT_BUFFER в ответ, что означает наличие девайса по адресу COM#.
Похоже я задачу решил.
...
Рейтинг: 0 / 0
03.06.2014, 01:02
    #38659444
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Короче имплементировал в большой проект 3 вещи:
1) Сделал Enum-ерацию портов через QueryDosDevice вместо GetDefaultCommConfig
2) Сделал Enum-ерацию модемов через GUID_DEVINTERFACE_MODEM+SetupDiEnumDeviceInfo вместо WMI
3) Сделал установку драйверов через InstallSelectedDriver вместо UpdateDriverForPlugAndPlayDevices

Ну и доволен весьма. Списки выводятся без задержек и драйвера устанавливаются быстрее.

Не могу понять следующего.
Microsoft рекомендует на >=Vista использовать DiInstallDevice function вместо InstallSelectedDriver function .
Речь идет об установке драйвера одного модема (при том что такие же уже могут присутствовать) из указанного INF-файла.
Оно мне чего-то даст (скорость установки драйвера и т.п.)? Кроме того что с этим придется отдельно разбираться (тестировать, подключать новые SDK/DDK если C++, бейсик не прокатит для x64), если делать.
"Старая" InstallSelectedDriver прекрасно работает везде включая Win 8.1 x64.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
04.07.2017, 10:16
    #39482235
inbox129
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Дмитрий77,

поделитесь, пожалуйста, кодом реализации 1-го и 2-го пункта!
...
Рейтинг: 0 / 0
04.07.2017, 10:25
    #39482241
rdb_dev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
maytonОбычно их в системе не больше четырёх. Можно сделать 4 вызова CreateFile("Com"+n,....) и
посмотреть коды возврата.Правильнее так:
Код: plaintext
CreateFile("\\.\Com"+n,....)
так как просто COM1-9 это предопределенные псевдоустройства (псевдонимы) с перенаправлением на пайпы, а чтобы "достучаться" до остальных, надо использовать именно пайпы - так универсальнее.
...
Рейтинг: 0 / 0
04.07.2017, 10:29
    #39482245
rdb_dev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
rdb_dev, едрит! Я и не заметил, что кто-то воскресил зомби-тред. Некромания какая-то...
...
Рейтинг: 0 / 0
04.07.2017, 10:58
    #39482262
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
rdb_devrdb_dev, едрит!и расщепление


Но вообще это скорее всего человек искал решение поиском и задал уточняющий вопрос в ветку
...
Рейтинг: 0 / 0
09.07.2017, 01:59
    #39485231
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
inbox129Дмитрий77,

поделитесь, пожалуйста, кодом реализации 1-го и 2-го пункта!

Ну там же простыня на VB6 приведена.
На C+/- будет тоже самое, даже наверно проще, потому как декларации ручками выписывать не надо, нужные .h подключите (какие в MSDN все написано, поиск в google по названиям ф-ций).
Ничего больше сказать не могу (такие вещи шаришь, пока в них копаешься), с тех пор этим занимался один раз формально когда переписывал VB6->.Net
...
Рейтинг: 0 / 0
09.07.2017, 11:03
    #39485262
inbox129
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как нормальным кодом получить список всех модемов и COM-портов в системе?
Спасибо, я по упомянутым Вами методам уже разобрался... Это я от лени вопрос озвучил :)
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как нормальным кодом получить список всех модемов и COM-портов в системе? / 25 сообщений из 25, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]