用Delphi通过SetupAPI.dll列举和停用硬件设备

本文介绍了如何使用Delphi结合SetupAPI.dll来列举和停用硬件设备,包括获取设备信息、设备类型图标、设备状态,并提供了设备禁用的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前天弄的东西,通过SetupAPI.dll列举硬件设备,部分是改自MSDN自带的例子,自己加了显示设备类型名和图标.代码是阿哦一个个加上去的有些乱.

{ Setup.pas---从SetupAPI.h里转的一些函数和常量 }
unit SetupAPI;

interface

uses
  Windows;

const
  DIGCF_PRESENT = $0002;
  DIGCF_ALLCLASSES = $0004;
  SPDRP_DEVICEDESC = 0;

  DIF_PROPERTYCHANGE = 18;

  DICS_ENABLE = 1;
  DICS_FLAG_GLOBAL = 1;
  DICS_DISABLE = 2;

type
  HDEVINFO = type Cardinal;
  DI_FUNCTION = type Cardinal;
 
  PSP_DEVINFO_DATA = ^SP_DEVINFO_DATA;
  SP_DEVINFO_DATA = record
    cbSize: DWORD;
    ClassGuid: TGUID;
    DevInst: DWORD;
    Reserved: Longint;
  end;

  PSP_CLASSINSTALL_HEADER = ^SP_CLASSINSTALL_HEADER;
  SP_CLASSINSTALL_HEADER = record
    cbSize: DWORD;
    InstallFunction: DI_FUNCTION; { (DIF code) }
  end;

  PSP_PROPCHANGE_PARAMS = ^SP_PROPCHANGE_PARAMS;
  SP_PROPCHANGE_PARAMS = record
    ClassInstallHeader: SP_CLASSINSTALL_HEADER;
    StateChange: DWORD;
    Scope: DWORD;
    HwProfile: DWORD;
  end;

  PSP_CLASSIMAGELIST_DATA = ^SP_CLASSIMAGELIST_DATA;
  SP_CLASSIMAGELIST_DATA = record
    cbSize: DWORD;
    ImageList: HWND;
    Reserved: DWORD;
  end;

function SetupDiGetClassDevs(const ClassGuid: PGUID; Enumerator: PChar;
  hwndParent: HWND; Flags: DWORD): HDEVINFO; stdcall;
  external 'Setupapi.dll' name 'SetupDiGetClassDevsA';

function SetupDiEnumDeviceInfo(DeviceInfoSet: HDEVINFO; MemberIndex: DWORD;
  DeviceInfoData: PSP_DEVINFO_DATA): BOOL; stdcall;
  external 'Setupapi.dll' name 'SetupDiEnumDeviceInfo';

function SetupDiGetDeviceRegistryProperty(DeviceInfoSet: HDEVINFO;
  DeviceInfoData: PSP_DEVINFO_DATA; Propertys: DWORD; PropertyRegDataType: PWORD;
  PropertyBuffer: PByte; PropertyBufferSize: DWORD; RequiredSize: PWORD): BOOL; stdcall;
  external 'Setupapi.dll' name 'SetupDiGetDeviceRegistryPropertyA';

function SetupDiDestroyDeviceInfoList(DeviceInfoSet: HDEVINFO): BOOL; stdcall;
  external 'Setupapi.dll' name 'SetupDiDestroyDeviceInfoList';

function SetupDiClassNameFromGuid(ClassGuid: PGUID; ClassName: PChar;
  ClassNameSize: DWORD; RequiredSize: PDWORD): BOOL; stdcall;
  external 'Setupapi.dll' name 'SetupDiClassNameFromGuidA';

function SetupDiSetClassInstallParams(DeviceInfoSet: HDEVINFO ;
  DeviceInfoData: PSP_DEVINFO_DATA; ClassInstallParams: PSP_CLASSINSTALL_HEADER;
  ClassInstallParamsSize: DWORD): BOOL stdcall;
  external 'Setupapi.dll' name 'SetupDiSetClassInstallParamsA';

function SetupDiCallClassInstaller(InstallFunction: DI_FUNCTION;
  DeviceInfoSet: HDEVINFO; DeviceInfoData: PSP_DEVINFO_DATA): BOOL; stdcall;
  external 'Setupapi.dll' name 'SetupDiCallClassInstaller';

function SetupDiGetClassImageList(ClassImageListData: PSP_CLASSIMAGELIST_DATA): BOOL;
  stdcall; external 'Setupapi.dll' name 'SetupDiGetClassImageList';

function SetupDiDestroyClassImageList(ClassImageListData: PSP_CLASSIMAGELIST_DATA):
  BOOL; stdcall; external 'Setupapi.dll' name 'SetupDiDestroyClassImageList';

function SetupDiGetClassImageIndex(ClassImageListData: PSP_CLASSIMAGELIST_DATA;
  ClassGuid: PGUID; ImageIndex: PINT): BOOL; stdcall;
  external 'Setupapi.dll' name 'SetupDiGetClassImageIndex';

implementation

end.

{ untMain.pas主窗体单元,Uses部分引用上面的pas,
再加1个BUTTON;1个TListView;1个TImageList,定义看代码 }

unit untMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, SetupAPI, StdCtrls, ComCtrls, ImgList;

type
  TForm1 = class(TForm)
    lv1: TListView;
    btn1: TButton;
    il1: TImageList;
    procedure btn1Click(Sender: TObject);
  private
    function GetDeviceClassName(aGUID: TGUID): string;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  ClassImageListData: SP_CLASSIMAGELIST_DATA; {设备类型图标结构,全局变量,退出时释放.}

implementation

{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
var
  hDevInfo: Cardinal;
  DeviceInfoData: SP_DEVINFO_DATA; {设备信息结构}
  i: Integer;
  DataT, Buffersize: DWORD;
  Buffer: PAnsiChar;
  List: TListItem;
  index: Integer;
begin
  { 获取设备信息句柄 }
  lv1.Items.BeginUpdate;
  DriverInfoData.cbSize := SizeOf(SP_DRVINFO_DATA_A);
  hDevInfo := SetupDiGetClassDevs(nil, 0, 0,
    DIGCF_PRESENT or DIGCF_ALLCLASSES);
  if hDevInfo = INVALID_HANDLE_VALUE then Exit;
  { 设备图标数据结构 }
  ClassImageListData.cbSize := SizeOf(SP_CLASSIMAGELIST_DATA);
  { 获取设备图标数据 }
  if SetupDiGetClassImageList(@ClassImageListData) then
  begin
    { 赋句柄给ImageList }
    il1.Handle := ClassImageListData.ImageList;
    { TreeView图标指定到ImageList }
    lv1.SmallImages := il1;
  end;
   
  i := 0;
  Buffersize := 256;
  DeviceInfoData.cbSize := SizeOf(SP_DEVINFO_DATA);
  GetMem(Buffer, Buffersize);
  { 枚举设备信息 }
  while SetupDiEnumDeviceInfo(hDevInfo, i, @DeviceInfoData) do
  begin

    { 获取设备信息包括GUID和名称 }
    SetupDiGetDeviceRegistryProperty(hDevInfo, @DeviceInfoData,
      SPDRP_DEVICEDESC, @DataT, PByte(Buffer), Buffersize, nil);
    Inc(i);
    List := lv1.Items.Add;
    { 获取制定GUID(设备类型)的图标索引 }
    if SetupDiGetClassImageIndex(@ClassImageListData,
      @DeviceInfoData.ClassGuid, @index) then
      { 制定显示图标 }
      List.ImageIndex := index;
    { 通过GUID获取设备类型(Class) }
    List.Caption := GetDeviceClassName(DeviceInfoData.ClassGuid);
    { 转换GUID到字符串 }
    List.SubItems.Add(GUIDToString(DeviceInfoData.ClassGuid));
    { 显示设备名称 }
    List.SubItems.Add(Buffer);
    { 设备状态 }
    if IsDisableable(i ,hDevInfo) then
      List.SubItems.Add('True')
    else
      List.SubItems.Add('False');
   
  end;
  if Buffer <> nil then FreeMem(Buffer);
  if (GetLastError() <> NO_ERROR) and
    (GetLastError() <> ERROR_NO_MORE_ITEMS) then
    Exit;
  { 释放 DeviceInfoData, hDevInfo }
  SetupDiDestroyDeviceInfoList(hDevInfo);
  lv1.Items.EndUpdate;
end;

{最后在退出程序时释放 SetupDiDestroyClassImageList(@ClassImageListData); }


{ 获取设备类型 }
function TForm1.GetDeviceClassName(aGUID: TGUID): string;
var
  ClassName: PChar;
  ClassNameSize: DWORD;
begin
  ClassNameSize := 0;
  GetMem(ClassName, ClassNameSize);
  { 利用GUID返回设备类型名 }
  while not SetupDiClassNameFromGuid(@aGUID, ClassName, ClassNameSize,
    @ClassNameSize) do
  begin
    if GetLastError() = ERROR_INSUFFICIENT_BUFFER then
    begin
      if ClassName <> nil then FreeMem(ClassName);
      GetMem(ClassName, ClassNameSize);
    end else
      Break;
  end;
  Result := ClassName;
  if ClassName <> nil then FreeMem(ClassName);
end;

end.

 

{设备禁用的代码,是从网上改些一个C++代码的,还没来得及加注解,先看着,以后加.}

function ChangeDeviceState(hDevInfo: HDEVINFO; NewStatus: DWORD;
  SelectedItem: DWORD): Boolean;
var
  PropChangeParams: SP_PROPCHANGE_PARAMS;
  DeviceInfoData: SP_DEVINFO_DATA;
begin
  Result := False;

  DeviceInfoData.cbSize := SizeOf(SP_DEVINFO_DATA);
  if not SetupDiEnumDeviceInfo(hDevInfo, SelectedItem, @DeviceInfoData) then Exit;

  // Set the PropChangeParams structure.
  PropChangeParams.ClassInstallHeader.cbSize := SizeOf(SP_CLASSINSTALL_HEADER);
  PropChangeParams.ClassInstallHeader.InstallFunction := DIF_PROPERTYCHANGE;
  PropChangeParams.Scope := DICS_FLAG_GLOBAL;
  PropChangeParams.StateChange := NewStatus;

  if not SetupDiSetClassInstallParams(hDevInfo, @DeviceInfoData,
    PSP_CLASSINSTALL_HEADER(@PropChangeParams), SizeOf(PropChangeParams)) then
    Exit;

  // Call the ClassInstaller and perform the change.
  if not SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo,
    @DeviceInfoData) then
    Exit;

  Result := True;
end;

function ControlDisk(nStatus, nIndex: Integer): Boolean;
var
  Guid: TGUID ;
  GUIDString: string;
  hDevInfo: Cardinal;
  i: DWORD;
  DeviceInfoData: SP_DEVINFO_DATA;
begin
  Result := False;
  if (nStatus = -1) then Exit;

  ZeroMemory(@Guid, sizeof(TGUID));
  case nIndex of
    0: // 0 代表软驱
      GUIDString := '{4D36E980-E325-11CE-BFC1-08002BE10318}';
    1: // 1 代表光驱
      GUIDString := '{4D36E965-E325-11CE-BFC1-08002BE10318}';
    2: // 2 代表USB
      GUIDString := '{36FC9E60-C465-11CF-8056-444553540000}';
  end;
  Guid := StringToGUID(GUIDString);

  hDevInfo := SetupDiGetClassDevs(@Guid, nil, HWND(nil), DIGCF_PRESENT);
  if (hDevInfo = INVALID_HANDLE_VALUE) then Exit;

  ZeroMemory(@DeviceInfoData, SizeOf(SP_DEVINFO_DATA));
  DeviceInfoData.cbSize := SizeOf(SP_DEVINFO_DATA);

  i := 0;
  while SetupDiEnumDeviceInfo(hDevInfo, i, @DeviceInfoData) do
  begin
    if nStatus  = 1 then
      Result := ChangeDeviceState(hDevInfo, DICS_ENABLE, i)
    else if nStatus = 2 then
      Result := ChangeDeviceState(hDevInfo, DICS_DISABLE, i);
    Inc(i);
  end;

  SetupDiDestroyDeviceInfoList(hDevInfo);
end;


{ 调用如下: }
{ 禁用光驱: if ControlDisk(DICS_DISABLE, 1) then ShowMessage('成功禁用!'); }

{启用光驱: if ControlDisk(DICS_ENABLE, 1) then ShowMessage('启用成功!'); }

{ 注意USB要调用2次 ControlDisk(DICS_ENABLE, 2)才能完成启用. }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值