Конференция "KOL" » Как програмно остановить USB-Flash? [Delphi]
 
  • Grademax (12.10.06 09:11) [0]
    Как програмно остановить USB-Flash? Если можно, то пример на чистом KOL
  • ANTPro © (12.10.06 11:23) [1]
    может на апи ?
  • Grademax (12.10.06 11:46) [2]
    Почему бы и нет? Думаю без API здесь не обойтись...
  • ANTPro © (12.10.06 12:00) [3]
    Вопрос. Зачем?
    Средствами Выни её не всегда тормознуть :(
    особенно если файловая НТФС
  • Grademax (12.10.06 12:28) [4]
    Так получилось, что наша контора закупила 12 ПК. Комплектация у всех одинаковая (в частности здорово глючили мамы на предмет работы USB портов). Наступил момент, когда USB порт перестал опознаваться вообще. Проблема решилась перепрошивкой BIOSa, но остался неприятный глюк - при работе с любыми фрешками не загорается значек в трее "Безопасное извлечение устройства". Можно конечно переустановить OS, но придется устанавливать целую гору ПО. Да и неохота, ведь в остальном всё работает стабильно.
    Решение проблемы я вижу в следующем:
    1) Написать програмку (замену стандартного "Безопасного извлечения устройства") - это конечно лучше (может ещё когда сгодится для чего-нибудь)
    2) Найти как эта функция включается например в реестре (если конечно там).

    В общем я в поисках и буду рад любой помощи по этому вопросу...
  • Thaddy (12.10.06 12:57) [5]
    Here's some code, but it needs to be extended a little to handle
    the foillowing WM_DEVICECHANGE messages
    1. DBT_DEVICEQUERYREMOVE  // broadcast this for the device to remove
    2. DBT_DEVICEQUERYREMOVEFAILED // handle this in an event handler

    unit KolUsb;
    // original VCL by miguel lucero
    // KOL translation Thaddy de Koning
    interface

    uses
     Windows, Messages, Kol, Objects;

    type
     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: short;
     end;

    const
     GUID_DEVINTERFACE_USB_DEVICE: TGUID = '{A5DCBF10-6530-11D2-901F-00C04FB951ED}';
     DBT_DEVICEARRIVAL          = $8000;
     DBT_DEVICEREMOVECOMPLETE   = $8004;
     DBT_DEVTYP_DEVICEINTERFACE = $00000005;

    type

     PKolUSB = ^ TKolUSB;
     TKolUSB= object(Tobj)
     private
       FWindowHandle: HWND;
       FOnUSBArrival: TNotifyEvent;
       FOnUSBRemove: TNotifyEvent;
       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: TNotifyEvent read FOnUSBArrival write FOnUSBArrival;
       property OnUSBRemove: TNotifyEvent read FOnUSBRemove write FOnUSBRemove;
     end;

    implementation

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

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

    procedure TKolUSB.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 TKolUSB.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_DEVICEINTERFACE then
       begin
         if Msg.wParam = DBT_DEVICEARRIVAL then
         begin
           if Assigned(FOnUSBArrival) then
             FOnUSBArrival(Self);
         end
         else
         begin
           if Assigned(FOnUSBRemove) then
             FOnUSBRemove(Self);
         end;
       end;
     end;
    end;

    function TKolUSB.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;
     dbi.dbcc_name := 0;

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

    end.


  • Thaddy (12.10.06 13:02) [6]
    And you have to remove Application handle exception. I was to fast translating this ;) This is better:


    unit KolUsb;
    // original VCL by miguel lucero
    // KOL translation Thaddy de Koning
    interface

    uses
     Windows, Messages, Kol, Objects;

    type
     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: short;
     end;

    const
     GUID_DEVINTERFACE_USB_DEVICE: TGUID = '{A5DCBF10-6530-11D2-901F-00C04FB951ED}';
     DBT_DEVICEARRIVAL          = $8000;
     DBT_DEVICEREMOVECOMPLETE   = $8004;
     DBT_DEVTYP_DEVICEINTERFACE = $00000005;

    type

     PKolUSB = ^ TKolUSB;
     TKolUSB= object(Tobj)
     private
       FWindowHandle: HWND;
       FOnUSBArrival: TOnEvent;
       FOnUSBRemove: TOnEvent;
       procedure WndProc(var Msg: TMessage);
       function USBRegister: Boolean;
     protected
       procedure WMDeviceChange(var Msg: TMessage);
     public
       destructor Destroy; virtual;
       property OnUSBArrival: TOnEvent read FOnUSBArrival write FOnUSBArrival;
       property OnUSBRemove: TOnEvent read FOnUSBRemove write FOnUSBRemove;
     end;

    function NewKolUSB:PKolUSB;

    implementation

    function NewKolUSB:PKolUSB;
    begin
     New(Result,Create);
     Result.FWindowHandle := AllocateHWnd(Result.WndProc);
     Result.USBRegister;
    end;

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

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

    procedure TKolUSB.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_DEVICEINTERFACE then
       begin
         if Msg.wParam = DBT_DEVICEARRIVAL then
         begin
           if Assigned(FOnUSBArrival) then
             FOnUSBArrival(@Self);
         end
         else
         begin
           if Assigned(FOnUSBRemove) then
             FOnUSBRemove(@Self);
         end;
       end;
     end;
    end;

    function TKolUSB.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;
     dbi.dbcc_name := 0;

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

    end.


  • [e]Bu$ter © (12.10.06 13:16) [7]
    Зачем тратить время? На это дело, есть куча готовых решений, вот например, пока в FAR manager не встроили эту фишку (возможность отключать сменные девайсы) я узал DevEject - http://www.heise.de/ct/03/25/links/206.shtml
    // там, если я не ошибаюсь, да же сорцы прилагаюстся, только на С++
  • AndreyRus (12.10.06 15:52) [8]

    program USBEject;

    uses
    Windows;

    const
    setupapi = 'SetupApi.dll';

    type
    HDEVINFO = THandle;

    PSP_DEVINFO_DATA = ^SP_DEVINFO_DATA;
    SP_DEVINFO_DATA = packed record
    cbSize: DWORD;
    ClassGuid: TGUID;
    DevInst: DWORD;
    Reserved: DWORD;
    end;

    function SetupDiGetClassDevsA(ClassGuid: PGUID; Enumerator: PChar; hwndParent: HWND; Flags: DWORD): HDEVINFO; stdcall; external setupapi;
    function SetupDiEnumDeviceInfo(DeviceInfoSet: HDEVINFO; MemberIndex: DWORD; DeviceInfoData: PSP_DEVINFO_DATA): boolean; stdcall; external setupapi;
    function SetupDiDestroyDeviceInfoList(DeviceInfoSet: HDEVINFO): boolean; stdcall; external setupapi;
    function CM_Get_Parent(pdnDevInst: PDWORD; dnDevInst: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi;
    function CM_Get_Device_ID_Size(pulLen: PDWORD; dnDevInst: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi;
    function CM_Get_Device_IDA(dnDevInst: DWORD; Buffer: PChar; BufferLen: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi;
    function CM_Locate_DevNodeA(pdnDevInst: PDWORD; pDeviceID: PChar; ulFlags: DWORD): DWORD; stdcall; external setupapi;
    function CM_Request_Device_EjectA(dnDevInst: DWORD; pVetoType: Pointer; pszVetoName: PChar; ulNameLength: DWORD;
    ulFlags: DWORD): DWORD; stdcall; external setupapi;

    function IsUSBDevice(DevInst: DWORD): boolean;
    function CompareMem(p1, p2: Pointer; len: DWORD): boolean;
    var
    i: DWORD;
    begin
    result := false;
    if len = 0 then exit;
    for i := 0 to len-1 do
     if PByte(DWORD(p1) + i)^ <> PByte(DWORD(p2) + i)^ then exit;
    result := true;
    end;
    var
    IDLen: DWORD;
    ID: PChar;
    begin
    result := false;
    if (CM_Get_Device_ID_Size(@IDLen, DevInst, 0) <> 0) or (IDLen = 0) then exit;
    inc(IDLen);
    ID := GetMemory(IDLen);
    if ID = nil then exit;
    if (CM_Get_Device_IDA(DevInst, ID, IDLen, 0) <> 0) or (not CompareMem(ID, PChar('USBSTOR'), 7)) then
    begin
     FreeMemory(ID);
     exit;
    end;
    FreeMemory(ID);
    result := true;
    end;

    procedure EjectUSB();
    const
    GUID_DEVCLASS_DISKDRIVE: TGUID = (D1: $4D36E967; D2: $E325; D3: $11CE; D4: ($BF, $C1, $08, $00, $2B, $E1, $03, $18));
    var
    hDevInfoSet: HDEVINFO;
    DevInfo: SP_DEVINFO_DATA;
    i: Integer;
    Parent: DWORD;
    VetoName: PChar;
    begin
    DevInfo.cbSize := sizeof(SP_DEVINFO_DATA);
    hDevInfoSet := SetupDiGetClassDevsA(@GUID_DEVCLASS_DISKDRIVE, nil, 0, 2);
    if hDevInfoSet = INVALID_HANDLE_VALUE then exit;
    i := 0;
    while (SetupDiEnumDeviceInfo(hDevInfoSet, i, @DevInfo)) do
    begin
     if (IsUSBDevice(DevInfo.DevInst)) and (CM_Get_Parent(@Parent, DevInfo.DevInst, 0) = 0) then
      begin
       VetoName := GetMemory(260);
       if (CM_Request_Device_EjectA(Parent, nil, VetoName, 260, 0) <> 0) then
        begin
         if (CM_Locate_DevNodeA(@Parent, VetoName, 0) <> 0) then
          begin
           FreeMemory(VetoName);
           continue;
          end;
         FreeMemory(VetoName);
         if (CM_Request_Device_EjectA(Parent, nil, nil, 0, 0) <> 0) then continue;
        end;
       FreeMemory(VetoName);
       break;
      end;
     inc(i);
    end;
    SetupDiDestroyDeviceInfoList(hDevInfoSet);
    end;

    begin
    if MessageBoxA(0, 'Вы действительно хотите извлечь USB-диск?', 'Подтверждение', MB_YESNO) = ID_YES then
    EjectUSB();
    end.

  • Grademax (13.10.06 05:17) [9]
    Спасибо за помощь! Всё работает как часы! Проверял!
  • Doom-2 (10.05.07 13:29) [10]
    А конкретное как? D: F: ...
  • DVK (14.05.07 07:21) [11]
    Как остановить USB Flash понятно. А может кто знает, как заставить Windows снова обнаружить USB устройство, если оно было только программно извлечено из компьютера, а физически не извлекалось, то есть "пересканировать" USB-устройства?
  • ANTPro © (14.05.07 14:13) [12]
    > [11] DVK   (14.05.07 07:21)

    Так лень флешку вытащить? : )
  • DVK (16.05.07 12:28) [13]
    Да нет, не в этом дело, хотя и лень тоже:)
    Я написал программу для проверки правильности записи информации на USB флэшку. Но вот только сразу после записи файлов на флэш их проверять нельзя, поскольку Winows как-то кэширует информацию, и вместо реального чтения с USB устройства подсовывает данные из своего кэша. Необходимо извлечь устройство, а затем снова вставить его в компьютер. Мне захотелось сделать это программно. Извлечь удалось, а вот снова "Вставить" - нет.
  • Thaddy (16.05.07 12:34) [14]
    My code detects USB insert.
  • AndreyRus (16.05.07 12:34) [15]
    Use google. "Rescan SetupApi".
  • DVK (17.05.07 15:31) [16]
    2AndreyRus
    Спасибо, решил использовать devcon.exe restart usb\*
  • Daemvil © (20.08.07 16:18) [17]
    Так как же сделать так, чтобы можно было вытаскивать флеш-диск, зная только его букву?...
  • Andrey_rus © (20.08.07 16:58) [18]
    А причем здесь KOL? Итак ветка не по теме!
  • CraZy_MaTH (26.08.07 02:49) [19]
    нашел программку, при запуске её с флешки закрывает все программы и вытаскивает флешку безопасно.
    http://code.google.com/p/pr-safe-eject/
  • имя (17.09.07 22:47) [20]
    Удалено модератором
  • имя (01.12.07 02:45) [21]
    Удалено модератором
  • имя (12.05.08 15:54) [22]
    Удалено модератором
 
Конференция "KOL" » Как програмно остановить USB-Flash? [Delphi]
Есть новые Нет новых   [134431   +14][b:0][p:0.006]