-
Как програмно остановить USB-Flash? Если можно, то пример на чистом KOL
-
может на апи ?
-
Почему бы и нет? Думаю без API здесь не обойтись...
-
Вопрос. Зачем? Средствами Выни её не всегда тормознуть :( особенно если файловая НТФС
-
Так получилось, что наша контора закупила 12 ПК. Комплектация у всех одинаковая (в частности здорово глючили мамы на предмет работы USB портов). Наступил момент, когда USB порт перестал опознаваться вообще. Проблема решилась перепрошивкой BIOSa, но остался неприятный глюк - при работе с любыми фрешками не загорается значек в трее "Безопасное извлечение устройства". Можно конечно переустановить OS, но придется устанавливать целую гору ПО. Да и неохота, ведь в остальном всё работает стабильно. Решение проблемы я вижу в следующем: 1) Написать програмку (замену стандартного "Безопасного извлечения устройства") - это конечно лучше (может ещё когда сгодится для чего-нибудь) 2) Найти как эта функция включается например в реестре (если конечно там).
В общем я в поисках и буду рад любой помощи по этому вопросу...
-
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;
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 = '';
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.
-
And you have to remove Application handle exception. I was to fast translating this ;) This is better:
unit KolUsb;
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 = '';
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.
-
Зачем тратить время? На это дело, есть куча готовых решений, вот например, пока в FAR manager не встроили эту фишку (возможность отключать сменные девайсы) я узал DevEject - http://www.heise.de/ct/03/25/links/206.shtml // там, если я не ошибаюсь, да же сорцы прилагаюстся, только на С++
-
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.
-
Спасибо за помощь! Всё работает как часы! Проверял!
-
А конкретное как? D: F: ...
-
Как остановить USB Flash понятно. А может кто знает, как заставить Windows снова обнаружить USB устройство, если оно было только программно извлечено из компьютера, а физически не извлекалось, то есть "пересканировать" USB-устройства?
-
> [11] DVK (14.05.07 07:21)
Так лень флешку вытащить? : )
-
Да нет, не в этом дело, хотя и лень тоже:) Я написал программу для проверки правильности записи информации на USB флэшку. Но вот только сразу после записи файлов на флэш их проверять нельзя, поскольку Winows как-то кэширует информацию, и вместо реального чтения с USB устройства подсовывает данные из своего кэша. Необходимо извлечь устройство, а затем снова вставить его в компьютер. Мне захотелось сделать это программно. Извлечь удалось, а вот снова "Вставить" - нет.
-
My code detects USB insert.
-
Use google. "Rescan SetupApi".
-
2AndreyRus Спасибо, решил использовать devcon.exe restart usb\*
-
Так как же сделать так, чтобы можно было вытаскивать флеш-диск, зная только его букву?...
-
А причем здесь KOL? Итак ветка не по теме!
-
|