Delphi: Работа с устройствами в Windows - Включение и отключение устройств

ОГЛАВЛЕНИЕ

Включение и отключение устройств

Состоянием устройства управляет функция SetupDiSetClassInstallParams. Её описание:

WINSETUPAPI BOOL WINAPI
  SetupDiSetClassInstallParams(
 IN HDEVINFO DeviceInfoSet,
 IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
 IN PSP_CLASSINSTALL_HEADER ClassInstallParams, OPTIONAL
 IN DWORD ClassInstallParamsSize
 );

С первыми двумя параметрами я думаю всё ясно. Третий параметр задаёт указатель на структуру SP_CLASSINSTALL_HEADER. Четвёртый параметр задаёт размер третьего параметра. С помощью этой функции можно производить различные действия с устройствами и, разумеется, для каждого действия используются различные структуры. Но у каждой из структур первая составляющая одинаковая – структура SP_CLASSINSTALL_HEADER, вот она:

typedef struct _SP_CLASSINSTALL_HEADER {
  DWORD cbSize;
  DI_FUNCTION InstallFunction;
} SP_CLASSINSTALL_HEADER, *PSP_CLASSINSTALL_HEADER;

Поле InstallFunction задаёт производимую над устройством операцию. Для включения/отключения это поле будет равно константе DIF_PROPERTYCHANGE. Для включения/отключения устройства используется следующая структура:

typedef struct _SP_PROPCHANGE_PARAMS {
  SP_CLASSINSTALL_HEADER ClassInstallHeader;
  DWORD StateChange;
  DWORD Scope;
  DWORD HwProfile;
} SP_PROPCHANGE_PARAMS, *PSP_PROPCHANGE_PARAMS;

Если поле StateChange будет равно DICS_ENABLE, то устройство будет включено иначе DICS_DISABLE. Если поле Scope равно DICS_FLAG_GLOBAL, то изменения вступят в силу для всех аппаратных профилей, если DICS_FLAG_CONFIGSPECIFIC, то изменения вступят в силу только для указанного аппаратного профиля. Поле HwProfile задаёт ID аппаратного профиля, к которому будут применяться изменения, если он равен нулю, то текущий аппаратный профиль. Все параметры нуждаются в «утверждении» перед любыми изменениями. Поэтому функцию надо вызывать два раза. Если после первого вызова функция возвратила истинное значение, значит можно вызывать функцию второй раз.

После изменения состояния устройства надо вызвать установщик класса, т.к. после изменения состояния устройства может потребоваться перезагрузка системы или другие действия, для того чтобы изменения вступили в силу. Это осуществляется функцией SetupDiCallClassInstaller

WINSETUPAPI BOOL WINAPI
  SetupDiCallClassInstaller(
 IN DI_FUNCTION InstallFunction,
 IN HDEVINFO DeviceInfoSet,
 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
 );

Первый параметр задаёт код произведённой операции. Два остальных параметра я думаю, проблем не вызовут.

В качестве примера можно привести код включения и отключения сетевого подключения. Для того чтобы включить/выключить сетевое подключение достаточно включить/выключить сетевое устройство, через которое осуществляется сетевое подключение. Это производит следующая функция:

procedure EnableNetDevice(aState:boolean;index:integer);
var
  NetPnPHandle:HDEVINFO;
  PCHP:TSPPropChangeParams;
  DeviceData:TSPDevInfoData;
begin
  NetPnPHandle:=SetupDiGetClassDevs(@GUID_DEVCLASS_NET, 0, 0, DIGCF_PRESENT);
  if NetPnPHandle=INVALID_HANDLE_VALUE then exit;
  DeviceData.cbSize:=sizeof(TSPDevInfoData);
  SetupDiEnumDeviceInfo(NetPnPHandle, index, DeviceData);
  PCHP.ClassInstallHeader.cbSize:=sizeof(TSPClassInstallHeader);
  if SetupDiSetClassInstallParams(NetPnPHandle,@DeviceData,@PCHP,sizeof(TSPPropChangeParams)) then
 begin
   PCHP.ClassInstallHeader.cbSize := sizeof(TSPClassInstallHeader);
   PCHP.ClassInstallHeader.InstallFunction := DIF_PROPERTYCHANGE;
   PCHP.Scope := DICS_FLAG_CONFIGSPECIFIC;
 if aState then
   PCHP.StateChange := DICS_ENABLE
   else
   PCHP.StateChange := DICS_DISABLE;
 SetupDiSetClassInstallParams(NetPnPHandle,@DeviceData,@PCHP,sizeof(TSPPropChangeParams));
 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,NetPnPHandle,@DeviceData);
  end;
  DeviceData.cbSize := sizeof(TSPDevInfoData);
  SetupDiDestroyDeviceInfoList(NetPnPHandle);
end;

Параметр index задаёт индекс сетевого устройства в списке сетевых устройств.