Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 26.12.2014, 18:51   #1
WinCoder
Заблокирован
 
Регистрация: 24.11.2014
Сообщений: 721
По умолчанию Получение списка COM портов через wmi.

Получаю список портов стандартным способом.

Код:
procedure TForm1.GetSerialPorts;
  const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator   : ISWbemLocator;
  FWMIService     : ISWbemServices;
  FWbemObjectSet  : ISWbemObjectSet;
  FWbemObject     : ISWbemObject;
  FWbemPropertySet: ISWbemPropertySet;
  TempObj         : OleVariant;
  oEnum           : IEnumvariant;
  iValue          : Cardinal;
  DeviceID, Caption: string;
begin
  FSWbemLocator := CoSWbemLocator.Create;
  FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword, '', '', 0, nil);
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_SerialPort','WQL', wbemFlagForwardOnly, nil);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  ComPortList.Clear; // combobox
  while oEnum.Next(1, TempObj, iValue) = 0 do
    begin
      FWbemObject     := IUnknown(TempObj) as ISWBemObject;
      FWbemPropertySet:= FWbemObject.Properties_;
      Caption  := (FWbemPropertySet.Item('Caption', 0).Get_Value);
      DeviceID := (FWbemPropertySet.Item('DeviceID', 0).Get_Value);
      ComPortList.Items.Add(DeviceID + '=' + Caption); // combobox
      TempObj  := Unassigned;
    end;
end;
При этом к примеру микросхема Amtel ATmega8U2 данным кодом определяется, а микросхема FTDI FT232RL не определяется. Обе микрухи являются тупо преобразователями USB to Serial. Пробовал ещё 3G модем, тоже не работает. Все три устройства в диспетчере видны, как COM порты. Вопрос. Почему код определяет не все устройства, и как это исправить?
WinCoder вне форума Ответить с цитированием
Старый 02.01.2015, 12:29   #2
WinCoder
Заблокирован
 
Регистрация: 24.11.2014
Сообщений: 721
По умолчанию

Немного почитав гугл пришёл к выводу, что это проблема wmi. Решил попробовать получать список через SetupAPI. В интернете есть пример получения всех устройств. Мне же нужно получить только com устройства. Как отфильтровать поиск, не знаю. Вдруг кто подскажет?

Код:
procedure FillDeviceList;
var
  dwIndex: DWORD;
  DeviceInfoData: SP_DEVINFO_DATA;
  DeviceName, DeviceClassName: AnsiString;
  ClassGUID: TGUID;
  DeviceClassesCount, DevicesCount: Integer;
begin
    dwIndex := 0;
    DeviceClassesCount := 0;
    DevicesCount := 0;
    // Подготавливаем структуру для получения информации
    ZeroMemory(@DeviceInfoData, SizeOf(SP_DEVINFO_DATA));
    DeviceInfoData.cbSize := SizeOf(SP_DEVINFO_DATA);
    // Получаем данные по каждому устройству в DIS
    // Номер устройства содержится в dwIndex
    while SetupDiEnumDeviceInfo(hAllDevices, dwIndex, DeviceInfoData) do
    begin
      // Инизиализируем наш DeviceHelper,
      // дальнейшая работа с SP_DEVINFO_DATA будет происходить
      // при помощи методов данного класса
      DeviceHelper.DeviceInfoData := DeviceInfoData;
      // Получаем расширенное имя устройства
      DeviceName := DeviceHelper.FriendlyName;
      // Если расширенного имени нет -
      // получаем имя устройства по умолчанию
      if DeviceName = '' then
        DeviceName := DeviceHelper.Description;
      // Получаем GUID класса, к которому относится устройство
      ClassGUID := DeviceHelper.ClassGUID;
      // Получаем имя класса, к которому относится устройство
      DeviceClassName := DeviceHelper.DeviceClassDescription(ClassGUID);
      form1.Memo1.Lines.Add('[' + DeviceClassName + '] ' + DeviceName);
      // Имя класса + Имя девайса     
      // Переходим к следующему устроству
      Inc(dwIndex);
    end;
end;
Напоминаю задачу. Нужно получить имена всех com устройств
WinCoder вне форума Ответить с цитированием
Старый 19.01.2015, 12:32   #3
Daemvil
Пользователь
 
Регистрация: 23.12.2009
Сообщений: 56
По умолчанию

Доброго времени суток! помогите, пожалуйста, разобраться. У меня данный код FillDeviceList в Delphi 7 работает нормально, а в Delphi XE7 в DeviceName пишется какая-то абракадабра. XE7 Появился у меня относительно недавно (потребовалось работать с большими объемами данных), так что не везде его пока понимаю.
UPD: ответ для ТС в Delphi 7:
Код:
procedure FillDeviceList(DevList:TStrings; PortNames:TStrings);
var
  dwIndex: DWORD;
  DeviceInfoData: SP_DEVINFO_DATA;
  DeviceName, DeviceClassName: String;
  ClassGUID: TGUID;
  DeviceClassesCount, DevicesCount: Integer;
begin

    dwIndex := 0;
    DeviceClassesCount := 0;
    DevicesCount := 0;

    // Подготавливаем структуру для получения информации
    ZeroMemory(@DeviceInfoData, SizeOf(SP_DEVINFO_DATA));
    DeviceInfoData.cbSize := SizeOf(SP_DEVINFO_DATA);

    // Получаем данные по каждому устройству в DIS
    // Номер устройства содержится в dwIndex
    while SetupDiEnumDeviceInfo(hAllDevices, dwIndex, DeviceInfoData) do
    begin

      // Инизиализируем наш DeviceHelper,
      // дальнейшая работа с SP_DEVINFO_DATA будет происходить
      // при помощи методов данного класса
      DeviceHelper.DeviceInfoData := DeviceInfoData;

      // Получаем расширенное имя устройства
      DeviceName := DeviceHelper.FriendlyName;
      // Если расширенного имени нет -
      // получаем имя устройства по умолчанию
      if DeviceName = '' then
        DeviceName := DeviceHelper.Description;

      // Получаем GUID класса, к которому относится устройство
      ClassGUID := DeviceHelper.ClassGUID;
      // Получаем имя класса, к которому относится устройство
      DeviceClassName := DeviceHelper.DeviceClassDescription(ClassGUID);

      if pos('COM',DeviceName)<>0 then Inc(DeviceClassesCount);

      if pos('(COM',DeviceName)<>0 then //showmessage(DeviceName);
      begin
        DevList.Add(DeviceName);
        PortNames.Add(copy(DeviceName,POS('(COM',DeviceName)+1,length(DeviceName)-1-POS('(COM',DeviceName)));
      end;
      Inc(DevicesCount);

      // Переходим к следующему устроству
      Inc(dwIndex);
    end;
end;
Nostra Sunt

Последний раз редактировалось Daemvil; 20.01.2015 в 11:02.
Daemvil вне форума Ответить с цитированием
Старый 19.01.2015, 13:10   #4
northener
ПШП
Участник клуба
 
Регистрация: 15.07.2013
Сообщений: 1,885
По умолчанию

Попробуй
Код:
DeviceName, DeviceClassName: AnsiString;
northener вне форума Ответить с цитированием
Старый 19.01.2015, 13:18   #5
Daemvil
Пользователь
 
Регистрация: 23.12.2009
Сообщений: 56
По умолчанию

Цитата:
Сообщение от northener Посмотреть сообщение
Попробуй
Код:
DeviceName, DeviceClassName: AnsiString;
Пробовал, не помогает. DeviceHelper - в нем возможно проблема, т.к. сравнивал значения переменных, а на нем Дельфи ХЕ7 пишет в Watches, что идентификатора нет, хотя он на самом деле описан в TDeviceHelper. В Дельфи 7 пишет значение не ругаясь.
Причем на этой строке ClassGUID := DeviceHelper.ClassGUID; вылезает ошибка "неверный гуид".
при замене на ClassGUID := DeviceInfoData.ClassGUID; в DeviceClassName и следующем DeviceName пишется служебная инфа какая-то с кусками путей на диске %)
Nostra Sunt

Последний раз редактировалось Daemvil; 19.01.2015 в 13:21.
Daemvil вне форума Ответить с цитированием
Старый 19.01.2015, 13:28   #6
Daemvil
Пользователь
 
Регистрация: 23.12.2009
Сообщений: 56
По умолчанию

Выяснил, что "DeviceHelper" зарезервирован. Но замена на DH: TDeviceHelper; не помогла...
Nostra Sunt
Daemvil вне форума Ответить с цитированием
Старый 19.01.2015, 16:09   #7
Daemvil
Пользователь
 
Регистрация: 23.12.2009
Сообщений: 56
По умолчанию

Поборол. По-хорошему надо весь модуль перелопатить, но мне достаточно оказалось в FillDeviceList написать "DeviceName, DeviceClassName: AnsiString;", в DeviceHelper.pas поменять везде String на AnsiString, и в функции GetString изменить строчку на REG_SZ: Result := PAnsiChar(Result);
Собственно из-за несовместимого GetString и вылезала ошибка EConvertError.
Nostra Sunt
Daemvil вне форума Ответить с цитированием
Старый 20.01.2015, 09:30   #8
Daemvil
Пользователь
 
Регистрация: 23.12.2009
Сообщений: 56
По умолчанию

Мне подсказали, что проблема решается еще проще:
заменой двух функций:
SetupDiGetClassDescriptionA -> SetupDiGetClassDescriptionW
SetupDiGetDeviceRegistryPropertyA -> SetupDiGetDeviceRegistryPropertyW
либо проверкой юникодности {$IFDEF UNICODE} и последующей подставкой
TSetupDiGetClassDescription = TSetupDiGetClassDescriptionA;
либо
TSetupDiGetClassDescription = TSetupDiGetClassDescriptionW;
для универсальности
Nostra Sunt

Последний раз редактировалось Daemvil; 20.01.2015 в 09:51.
Daemvil вне форума Ответить с цитированием
Старый 20.01.2015, 09:56   #9
WinCoder
Заблокирован
 
Регистрация: 24.11.2014
Сообщений: 721
По умолчанию

Daemvil Будем знать, а то я пошёл стандартным путём, и переписал SetupAPI.pas под Ansi. Кстати проблема решена. Без проблем получаю список COM
WinCoder вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Настройка сетевухи через WMI ds.Dante Общие вопросы .NET 5 11.04.2012 00:30
Серийный номер hdd через wmi xil C# (си шарп) 3 08.09.2011 12:04
Получение списка процеcсов legendary Win Api 12 02.09.2010 18:06
Получение списка файлов Костян Пират Общие вопросы Delphi 11 16.02.2009 09:58
получение 1 списка из 2-х Neznau Помощь студентам 0 10.12.2008 22:16