Delphi: Работа с устройствами в WindowsИсточник: pblog
http://pblog.ru/?p=105
Функции, которые осуществляют работу с устройствами, находятся в системных библиотеках cfgmgr32.dll и setupapi.dll. К сожалению, в стандартных заголовочных файлах Delphi нет объявлений функций, констант и структур которые используются этими библиотеками. Эти заголовочные файлы можно скачать с сайта проекта Delphi-JEDI. Те, кому не нравятся модули от проекта Delphi-JEDI могут воспользоваться моим модулем setupapi.pas, но в нём далеко не полный список функции и структур.
Получение списка устройствПервая задача, с которой мы столкнёмся это получение списка устройств. Устройства в системе подразделяются на классы, например: класс видеоустройств, принтеров, модемы, клавиатуры и т.д. Любое устройство должно принадлежать как-нибудь классу. Каждый класс идентифицируется своим GUID"ом (глобальный уникальный идентификатор). GUID это 128 битная запись типа: {C06136A2-43EA-4F43-AF06-7413D07E28B7}. Для получения полного списка устройств сначала надо получить список классов. Для получения списка классов используется функция CM_Enumerate_Classes:
CMAPI CONFIGRET WINAPI Для перечисления всех классов мы должны в цикле вызывать функцию, начиная с индекса 0. Если функция вернула значение CR_NO_SUCH_VALUE, значит, мы пришли к концу списка. Вторым параметром должен быть указатель на переменную TGUID, в которую будет сохранён GUID класса. Получение информации о классе осуществляет функция SetupDiGetClassDescription:
WINSETUPAPI BOOL WINAPI Вторым параметром должен идти указатель на буфер, в который будет сохранена строка с именем класса. Третьим параметром должен идти размер передаваемого буфера. Если указанного буфера не хватит, то требуемый размер будет сохранён в переменной указатель, на которую мы передадим четвёртым параметром. Список классов мы получили. Теперь нам надо получить список устройств, принадлежащих некоторому классу. Здесь к нам придёт на помощь функция SetupDiGetClassDevs: HDEVINFO У этой функции почти все параметры опциональны за исключением последнего. Первый параметр задаёт класс устройств для перечисления. Если этот параметр равен нулю, то перечисляться будут все устройства в системе. Второй и третий параметры (соответственно, имя PnP перечислителя и хендл формы) могут быть равны нулю. Последний параметр самый важный. Он может принимать одно из следующий значений или их комбинацию:
В нашем случае надо указать только класс устройств и указать последним параметром флаг DIGCF_PRESENT. При успешном вызове функция возвращает хендл полученного списка. Итак, у нас есть список (вернее его хендл) и нам надо как-то перечислить все устройства находящиеся в нём. На помощь к нам придёт функция под названием SetupDiEnumDeviceInfo: WINSETUPAPI BOOL WINAPI С первых параметром, я думаю, всё ясно. Второй парметр задаёт индекс в списке. Третий параметр это указатель на структуру SP_DEVINFO_DATA, в которой будет сохранена информация об устройстве. Если функция вернула значение TRUE, то информация извлечена успешно, а если FALSE, то в большинстве случаев это означает что мы пришли к концу списка. Для перечисления всего списка нам надо будет в цикле вызывать функцию SetupDiEnumDeviceInfo каждый раз увеличивая значение индекса на единицу до тех пор пока не получим отрицательный результат. typedef struct _SP_DEVINFO_DATA { По сути, главным полем здесь является поле DevInst, которая и хранит хендл устройства. Для того чтобы получить имя устройства (или его описание) нам надо использовать функцию SetupDiGetDeviceRegistryProperty. Далее её описание WINSETUPAPI BOOL WINAPI Второй параметр это указатель на структуру SP_DEVINFO_DATA. Третий параметр задаёт тип информации, которую мы хотим получить. Для нас важны два флага: SPDRP_FRIENDLYNAME и SPDRP_DEVICEDESC. Далее идёт опциональный параметр который задаёт указатель на переменную в которой будет сохранён тип данных ключа реестра, из которого была извлечена информация. Далее идёт ещё три параметра которые задают соответственно указатель на буфер для сохранения информации, размер буфера и размер реально скопированных данных в ненр. Если мы будем использовать флаг SPDRP_FRIENDLYNAME, то получим вместо модели жёсткого диска "дисковый накопитель", а при использовании флага SPDRP_DEVICEDESC мы получим модель жёсткого диска. Не всегда информация для обоих параметров представлена, иногда есть только для SPDRP_FRIENDLYNAME, а иногда есть только для SPDRP_DEVICEDESC. Если при использовании первого флага мы получили пустую строку, то надо получить информацию с использованием второго флага. Следующая функция получает имя устройства по хендлу перечисления и структуре SP_DEVINFO_DATA. function GetDeviceName(PnPHandle: HDEVINFO; const DevData: TSPDevInfoData): string; В итоге в Delphi у нас вырисовывается функция, которая получает список устройств по заданному GUID"у класса. procedure TForm1.AddDevices(aNode: TTreeNode; aGUID: TGUID); Данная функция выводит список устройств заданного класса в компонент TreeView. Узел дерева TreeView задаётся первым параметром. Теперь мы можем написать функцию которая и произведёт вывод сего списка устройств в компонент TreeView. Вот она: procedure TForm1.AddAllDevices; Сначала формируется список строк с имена классов и указателей на их GUID"ы. Потом производится вызов предыдущей функции для каждого класса. |