обработка WM_DEVICECHANGE
От: Аноним  
Дата: 11.05.06 08:39
Оценка:
Добрый день.
Регистрирую обработчик WM_DEVICECHANGE и получаю DBT_DEVICEARRIVAL и DBT_DEVICEREMOVECOMPLETE.
Вопрос: как узнать какое именно устройство подключалось и отключалось? Конкретно интерисует случай с USB устройствами HardwareID?
Или по крайнер мере как узнать его в этом обработчике?
Re: обработка WM_DEVICECHANGE
От: Pavel_Agurov Россия  
Дата: 13.05.06 13:56
Оценка:
А>Вопрос: как узнать какое именно устройство подключалось и отключалось? Конкретно интерисует случай с USB устройствами HardwareID?А>Или по крайнер мере как узнать его в этом обработчике?

Конкретно про USB.


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics,
  Controls, Forms, Dialogs, StdCtrls, DBT;

type
  TForm1 = class(TForm)
    lbDevice: TListBox;
  private
    // обработчик сообщения WM_DEVICECHANGE
    procedure WMDEVICECHANGE(var Msg : TWMDeviceChange); message WM_DEVICECHANGE;

    // получение имени диска
    function GetDiskName(unitmask : Longint) : string;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{обработчик сообщения WM_DEVICECHANGE}
procedure TForm1.WMDEVICECHANGE(var Msg: TWMDeviceChange);
var
  lpdb  : PDevBroadcastHdr;
  lpdbv : PDevBroadcastVolume;
  lpdbpr: PDevBroadCastPort;
begin
 {Заголовок сообщения}
 lpdb := PDevBroadcastHdr(Msg.dwData);

 {Отображаем код события}
 lbDevice.Items.Add('Обнаружено событие. Код:'+IntToHex(Msg.Event, 4));

 Case Msg.Event of
  DBT_DEVICEARRIVAL: begin {Добавление}
   lbDevice.Items.Add('>Добавлено устройство. Код:'+IntToHex(lpdb^.dbch_devicetype, 4));

   { Новое устройство - порт (последовательный или параллельный) }
   If lpdb^.dbch_devicetype = DBT_DEVTYP_PORT then begin
    lpdbpr:= PDevBroadCastPort(Msg.dwData);
    lbDevice.Items.Add('>>Добавлен порт. Имя:'+WideCharToString(@lpdbpr.dbcp_name));
   End;

   { Новое устройство - логический диск }
   If lpdb^.dbch_devicetype = DBT_DEVTYP_VOLUME then begin
    lpdbv := PDevBroadcastVolume(Msg.dwData);
    lbDevice.Items.Add('>>Добавлен логический диск. Имя: '+GetDiskName(lpdbv.dbcv_unitmask));
   End;
  End;

  DBT_DEVICEREMOVECOMPLETE: begin {Удаление}
   lbDevice.Items.Add('>Удалено устройство. Код: '+IntToHex(lpdb^.dbch_devicetype, 4));

   { Удаленное устройство - порт (последовательный или параллельный) }
   If lpdb^.dbch_devicetype = DBT_DEVTYP_PORT then begin
    lpdbpr:= PDevBroadCastPort(Msg.dwData);
    lbDevice.Items.Add('>>Удален порт. Имя: '+WideCharToString(@lpdbpr.dbcp_name));
   End;

   { Удаленное устройство - логический диск }
   If lpdb^.dbch_devicetype = DBT_DEVTYP_VOLUME then begin
    lpdbv := PDevBroadcastVolume(Msg.dwData);
    lbDevice.Items.Add('>>Удален логический диск. Имя: '+GetDiskName(lpdbv.dbcv_unitmask));
   End;
  End;
 End;
 
end;

// Маска имени диска. Возвращаемое значение состоит из битов,
// соответствующих именам дисков:
// бит 0=A, бит 1=B, бит 3=C и т.д. 
function TForm1.GetDiskName(unitmask : Longint) : string;
var i : Integer;
begin
 For i:= 0 to 26 do begin
  if ((unitmask and 1) <> 0) then Break;
  unitmask:= unitmask shr 1;
 End;
 Result:= Char(Integer('A')+i);
end;

end.



Модуль DBT.pas возьмите из JEDI.

На C#:

private System.Windows.Forms.ListBox listBox1;

        [STAThread]
        static void Main() 
        {
            Application.Run(new Form1());
        }

        const int WM_DEVICECHANGE            = 0x0219;
        const int DBT_DEVICEARRIVAL            = 0x8000; 
        const int DBT_DEVICEREMOVECOMPLETE    = 0x8004;
        
        [StructLayout(LayoutKind.Sequential)]
        public struct DEV_BROADCAST_HDR
        {
            public int dbch_size;
            public int dbch_devicetype;
            public int dbch_reserved;
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_DEVICECHANGE)
            {
                int EventCode = m.WParam.ToInt32();
                Log(string.Format("WM_DEVICECHANGE. Код={0}", EventCode));

                switch (EventCode)
                {
                    case DBT_DEVICEARRIVAL:
                    {
                        Log("Добавление устройства");
                        break;
                    }
                    case DBT_DEVICEREMOVECOMPLETE:
                    {
                        Log("Удаление устройства");
                        break;
                    }
                }
            }
            base.WndProc (ref m);

        }

        private void Log(string s)
        {
            listBox1.Items.Add(s);
            listBox1.SelectedIndex = listBox1.Items.Count-1;
        }

    }




Подробности тут: здесь.
Re[2]: обработка WM_DEVICECHANGE
От: Аноним  
Дата: 13.05.06 15:44
Оценка:
Здравствуйте, Pavel_Agurov, Вы писали:

P_A>Конкретно про USB.


Спасибо за Ваш ответ.
То что оно появилось или удалилось я и так знаю, мне не интересно какое это устройство диск, порт или еще что то, мне конкретно нужно знать какое устройство USB подключилось — его HARDWARE ID
Re[3]: обработка WM_DEVICECHANGE
От: Геннадий Майко США  
Дата: 13.05.06 16:17
Оценка:
Здравствуйте, Аноним,

А>Спасибо за Ваш ответ.

А>То что оно появилось или удалилось я и так знаю, мне не интересно какое это устройство диск, порт или еще что то, мне конкретно нужно знать какое устройство USB подключилось — его HARDWARE ID
--
Можно попробовать определить HARWARE_ID нового устройства (кстати, а почему именно нужно знать HARDWARE_ID ?) следующим образом.
Напишите функцию перечисления всех устройств USB с помощью функций SetupDiXxx (SetupDiGetClassDevs, SetupDiEnumDeviceInfo) и получите для всех этих устройств их HARDWARE_ID (SetupDiGetDeviceRegistryProperty, SPDRP_HARDWAREID).
Вызовите эту функцию и запомните все эти HARDWARE_ID до регистрации получения WM_DEVICECHANGE. По появлению нового устройства вновь вызывайте эту функцию и сравнивайте вновь полученный список HARDWARE_ID с запомненным для нахождения новых HARDWARE_ID.

C уважением,
Геннадий Майко.
Re[4]: обработка WM_DEVICECHANGE
От: Аноним  
Дата: 13.05.06 16:21
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:

ГМ>Здравствуйте, Аноним,


А>>Спасибо за Ваш ответ.

А>>То что оно появилось или удалилось я и так знаю, мне не интересно какое это устройство диск, порт или еще что то, мне конкретно нужно знать какое устройство USB подключилось — его HARDWARE ID
ГМ>--
ГМ>Можно попробовать определить HARWARE_ID нового устройства (кстати, а почему именно нужно знать HARDWARE_ID ?) следующим образом.
ГМ>Напишите функцию перечисления всех устройств USB с помощью функций SetupDiXxx (SetupDiGetClassDevs, SetupDiEnumDeviceInfo) и получите для всех этих устройств их HARDWARE_ID (SetupDiGetDeviceRegistryProperty, SPDRP_HARDWAREID).
ГМ>Вызовите эту функцию и запомните все эти HARDWARE_ID до регистрации получения WM_DEVICECHANGE. По появлению нового устройства вновь вызывайте эту функцию и сравнивайте вновь полученный список HARDWARE_ID с запомненным для нахождения новых HARDWARE_ID.

Так собсвенно и делаю, просто думал может есть какой то способ внутри обработчика узнать от системы какое устройство подключилось или отключилось.

ГМ>C уважением,

ГМ>Геннадий Майко.
Re[3]: обработка WM_DEVICECHANGE
От: Pavel_Agurov Россия  
Дата: 13.05.06 17:07
Оценка:
Извините, не понял сразу. Действительно Вы спросили про ID

Вот такой код, надеюсь подойдет. Я правда его Name обозвал, в общем смысл — что имя передается в поле dbcc_name.


unit U_Usb;

interface

uses
  Windows, Messages, SysUtils, Classes, Forms;

type

  TNotifyUSBEvent = procedure(Sender: TObject; Name : String) of object;

  PDevBroadcastHdr  = ^DEV_BROADCAST_HDR;
  DEV_BROADCAST_HDR = packed record
    dbch_size: DWORD;
    dbch_devicetype: DWORD;
    dbch_reserved: DWORD;
  end;

  PDevBroadcastDeviceInterface  = ^DEV_BROADCAST_DEVICEINTERFACE;
  DEV_BROADCAST_DEVICEINTERFACE = record
    dbcc_size: DWORD;
    dbcc_devicetype: DWORD;
    dbcc_reserved: DWORD;
    dbcc_classguid: TGUID;
    dbcc_name: Array [1..1024] of char;
  end;

const
  GUID_DEVINTERFACE_USB_DEVICE: TGUID = '{A5DCBF10-6530-11D2-901F-00C04FB951ED}';
  DBT_DEVICEARRIVAL          = $8000;          // system detected a new device
  DBT_DEVICEREMOVECOMPLETE   = $8004;          // device is gone
  DBT_DEVTYP_DEVICEINTERFACE = $00000005;      // device interface class

type

  TComponentUSB = class(TComponent)
  private
    FWindowHandle: HWND;
    FOnUSBArrival: TNotifyUSBEvent;
    FOnUSBRemove: TNotifyUSBEvent;
    procedure WndProc(var Msg: TMessage);
    function USBRegister: Boolean;
  protected
    procedure WMDeviceChange(var Msg: TMessage); dynamic;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property OnUSBArrival: TNotifyUSBEvent read FOnUSBArrival write FOnUSBArrival;
    property OnUSBRemove: TNotifyUSBEvent  read FOnUSBRemove  write FOnUSBRemove;
  end;

implementation

constructor TComponentUSB.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FWindowHandle := AllocateHWnd(WndProc);
  USBRegister;
end;

destructor TComponentUSB.Destroy;
begin
  DeallocateHWnd(FWindowHandle);
  inherited Destroy;
end;

procedure TComponentUSB.WndProc(var Msg: TMessage);
begin
  if (Msg.Msg = WM_DEVICECHANGE) then 
  begin
    try
      WMDeviceChange(Msg);
    except
      Application.HandleException(Self);
    end;
  end
  else
    Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.wParam, Msg.lParam);
end;

procedure TComponentUSB.WMDeviceChange(var Msg: TMessage);
var
  devType: Integer;
  Datos: PDevBroadcastHdr;
  Device : PDevBroadcastDeviceInterface;
  Name   : String;
begin
  if (Msg.wParam = DBT_DEVICEARRIVAL) or (Msg.wParam = DBT_DEVICEREMOVECOMPLETE) then
  begin
    Datos := PDevBroadcastHdr(Msg.lParam);
    devType := Datos^.dbch_devicetype;
    if devType = DBT_DEVTYP_DEVICEINTERFACE then
    begin // USB Device
      if Msg.wParam = DBT_DEVICEARRIVAL then
      begin
        Device:= PDevBroadcastDeviceInterface(Msg.LParam);
        Name:= Device^.dbcc_name;
        if Assigned(FOnUSBArrival) then
          FOnUSBArrival(Self, Name);
      end 
      else 
      begin
        Device:= PDevBroadcastDeviceInterface(Msg.LParam);
        Name:= Device^.dbcc_name;
        if Assigned(FOnUSBRemove) then
          FOnUSBRemove(Self, Name);
      end;
    end;
  end;
end;

function TComponentUSB.USBRegister: Boolean;
var
  dbi: DEV_BROADCAST_DEVICEINTERFACE;
  Size: Integer;
  r: Pointer;
begin
  Result := False;
  Size := SizeOf(DEV_BROADCAST_DEVICEINTERFACE);
  ZeroMemory(@dbi, Size);
  dbi.dbcc_size := Size;
  dbi.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
  dbi.dbcc_reserved := 0;
  dbi.dbcc_classguid  := GUID_DEVINTERFACE_USB_DEVICE;


  r := RegisterDeviceNotification(FWindowHandle, @dbi,
    DEVICE_NOTIFY_WINDOW_HANDLE
    );
  if Assigned(r) then Result := True;
end;

end.



Используется так:


procedure TForm1.FormCreate(Sender: TObject);
begin
 USB:= TComponentUSB.Create(Self);
 USB.OnUSBArrival:= OnUSBArrival;
 USB.OnUSBRemove := OnUSBRemove;
end;

procedure TForm1.OnUSBArrival(Sender: TObject;  Name : String);
begin
 lbDevice.Items.Add('OnUSBArrival>'+Name);
end;

procedure TForm1.OnUSBRemove(Sender: TObject;  Name : String);
begin
 lbDevice.Items.Add('OnUSBRemove>'+Name);
end;
Re[4]: обработка WM_DEVICECHANGE
От: Аноним  
Дата: 13.05.06 17:40
Оценка:
Здравствуйте, Pavel_Agurov, Вы писали:

P_A>Извините, не понял сразу. Действительно Вы спросили про ID


P_A>Вот такой код, надеюсь подойдет. Я правда его Name обозвал, в общем смысл — что имя передается в поле dbcc_name.


Спасибо. Буду разбираться
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.