Как распознавать подсоединение флэшки?

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
Аватара пользователя
McLion
постоялец
Сообщения: 332
Зарегистрирован: 06.02.2015 17:41:00

Как распознавать подсоединение флэшки?

Сообщение McLion »

Всем привет,

подскажите как распознавать подсоединение флэшки или когда ее извлекают? То есть сам процесс как найти флэшку я знаю, я ищу только тот момент когда флэшку втыкают и извлекают. Сейчас я "сканирую" все диски таймером и так узнаю, добавилось что то или убавилось. Но это как то не профессионально.

Как получать инфу от Windows о том подключили флэш-устроиство или извлекли?

Пасиб!
Аватара пользователя
McLion
постоялец
Сообщения: 332
Зарегистрирован: 06.02.2015 17:41:00

Сообщение McLion »

Нашел вот этот код, но не пойму как добавить, что бы узнавались и SD-Card? Кто может подсказать?

Код: Выделить всё

unit Unit1; 
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  Windows;
 
type
  { TForm1 }
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
const
  GUID_DEVINTERFACE_USB_DEVICE: TGUID = '{A5DCBF10-6530-11D2-901F-00C04FB951ED}';
 
var
  Form1: TForm1;
 
implementation
uses JwaWinUser, JwaDbt;
 
{$R *.lfm}
 
type
  TMWndProc = Windows.WNDPROC;
 
var
   OldWndProc : TMWndProc;
 
function MyWndProc(my_wnd : HWND; Msg : UINT;
                   my_wparam : WPARAM; my_lparam : LPARAM) : LRESULT; stdcall;
var
  devType : Integer;
  Datos : PDevBroadcastHdr;
begin
  Result := 0;
  case Msg of
    WM_DEVICECHANGE:
    begin
      if (my_wparam = DBT_DEVICEARRIVAL) or (my_wparam = DBT_DEVICEREMOVECOMPLETE) then
      begin
        Datos := PDevBroadcastHdr(Pointer(my_lparam));
        devType := Datos^.dbch_devicetype;
        if devType = DBT_DEVTYP_DEVICEINTERFACE then
        begin
           if my_wparam = DBT_DEVICEARRIVAL then
              ShowMessage('USB устройство подключено')
           else
              ShowMessage('USB устройство отключено');
        end;
      end;
 
      // Здесь нужно, если не ошибаюсь, вернуть результат:
      // Return TRUE to grant the request
      // Return BROADCAST_QUERY_DENY to deny the request.
 
    end; // WM_DEVICECHANGE
  end; // case
  Result := Windows.CallWindowProc(OldWndProc, my_wnd, Msg, my_wparam, my_lparam);
end;
 
procedure TForm1.FormCreate(Sender: TObject);
var
  dbi: DEV_BROADCAST_DEVICEINTERFACE_W;
  Size: Integer;
  RDN: HDEVNOTIFY;
  arr : array[0 .. 0] of word;
begin
  arr[0] := 0;
  Size := SizeOf(DEV_BROADCAST_DEVICEINTERFACE_W);
  ZeroMemory(@dbi, Size);
  dbi.dbcc_size := Size;
  dbi.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
  dbi.dbcc_reserved := 0;
  dbi.dbcc_classguid  := GUID_DEVINTERFACE_USB_DEVICE;
  dbi.dbcc_name := arr;
  RDN := RegisterDeviceNotificationW(Form1.Handle, @dbi,
                                     DEVICE_NOTIFY_WINDOW_HANDLE);
  if not Assigned(RDN) then
  begin
    ShowMessage('Error Register Message');
  end;
 
  OldWndProc := TMWndProc(Windows.GetWindowLong(Self.Handle, GWL_WNDPROC));
  Windows.SetWindowLong(Self.Handle, GWL_WNDPROC, LongInt(@MyWndProc));
end;
 
end.
Аватара пользователя
Pavia
постоялец
Сообщения: 290
Зарегистрирован: 07.01.2011 11:46:51

Сообщение Pavia »

Ещё надо добавить
TDEV_BROADCAST_VOLUME

Код: Выделить всё

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
   procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE;
    { Private declarations }
  public
    { Public declarations }
  end;

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

  PTDEV_BROADCAST_DEVICEINTERFACE  = ^TDEV_BROADCAST_DEVICEINTERFACE;
  TDEV_BROADCAST_DEVICEINTERFACE =  record
    dbcc_size: DWORD;
    dbcc_devicetype: DWORD;
    dbcc_reserved: DWORD;
    dbcc_classguid: TGUID;
    dbcc_name: short;
  end;
  PDEV_BROADCAST_VOLUME=^TDEV_BROADCAST_VOLUME;
  TDEV_BROADCAST_VOLUME=  record
    dbcv_size: DWORD;
    dbcv_devicetype: DWORD;
    dbcv_reserved: DWORD;
    dbcv_unitmask:DWord;
    dbcv_flags:Word;
    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
  DBT_DEVTYP_VOLUME          = $00000002;
var
  Form1: TForm1;
  QarantinDir:String='c:\Qarantin\';
implementation

{$R *.dfm}

procedure LogAdd(Text:String);
begin

end;

procedure ToQarantin(FullFileName:String);
var
 Path,FileName:String;
begin

 Zip(Path+FileName,QarantinDir+FileName);
 LogAdd('File copy to Qarantin:'''+FileName+'''');

end;

procedure DeleteFile(FileName:String);
begin
 if DeleteFile(FileName)  then
    begin
    LogAdd('File deleted:'''+FileName+'''');
    end else
    begin
    LogAdd('File not deleted:'''+FileName+'''');
    end;
end;

procedure DetectAutorun(Volume:string);
var
  SearchRec : TSearchRec;
  FileDesc:PFileDesc;
  Mask:String;
begin
Mask:='Autorun.inf'
 if FindFirst(Volume+Mask, faAnyFile, SearchRec) = 0 then
    begin
    IF (SearchRec.Attr and faDirectory) <> faDirectory then
       begin
       ToQarantin(Volume,Mask);
       DeleteFile(Volume+Mask);
       end;

    end;
end;

procedure DetectVirusOnFlash(volume:String);
begin
DetectAutorun(Volume);
end;

procedure DetectFlash;
var
  drive:string;
  t:UInt;
  p:PChar;
  i,Len:Integer;
begin
    p:=nil;
    Len:=GetLogicalDriveStrings(0,p);
    GetMem(p,Len+1);
    Len:=GetLogicalDriveStrings(Len,p);
    drive:='';
    for i := 0 to Len-1 do          // Определяем букву устройства
      begin
       if p[i]<>#0 then
          begin
            drive:=drive+p[i];
          end
          else
          begin
          t:=GetDriveType(PChar(drive));
          if t=DRIVE_REMOVABLE then //Проверяем тип устройства
                                                        // Если это флешка, то...
             begin
             DetectVirusOnFlash(drive);
             //showmessage('Была воткнута Флешка');
              //....
             end;
          drive:='';
          end;
      end;
    FreeMem(p);
end;

procedure TForm1.WMDeviceChange(var Msg: TMessage);
var
  devType: Integer;
  Datos: PDevBroadcastHdr;
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_VOLUME then
    begin // USB Device
      if Msg.wParam = DBT_DEVICEARRIVAL then
      begin
        DetectFlash;
        //showmessage('Устройство подключено');       // Усройство подключено
        //.....
      end
      else
      begin
        //showmessage('Устройство ОТКЛЮЧЕНО');
        //.....
      end;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  dbi: TDEV_BROADCAST_DEVICEINTERFACE;
  dbv: TDEV_BROADCAST_VOLUME;
  Size: Integer;
  r: Pointer;
begin
  Size := SizeOf(TDEV_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;
  dbi.dbcc_name := 0;
  r := RegisterDeviceNotification(Form1.Handle, @dbi, DEVICE_NOTIFY_WINDOW_HANDLE);
  if not Assigned(r) then
   ShowMessage('Error Register Message');

  Size := SizeOf(TDEV_BROADCAST_VOLUME);
  ZeroMemory(@dbv, Size);
  dbv.dbcv_size := Size;
  dbv.dbcv_devicetype := DBT_DEVTYP_VOLUME;
  dbv.dbcv_reserved := 0;
  dbv.dbcv_flags := 0;
  r := RegisterDeviceNotification(Form1.Handle, @dbi, DEVICE_NOTIFY_WINDOW_HANDLE);
  if not Assigned(r) then
   ShowMessage('Error Register Message');
end;

end.
Аватара пользователя
McLion
постоялец
Сообщения: 332
Зарегистрирован: 06.02.2015 17:41:00

Сообщение McLion »

А зачем это добавлять? Это пример под Lazarus или Delphi?
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 839
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

У функции GetDriveType для флешки и флеш-карты разные константы возвращаются, может у тебя тоже все дело в том что ты получаешь оповещение о целом устройстве, а не съемном носителе для устройства.
Аватара пользователя
McLion
постоялец
Сообщения: 332
Зарегистрирован: 06.02.2015 17:41:00

Сообщение McLion »

Я GetDriveType не использую...
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 839
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

McLion писал(а):Я GetDriveType не использую...

Ты увидел слово GetDriveType , а надо было
для флешки и флеш-карты разные константы возвращаются


Выше Pavia привел пример. У тебя в FormCreate регистрируется одно оповещение, как я вижу, а у него в коде в том же FormCreate регистрируется два оповещения, для двух типов носителей.
Аватара пользователя
McLion
постоялец
Сообщения: 332
Зарегистрирован: 06.02.2015 17:41:00

Сообщение McLion »

А что если просто

Код: Выделить всё

if devType = DBT_DEVTYP_DEVICEINTERFACE then
поменять на

Код: Выделить всё

if devType = DBT_DEVTYP_VOLUME then
??? После того как TDEV_BROADCAST_VOLUME добавить? Вроде работает, и флеш-карты узнает!

Добавлено спустя 12 часов 43 минуты 36 секунд:
Pavia писал(а):Ещё надо добавить
TDEV_BROADCAST_VOLUME


По моему у тебя ошибка в коде, @dbi нужно на @dbv поменять, во второй функции RegisterDeviceNotification.

Код: Выделить всё

  r := RegisterDeviceNotification(Form1.Handle, @dbi, DEVICE_NOTIFY_WINDOW_HANDLE);

Код: Выделить всё

  r := RegisterDeviceNotification(Self.Handle, @dbv, DEVICE_NOTIFY_WINDOW_HANDLE);
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

Не в первый раз наблюдаю, что интерес к одной и той же теме возникает сразу в нескольких местах.
Это потому что все на одних и тех же фрилансах сайтах работают?
Аватара пользователя
Pavia
постоялец
Сообщения: 290
Зарегистрирован: 07.01.2011 11:46:51

Сообщение Pavia »

Код из черновика. Особо не гонял
McLion писал(а):По моему у тебя ошибка в коде, @dbi нужно на @dbv поменять, во второй функции RegisterDeviceNotification.

Да.
Сообщения надо зарегистрировать на прием. Иначе форма их вообще не будет получать.
Но учти разные карт-ридеры работают по разному. Кто-то генерирует оба сообщения, а кто-то только одно.
И плюс CD-карты и флешки могут быть не отформатированными. И скорее всего они не будут генерировать VOLUME.
Аватара пользователя
McLion
постоялец
Сообщения: 332
Зарегистрирован: 06.02.2015 17:41:00

Сообщение McLion »

Я так посмотрел на весь этот винегрет и подумал, что буду сканировать таймером все диски и таким образом всегда буду знать, что добавилось или отнялось. Как то проще все будет, хоть и не совсем элегантно.
Ответить