Страницы

Поиск по вопросам

Показаны сообщения с ярлыком usb. Показать все сообщения
Показаны сообщения с ярлыком usb. Показать все сообщения

вторник, 31 марта 2020 г.

Как в Windows 10 сделать так, чтобы USB флеш-накопители не надо было отключать отдельной командой?

#windows #администрирование #windows_10 #usb


Как известно, в Windows, когда завершаешь операции с  USB флеш-накопителем, его надо
отключить отдельной командой. После этой команды появляется сообщение "теперь накопитель
ХХХ можно удалить".

Надоело мне каждый раз отключать USB флеш-накопители отдельной командой. Помнится
мне, что когда в ходу были дискеты, то для них не было никакой отдельной команды для
отключения. Конец операции копирования на дискету означал, что дискету можно вынимать.

Вопрос:

Как в Windows 10 сделать так, чтобы не надо было отключать USB флеш-накопители отдельной
командой? Хочу, чтобы как при работе с дискетами, окончание операции копирования (чтения
или записи) означало, что USB флеш-накопитель можно вынимать.
    


Ответы

Ответ 1



Втыкаем флешку. Идем в Диспетчер устройств, находим в нем флешку, правый клик - Свойства. Во второй вкладке активируем верхнюю опцию "Быстрое удаление". Важно: окончание операции записи/копирования определяется не исчезновением индикатора процесса копирования, а тем, что на флешке перестал мигать светодиод. PS. Это в Вин7. Если в Вин10 не так, то удалю ответ.

Как получить информацию о подключенном устройстве?

#linux #windows #qt #winapi #usb


Я пишу на С++, использую Qt под Windows. Мне надо получить: название модели, изготовителя,
серийный номер устройства(видео камеры, фото , квадрокоптера , флешки или SD Card)
и путь до устройства. Желательно кроссплатформенное решение.


Есть ответ SetupDiGetDeviceProperty. Но тут не кроссплатформенное решение , к тому
же я не совсем понимаю как получить путь до устройства.
Читал о библиотеки libusb. Но тут не выводятся название модели, изготовителя, серийный
номер устройства. То что выводиться :

Dev (bus 2, device 0): 8086 - 1E31
Dev (bus 1, device 4): 04A9 - 1795
Dev (bus 1, device 3): A4Tech - USB Mouse
Dev (bus 3, device 0): 8086 - 1E26
Dev (bus 1, device 1): 8087 - 0024
Dev (bus 1, device 0): 8086 - 1E2D
Dev (bus 1, device 2): 0BDA - 0151
Dev (bus 1, device 6): Logitech Inc. - Logitech USB Headset H340
Dev (bus 3, device 2): 8087 - 0024
Dev (bus 3, device 3): Logitech - USB Keyboard
Dev (bus 3, device 1): 04A9 - 3206


Хотя была вставлена флешка и подключена камера.
Есть изящное решение этой задачи. Если кто сталкивался с такой задачей поделитесь
кодом пожалуйста.
    


Ответы

Ответ 1



К сожалению, используя библиотеку libusb под Windows нельзя вытянуть всю эту информацию без установки специального драйвера WinUSB. Можно только получить VID и PID (шестнадцатеричные значения типа 8086 - 1E31 в вашем примере), и по ним найти производителя и устройство в таблице известных идентификаторов, например здесь. Производителя и серийный номер можно получить, используя Setup API и IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION. Букву диска тоже можно получить только средствами Setup API, это несколько сложнее. Для этого нужно вначале построить таблицу номеров дисков для всех используемых букв дисков с помощью IOCTL_STORAGE_GET_DEVICE_NUMBER; затем открыть интересующее устройство (запоминающее устройство, которое является дочерним для USB-устройства), найти его номер тем же IOCTL, сравнить его со значениями из таблицы и таким образом определить букву. Как-то так: #include #include #include #include #include #include #include #undef LowSpeed #include #include #pragma comment(lib,"Setupapi.lib") void ErrorMes(LPCTSTR lpszFunction) { // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; LPVOID lpDisplayBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); // Display the error message lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen(lpszFunction) + 40) * sizeof(TCHAR)); wprintf(L"%s failed with error %d: %s", lpszFunction, dw, lpMsgBuf); LocalFree(lpMsgBuf); LocalFree(lpDisplayBuf); } //Поиск номера диска для USB-устройства BOOL FindDiskNumber(LPCWSTR match, STORAGE_DEVICE_NUMBER* lpret){ BOOL retval = FALSE; DEVPROPTYPE dpt=0; wchar_t buffer[1024]=L""; TCHAR id_upper[1024]=L""; DWORD RequiredSize = 0; SP_DEVINFO_DATA devinfo = { 0 }; SP_DEVICE_INTERFACE_DATA deviceInterface = { 0 }; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail = NULL; BOOL res; HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (deviceInfoHandle != INVALID_HANDLE_VALUE) { int deviceIndex = 0; while (true) { ZeroMemory(&deviceInterface,sizeof(deviceInterface)); deviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); //получение всех дисков if (SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &GUID_DEVINTERFACE_DISK, deviceIndex, &deviceInterface)) { DWORD cbRequired = 0; SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, 0, 0, &cbRequired, 0); if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { deviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[cbRequired]); memset(deviceInterfaceDetail, 0, cbRequired); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (!SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, deviceInterfaceDetail, cbRequired, &cbRequired, 0)) { goto Next; } // Initialize the structure before using it. memset(deviceInterfaceDetail, 0, cbRequired); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); // Call the API a second time to retrieve the actual // device path string. BOOL status = SetupDiGetDeviceInterfaceDetail( deviceInfoHandle, // Handle to device information set &deviceInterface, // Pointer to current node in devinfo set deviceInterfaceDetail, // Pointer to buffer to receive device path cbRequired, // Length of user-allocated buffer &cbRequired, // Pointer to arg to receive required buffer length NULL); // Not interested in additional data //получение информации о устройстве ZeroMemory(&devinfo,sizeof(devinfo)); devinfo.cbSize = sizeof(SP_DEVINFO_DATA); BOOL success = SetupDiEnumDeviceInfo(deviceInfoHandle, deviceIndex, &devinfo); if(success==FALSE){ErrorMes(L"SetupDiEnumDeviceInfo"); goto Next;} res=SetupDiGetDeviceProperty(deviceInfoHandle,&devinfo, &DEVPKEY_Device_Parent,&dpt,(PBYTE)buffer,1000,NULL,0); if(res==FALSE){ErrorMes(L"SetupDiGetDeviceProperty");goto Next;} int len = wcslen(buffer); for(int i=0;iDevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if(handle==INVALID_HANDLE_VALUE) { ErrorMes(L"CreateFile");goto Next; } STORAGE_DEVICE_NUMBER sdn = {0}; DWORD nbytes = 0; //получение номера диска res = DeviceIoControl(handle, // handle to device IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode NULL, // lpInBuffer 0, // nInBufferSize (LPVOID) &sdn, // output buffer (DWORD) sizeof(sdn), // size of output buffer (LPDWORD) &nbytes, // number of bytes returned NULL // OVERLAPPED structure ); CloseHandle(handle); if(res != FALSE){ //устройство найдено memcpy(lpret,&sdn,sizeof(sdn)); retval = TRUE; } else ErrorMes(L"DeviceIoControl"); } } } else { break; } Next: if(deviceInterfaceDetail != NULL){ delete[] deviceInterfaceDetail; deviceInterfaceDetail = NULL; } if(retval != FALSE) break; //устройство уже найдено deviceIndex++; //следующее устройство } SetupDiDestroyDeviceInfoList(deviceInfoHandle); } else ErrorMes(L"SetupDiGetClassDevs"); return retval; } //таблица номеров для всех дисков bool disk_IsUsed[30]={0}; STORAGE_DEVICE_NUMBER disk_number[30]={0}; int _tmain(int argc, _TCHAR* argv[]) { setlocale(LC_ALL,"Russian"); HANDLE hVol; DWORD nbytes; WCHAR letter; WCHAR volume[100]={0}; int i; STORAGE_DEVICE_NUMBER sdn={0}; //заполняем таблицу номеров для дисков for(i=0;i<30;i++){ letter = 'A' + i; wsprintf(volume,L"\\\\.\\%c:",letter); disk_IsUsed[i] = FALSE; hVol = CreateFile( volume, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(hVol == NULL || hVol == INVALID_HANDLE_VALUE){continue;} BOOL ret = DeviceIoControl(hVol, // handle to device IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode NULL, // lpInBuffer 0, // nInBufferSize (LPVOID) &(disk_number[i]), // output buffer (DWORD) sizeof(STORAGE_DEVICE_NUMBER), // size of output buffer (LPDWORD) &nbytes, // number of bytes returned NULL // OVERLAPPED structure ); CloseHandle(hVol); if(ret == FALSE){continue;} disk_IsUsed[i] = TRUE; } WCHAR match[1024]={0}; GUID guid = { 0xF18A0E88, 0xC30C, 0x11D0, { 0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8 } }; /*USB HUB Interface class GUID*/ HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (deviceInfoHandle != INVALID_HANDLE_VALUE) { int deviceIndex = 0; while (true) { SP_DEVICE_INTERFACE_DATA deviceInterface = { 0 }; deviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); //получение всех USB-концентраторов if (SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, deviceIndex, &deviceInterface)) { DWORD cbRequired = 0; SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, 0, 0, &cbRequired, 0); if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[cbRequired]); memset(deviceInterfaceDetail, 0, cbRequired); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (!SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, deviceInterfaceDetail, cbRequired, &cbRequired, 0)) { delete[] deviceInterfaceDetail; deviceIndex++; continue; } // Initialize the structure before using it. memset(deviceInterfaceDetail, 0, cbRequired); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); // Call the API a second time to retrieve the actual // device path string. BOOL status = SetupDiGetDeviceInterfaceDetail( deviceInfoHandle, // Handle to device information set &deviceInterface, // Pointer to current node in devinfo set deviceInterfaceDetail, // Pointer to buffer to receive device path cbRequired, // Length of user-allocated buffer &cbRequired, // Pointer to arg to receive required buffer length NULL); // Not interested in additional data BOOL res; /*Открываем устройство для отправки IOCTL*/ HANDLE handle = CreateFile(deviceInterfaceDetail->DevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if(handle!=INVALID_HANDLE_VALUE) { DWORD bytes_read=0; UINT ports = 0; USB_NODE_INFORMATION nodeinfo; USB_NODE_CONNECTION_INFORMATION_EX coninfo={0}; const UINT BUFSIZE = 1000; char buffer[BUFSIZE]={0}; USB_DESCRIPTOR_REQUEST* req = (USB_DESCRIPTOR_REQUEST*)&buffer; USB_STRING_DESCRIPTOR* desc; ZeroMemory(&nodeinfo,sizeof(nodeinfo)); nodeinfo.NodeType = UsbHub; //получаем число портов на концентраторе res=DeviceIoControl(handle,IOCTL_USB_GET_NODE_INFORMATION , &nodeinfo,sizeof(nodeinfo),&nodeinfo,sizeof(nodeinfo),&bytes_read,0); if(res==FALSE)ErrorMes(L"DeviceIoControl"); else ports = (UINT)nodeinfo.u.HubInformation.HubDescriptor.bNumberOfPorts; for(int j=1;j<=ports;j++){ ZeroMemory(&coninfo,sizeof(coninfo)); coninfo.ConnectionIndex=j; //получаем инфу о порте res=DeviceIoControl(handle,IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX , &coninfo,sizeof(coninfo),&coninfo,sizeof(coninfo),&bytes_read,0); if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;} if(coninfo.ConnectionStatus==0) continue; //нет устройства printf("\n- Hub %2d, Port %2d: USB v%x device\n",deviceIndex, j,(int)coninfo.DeviceDescriptor.bcdUSB); printf("VID: %04X PID: %04X\n",(int)coninfo.DeviceDescriptor.idVendor ,(int)coninfo.DeviceDescriptor.idProduct); //формируем строку для поиска устройства wsprintf(match,L"VID_%04X&PID_%04X",(UINT)coninfo.DeviceDescriptor.idVendor ,(UINT)coninfo.DeviceDescriptor.idProduct); /*Serial number*/ ZeroMemory(buffer,BUFSIZE); req->ConnectionIndex=j; req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) + coninfo.DeviceDescriptor.iSerialNumber; req->SetupPacket.wLength = BUFSIZE - sizeof(USB_DESCRIPTOR_REQUEST); req->SetupPacket.wIndex = 0x409; //US English res=DeviceIoControl(handle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION , &buffer,sizeof(buffer),&buffer,sizeof(buffer),&bytes_read,0); if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;} desc = (USB_STRING_DESCRIPTOR*)(&req->Data[0]); wprintf(L"Serial: %s\n",desc->bString); /*Vendor*/ ZeroMemory(buffer,BUFSIZE); req->ConnectionIndex=j; req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) + coninfo.DeviceDescriptor.iManufacturer; req->SetupPacket.wLength = BUFSIZE - sizeof(USB_DESCRIPTOR_REQUEST); req->SetupPacket.wIndex = 0x409; //US English res=DeviceIoControl(handle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION , &buffer,sizeof(buffer),&buffer,sizeof(buffer),&bytes_read,0); if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;} desc = (USB_STRING_DESCRIPTOR*)(&req->Data[0]); wprintf(L"Vendor: %s\n",desc->bString); /*Product*/ ZeroMemory(buffer,BUFSIZE); req->ConnectionIndex=j; req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) + coninfo.DeviceDescriptor.iProduct; req->SetupPacket.wLength = BUFSIZE - sizeof(USB_DESCRIPTOR_REQUEST); req->SetupPacket.wIndex = 0x409; //US English res=DeviceIoControl(handle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION , &buffer,sizeof(buffer),&buffer,sizeof(buffer),&bytes_read,0); if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;} desc = (USB_STRING_DESCRIPTOR*)(&req->Data[0]); wprintf(L"Product: %s\n",desc->bString); /*Disk letter*/ res = FindDiskNumber(match,&sdn); if(res != FALSE) { for(i=0;i<30;i++) if( disk_IsUsed[i] !=FALSE && disk_number[i].DeviceNumber == sdn.DeviceNumber && disk_number[i].DeviceType == sdn.DeviceType) { letter = 'A' + i; printf("Disk letter: %c\n",letter); } } else printf("Disk letter not found\n"); } CloseHandle(handle); }else{ ErrorMes(L"CreateFile");//failed to open device }//endif delete[] deviceInterfaceDetail; } } else { break; } ++deviceIndex; } SetupDiDestroyDeviceInfoList(deviceInfoHandle); } else ErrorMes(L"SetupDiGetClassDevs"); system("PAUSE"); return 0; } Должно вывести подобный результат: ‐ Hub 3, Port 1: USB v200 device VID: 8564 PID: 1000 Serial: 5B94314A Vendor: JetFlash Product: Mass Storage Device Disk letter: G ‐ Hub 3, Port 4: USB v110 device VID: 09DA PID: 000A Serial: ? Vendor: A4Tech Product: USB Mouse Disk letter not found ‐ Hub 3, Port 6: USB v110 device VID: 046E PID: 5505 Serial: ? Vendor: BTC Product: USB Multimedia Keyboard Disk letter not found ‐ Hub 3, Port 10: USB v200 device VID: 04E8 PID: 689E Serial: 1234567890ABCDEF Vendor: SAMSUNG Electronics Co., Ltd. Product: Samsung Android USB Device Disk letter: H

суббота, 15 февраля 2020 г.

delphi Отловить подключение usb

#delphi #usb


Нашел на просторах рунета код для отлова подключения к усб порту

 unit usb_utils;

//http://www.swissdelphicenter.ch/en/tipsindex.php

interface

uses 
  Windows, Messages, SysUtils, Classes, Forms;

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;          // 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: 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 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; 
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 
        if Assigned(FOnUSBArrival) then 
          FOnUSBArrival(Self); 
      end  
      else  
      begin 
        if Assigned(FOnUSBRemove) then 
          FOnUSBRemove(Self); 
      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; 
  dbi.dbcc_name := 0;

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

end.


Все бы хорошо, но вот не особо у меня получается его совместить с dll (хочу потом
заинжектить длл в процесс). Тобищь, нужно чтоб длл отлавливала подключения флешки,
как я использовал код выше

library dll;

uses
  SysUtils,
  Classes,windows,dialogs,messages;

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;          // 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: 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;




{$R *.res}


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
   showmessage('error');
  //   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;
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
     showmessage('tada!');
       if Assigned(FOnUSBArrival) then
         FOnUSBArrival(Self);
     end
     else
     begin
       if Assigned(FOnUSBRemove) then
         FOnUSBRemove(Self);
     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;
dbi.dbcc_name := 0;

r := RegisterDeviceNotification(FWindowHandle, @dbi,
   DEVICE_NOTIFY_WINDOW_HANDLE
   );
if Assigned(r) then Result := True
else
showmessage('bad');

end;

begin
showmessage('good');
 TComponentUSB.Create(nil);
 while true do
 sleep(100);
end.


Инжектю длл, выходит сообщение good, значит заинжектилось норм, но вот при вставке
флэшки не выходит сообщение tada!, хотя на форме все работает хорошо. Я думаю, что
проблема в регистрации (USBRegister) мб хэндл не тот, можете мне подсказать ?
    


Ответы

Ответ 1



Представленный в вопросе код содержит ошибки: При инициализации dll (между begin и end, в секции initialization используемых модулей) крайне не рекомендуется использовать что-то "тяжелое". Объяснение легко тянет на отдельную статью (например - статья Gunsmoker-а ) Уведомления о подключении устройств к компьютеру используют штатный механизм сообщений Windows , т.е. код, реализующий этот функционал, должен выполняться в потоке, который реализует цикл выборки сообщений (Message loop). Собственно, код из вопроса не работает "благодаря" пункту 2. С учетом обоих замечаний, код должен выполнять следующие действия: Максимально быстро завершить работу между "главными" begin и end кода dll. После "отложенной" инициализации нужно организовать цикл выборки сообщений, который должен работать до момента выгрузки dll (или любых других условий, на ваш выбор). По завершению работы цикла выборки сообщений - провести деинициализацию. Пункт 1 будем выполнять при помощи потока. Т.е. при инициализации dll создаем свой поток и уже в нем проводим основную работу. Этот метод тоже не очень хорош, посему - если есть возможность, то при внедрении dll лучше вызвать отдельную функцию, экспортируемую этой dll и уже в ней производить указанные манипуляции. Итого, общий код dll будет выглядеть примерно так: var DelayedThread: TDelayedThread; procedure LibProc(Reason: integer); begin case Reason of DLL_PROCESS_ATTACH: // нашу dll загрузили begin DelayedThread:=TDelayedThread.Create; // создаем отдельный поток // внутри которого и будем осуществлять основные "тяжелые" действия DelayedThread.FreeOnTerminate:=True; // мы будем завершать поток при выгрузке dll // и из-за этого не будем ждать, пока поток завершится. Пусть он уничтожится после завершения самостоятельно. end; DLL_PROCESS_DETACH: // нашу dll выгружают begin // Завершаем поток. DelayedThread.Terminate; PostThreadMessage(DelayedThread.ThreadID, WM_QUIT, 0, 0); // отправляем нашему потоку сообщение // чтобы он "проснулся", если в данный момент он "спит" внутри GetMessage (см. код ниже). // и после пробуждения - вышел из цикла. end; end; end; begin DLLProc := LibProc; LibProc(DLL_PROCESS_ATTACH); end. Этот код выполняет действия №1 (не делать ничего "тяжелого" при инициализации dll, максимально быстро отдать управление) и №3 (деинициализация). Теперь нужно реализовать основное действие №2. Объявление класса потока оставим на ваше усмотрение, здесь же остановимся именно на реализации. Код организации выборки сообщений для работы всех окон (созданных в этом потоке) может выглядеть так: procedure TDelayedThread.Execute; var msg: TMSG; ComponentUSB: TComponentUSB; begin ComponentUSB:=TComponentUSB.Create(nil); // создание компонента, в котором есть необходимость получения сообщений // создаем именно внутри метода Execute, а не в конструкторе. // чтобы созданное внутри компонента окно принадлежало именно этому потоку. // Иначе дальнейшие действия окажутся бессмысленными. try PeekMessage(msg, 0, 0, 0, PM_NOREMOVE); // "говорим" ОС, что этот поток будет выбирать сообщения while not Terminated and GetMessage(msg, 0, 0, 0) do // и входим в цикл выборки сообщений // пока этот поток не прервут. begin TranslateMessage(msg); DispatchMessage(msg); // этот (стандартный) метод "отдает" принятое сообщение нужной оконной функции. // в данном случае - той, которая использовалась в AllocateHWND в конструкторе TComponentUSB end; finally ComponentUSB.Free; end; end; В главном потоке обычного VCL-приложения выборкой сообщений (используя подобный цикл) занимается объект Application: TApplication, а конкретнее - его метод ProcessMessages (лирическое отступление: если вам приходится принудительно вызывать этот метод у себя в приложении - скорее всего, вы что-то делаете неправильно).

суббота, 8 февраля 2020 г.

Привязка контроллеров к USB-портам

#linux #usb #микроконтроллеры


Имеются два идентичных конторллера для управления шаговыми двигателями, подключенные
по USB. Если подключать их при работающей ОС, то первый подключенный вешается на /dev/USB0,
а второй на /dev/USB1.
Как сделать так, чтобы при старте системы первый контроллер всегда вешался на /dev/USB0,
а второй на /dev/USB1?     


Ответы

Ответ 1



Попробуйте создать правила для Ваших контроллеров через udev. Каждый раз при подключении или отключении устройства ядро посылает событие uevent, которое информирует udev о произошедших изменениях. Демон udev считывает правила для своей работы из каталога /etc/udev/rules.d/ единожды при своем запуске и затем хранит их в памяти. Каждое полученное событие сравнивается с набором загруженных правил. С помощью правил можно добавлять специфичные для окружения опции, создавать символические ссылки на создаваемый файл устройства или указать программу, запускаемую после того как файл устройства будет создан. События ядра uevents от драйверов устройств передаются через сокет ядра netlink. Нампример, здесь рассказывается, как создаются правила, но думаю, без труда найдете еще с десяток разных примеров и инструкций. Надеюсь, это то, что нужно! :)

среда, 5 февраля 2020 г.

Какие есть цвета usb-разъёмов и что они означают?

#usb #железо #разъёмы


Для usb распространено окрашивание разъёмов в различные цвета с целью сделать их
легкоразличимыми визуально. Например, разъёмы usb 3 обычно делают синими, а разъёмы,
пригодные только для зарядки, красными или жёлтыми. Есть ли собственные цвета у usb
3.1, 3.2 и 4? В случае кабеля, влияет ли как-то максимально допустимый ток? Для чего
используется сиреневый цвет?
    


Ответы

Ответ 1



В спецификации сказано строго "рекомендуем использовать только синий". Но подробнее о цветах: Белый это USB 1.x Серый это USB 2.x Синий это USB 3 Красный или желтый это USB 3 - это говорит о том, что разъём не будет выключен во время сна или в режиме ожидания. Тут отмечу, что в спецификации на этот счёт ничего не сказано (может специалисты меня поправят). Часто красный используются для повышенного питания, но на практике я не встречал. По факту порт должен быть всегда синий. Других цветов в спецификации я не встречал. USB 3.1, 3.2 тоже синий, красный или жёлтый. USB 4 - точной спецификации нет Из спецификации: PDF спецификации, страница 5-14. Ссылка.

Ответ 2



Насколько я знаю, обычно: Чёрный - USB 1 (позже USB 2); Белый - USB 2; Синий - USB 3; Красный - интерфейс повышенного напряжения, передаваемые ток свыше 500 мА; Жёлтый - интерфейс, который передает ток даже при выключенном компьютере (предполагает использование для зарядки различного оборудования, независимо от состоянии компьютера). Здесь ключевое слово "обычно", т.к. на самом деле многое зависит от производителя и модели мат.платы. Видел модели, где все порты красного цвета, но не потому, что они для зарядки. Просто так захотелось дизайнеру.

вторник, 28 января 2020 г.

Как запустить Ubuntu c загрузочного диска на USB / Как вернуться в Windows?

#linux #windows #ubuntu #usb #dual_boot


Буду благодарен за пошаговые инструкции:


Есть загрузочный диск на USB с образом Ubuntu. Как его запустить?
Как после запуска Ubuntu вернуться в Windows?

    


Ответы

Ответ 1



Вопрос: Есть загрузочный диск на USB с образом Ubuntu. Как его запустить? Ответ: Необходимые условия: Подключение к сети интернет, т.к. во время установки будут загружены дополнительные пакеты программ, которые не поместились на установочный образ. Диск или флешка с iso-образом Установка Вставьте диск в дисковод, либо флешку в порт и перезагрузите компьютер. После перезагрузки должно открыться на экране окно приветствия Welcome, где нужно выбрать язык: Когда вы выберите язык, в окне приветствия будет предложено два варианта: Запустить Ubuntu и Установить Ubuntu: Если вы выберите Запустить Ubuntu, то система будет загружена в Live-режиме, т.е. без установки на ж/диск компьютера и можно будет "пощупать" Ubuntu, а в дальнейшем перейти к установке. В случае с выбором Установить Ubuntu, вы перейдёте к непосредственной установке. Предположим вы выбрали Запустить Ubuntu. Должен открыться рабочий стол Ubuntu: После знакомства с Ubuntu, вы можете перейти к непосредственной установке. Двойной клик на значке на рабочем столе - Установить Ubuntu: Если язык выбран вами правильно, нажмите копку Продолжить, чтобы перейти к следующему шагу: В шаге Подготовка к установке Ubuntu, активируйте оба пункта: Загрузить обновления при установке и Установить сторонне программное обеспечение, как на верхнем снимке и Продолжить. В шаге Тип установки нужно выбрать один из трёх типов. У меня установлено несколько систем на жестком диске, у вас может быть одна, но суть от этого не меняется. Если вы не умеете разбивать жесткий диск на разделы, оставьте активированным первый пункт и установщик сам найдет место рядом с установленной системой, не причинив ей ни какого вреда. Либо вы можете выбрать второй вариант, который предлагает Стереть диск и установить Ubuntu. В этом случае сотрётся всё что у вас есть на ж/диске и установится только Ubuntu. И наконец третий вариант - Другой вариант, предлагает создать и изменить разделы самостоятельно для Ubuntu (для опытных пользователей). Выбрав первый пункт Установить Ubuntu рядом с ними, нажмите Продолжить, после чего откроется следующий шаг, где будет предложено автоматическое разбиение пространства на ж/диске, но вы можете поместить курсор в центр, между двух разделов и двигать его, тем самым изменяя размеры разделов. В случае выбора третьего варианта - Другой вариант, вы можете выбрать один из существующих разделов, двойной клик на строке с разделом и в открывшемся окне Изменить раздел, в параметре Использовать как выберите Журналируемая файловая система Ext4; поставьте флажок в параметре Форматировать раздел; Точка монтирования - корневой раздел / (правый слэш) и нажмите ОК, как на нижнем снимке : После того как вы определились с разделами, нажмите Установить сейчас. Откроется окно с пояснениями о том что раздел будет отформатирован и пр. Если вы сомневаетесь или выбрали не тот раздел ж/диска, то есть возможность вернуться и переделать созданный раздел, либо переключиться на другой, нажав кнопку Вернуться. Если всё правильно, нажмите Продолжить, чтобы перейти к следующему шагу. Далее, в окне установки Где вы находитесь? введите в поле внизу окна название вашей местности, либо кликните на карте, для правильного отображения времени в системе и Продолжить. Следующим шагом будет определение Раскладки клавиатуры: Здесь вам предложено выбрать язык раскладки клавиатуры и Продолжить. Откроется приветственное окно, демонстрирующее возможности Ubuntu, с которыми можно познакомиться до окончания установки. Дождитесь окончания установки. Когда установка закончится, откроется последнее окно установщика - Установка завершена. Вопрос: Как после запуска Ubuntu вернуться в Windows? Ответ: Если вы хотите чтоб на вашем ПК нормально работал Windows и Ubuntu. В случае установки с нуля (новый "чистый" ПК), рекомендую сначала устанавливать Windows. В случае установки Ubuntu быстрее Windows будут проблемы. Если у вас уже установлена Windows, смело устанавливайте Ubuntu рядом как вторую ОС. Будте внимательны во время установки в моменте с Разделами После того как Ubuntu будет установлена, вы можете менять системы через клавишу F11, нажимать ее необходимо во время загрузки, когда система начинает загружаться. Хотя еще могут быть разные моменты, но в целом принцип такой.

пятница, 10 января 2020 г.

Как получить VID:PID для USB Hub в Windows?

#windows #winapi #usb


Имею symbolic link на USB Root Hub вида "\\.\USB#ROOT_HUB#4&e097488&0#{f18a0e88-c30c-11d0-8815-00a0c906bed8}"
и хочу получить VID:PID для хаба.
Работаю в user mode, IOCTLы слать могу. Но среди описанных в MSDN (https://msdn.microsoft.com/en-us/library/windows/hardware/ff537421%28v=vs.85%29.aspx)
не нахожу подходящего. Как быть?
    


Ответы

Ответ 1



VID и PID для USB Hub можно определить разбором его Hardware ID. Hardware ID можно получить с помощью функции SetupDiGetDeviceRegistryProperty (Setup API). Функция возвращает несколько значений, нужно взять первое с вхождением подстрок VID/PID. Для корневого концентратора формат строки выглядит так: USB\ROOT_HUB30&VID8086&PID8C31&REV0005 Пример кода на c++ для вывода symbolic link, названия, VID и PID для всех USB Hub-ов; основан на этом ответе. #pragma comment(lib,"Setupapi.lib") #include #include #include #include #include #include #include #include #include void ErrorMes(LPTSTR lpszFunction) { // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; LPVOID lpDisplayBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); // Display the error message lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); wprintf(L"%s failed with error %d: %s", lpszFunction, dw, lpMsgBuf); LocalFree(lpMsgBuf); LocalFree(lpDisplayBuf); } int main() { setlocale(LC_ALL,"Russian"); GUID guid; HRESULT hr = CLSIDFromString(L"{F18A0E88-C30C-11D0-8815-00A0C906BED8}", (LPCLSID)&guid);//USB Hub HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (deviceInfoHandle != INVALID_HANDLE_VALUE) { int deviceIndex = 0; while (true) { SP_DEVICE_INTERFACE_DATA deviceInterface = { 0 }; deviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); //перечисление всех интерфейсов USB Hub if (SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, deviceIndex, &deviceInterface)) { DWORD cbRequired = 0; SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, 0, 0, &cbRequired, 0); if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[cbRequired]); memset(deviceInterfaceDetail, 0, cbRequired); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (!SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, deviceInterfaceDetail, cbRequired, &cbRequired, 0)) { deviceIndex++; continue; } // Initialize the structure before using it. memset(deviceInterfaceDetail, 0, cbRequired); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); // Call the API a second time to retrieve the actual // device path string. BOOL status = SetupDiGetDeviceInterfaceDetail( deviceInfoHandle, // Handle to device information set &deviceInterface, // Pointer to current node in devinfo set deviceInterfaceDetail, // Pointer to buffer to receive device path cbRequired, // Length of user-allocated buffer &cbRequired, // Pointer to arg to receive required buffer length NULL); // Not interested in additional data wprintf(deviceInterfaceDetail->DevicePath);//вывод symbolic link wprintf(L"\n"); //получение информации о устройстве DEVPROPTYPE dpt=0; wchar_t buffer[1000]=L""; DWORD RequiredSize = 0; SP_DEVINFO_DATA devinfo = { 0 }; devinfo.cbSize = sizeof(SP_DEVINFO_DATA); BOOL success = SetupDiEnumDeviceInfo(deviceInfoHandle, deviceIndex, &devinfo); if(success==FALSE){ErrorMes(L"SetupDiEnumDeviceInfo");} BOOL res; //name res=SetupDiGetDeviceProperty(deviceInfoHandle,&devinfo, &DEVPKEY_Device_DeviceDesc,&dpt,(PBYTE)buffer,1000,NULL,0); printf("Name: "); if(res==FALSE)ErrorMes(L"SetupDiGetDeviceProperty"); else wprintf(buffer); printf("\n"); //hardware id DWORD regType = REG_MULTI_SZ; unsigned char* ptr = new unsigned char[2048]; if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &devinfo, SPDRP_HARDWAREID, ®Type, ptr, 2048, &RequiredSize)) { wchar_t* input=reinterpret_cast(ptr); wchar_t sep[]=L"&\\"; wchar_t vid[5]=L""; wchar_t pid[5]=L""; bool found=false; /*проходим по всем элементам REG_MULTI_SZ*/ while(true){ wchar_t* tok=NULL; wchar_t* pos=NULL; //разбор hardware id tok=wcstok(input,sep); while( tok != NULL ) { pos=wcsstr(tok,L"VID"); if(pos!=NULL){ pos+=3; if(pos[0]==L'_')pos++; StringCchCopy(vid,5,pos); found=true; } pos=wcsstr(tok,L"PID"); if(pos!=NULL){ pos+=3; if(pos[0]==L'_')pos++; StringCchCopy(pid,5,pos); found=true; } tok = wcstok( NULL, sep ); }//конец разбора hardware id if(found!=false)break; input+=wcslen(input)+1;//переход к следующему элементу REG_MULTI_SZ if(wcscmp(input,L"")==0)break; }//конец прохода if(found!=false) { wprintf( L"VID: %s\n", vid ); wprintf( L"PID: %s\n", pid ); } else { wprintf( L"Not found\n"); } } else ErrorMes(L"SetupDiGetDeviceRegistryProperty"); delete[] ptr; delete[] deviceInterfaceDetail; printf("\n"); } } else { break; } ++deviceIndex; } SetupDiDestroyDeviceInfoList(deviceInfoHandle); } system("PAUSE"); return 0; }

суббота, 7 декабря 2019 г.

Автоматизация огорода [закрыт]

#java #delphi #usb #железо #микроконтроллеры


        
             
                
                    
                        
                            Closed. This question needs to be more focused. It is
not currently accepting answers.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Want to improve this question? Update the question so
it focuses on one problem only by editing this post.
                        
                        Closed 4 года назад.
                                                                                
           
                
        
Доброго время суток.
Подскажите, пожалуйста, планирую сделать автоматизированное управление (как бы смешно
не звучала огорода) т.к живу очень далеко а ездить каждые выходные что то не хочется. т.е 

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

Подскажите какую плату можно использовать? и контроллеры?
Планируется управление по wifi (или чем то еще но только без проводов)
Программировать планирую на delphi или Java, C# только изучаю.
Желательно детали недорогие если можно посоветовать.
У кого какие предложения?
Я никогда ранее не работал с микроконтроллерами и т.д. Извините за некомпетентность.    


Ответы

Ответ 1



Культивацией плантации собираетесь заниматься?) Датчики влажности, температуры и прочей электроники можно найти на китайский барахолках, типа http://dx.com За контроллер берите arduino mega, ибо его разъемов должно хватить почти на всё.

Ответ 2



Omron! Есть такая фирма, правда дороговато, но программирование их микроконтроллеров, похоже на построение электрических сетей(в их специальной программе есс-но, CX-Programmer вроде или CX-One)

Ответ 3



Если управление поливом будет автоматическое, то Atmel+Датчик влажности+исполнительное устройство включения полива. Если управление будет on-line, то добавляется огородный ПК с GPRS модемом, программа сбора показаний датчиков на огороде с отправкой данных оператору, программа управления на удаленном ПК, связь между ними можно организовать по технологии socket. Чтоб управление было стойкое к метеоусловиям передачу данных между ПК и контроллером на огороде лучше организовать по bluetooth (bluegiga, HC-07 ...). В общем это комплексный проект. И нужно изучить все его составляющие.

Ответ 4



Самый имхо простой способ - прикупить нужные сенсоры к Android телефону, написать на Java прожку для телефона через специальное API и вуаля.

понедельник, 15 июля 2019 г.

Как перенести linux ubuntu на флешку

У меня на пк установлен ubuntu linux 16.04 x64. Есть ли способ перенести данную систему на флешку, сохранив все настройки и программы, затем полноценно ее запускать?


Ответ

UNetbootin - Установите эту програрамму из стандартного репозитария и она создаст загрузочную флэшку. Далее можете писать туда все файлы, которые считаете необходимыми.
Или второй вариант - создать ISO образ Вашей системы и уже его записать на флэшку.

воскресенье, 9 июня 2019 г.

Как в Windows 10 сделать так, чтобы USB флеш-накопители не надо было отключать отдельной командой?

Как известно, в Windows, когда завершаешь операции с USB флеш-накопителем, его надо отключить отдельной командой. После этой команды появляется сообщение "теперь накопитель ХХХ можно удалить".
Надоело мне каждый раз отключать USB флеш-накопители отдельной командой. Помнится мне, что когда в ходу были дискеты, то для них не было никакой отдельной команды для отключения. Конец операции копирования на дискету означал, что дискету можно вынимать.
Вопрос:
Как в Windows 10 сделать так, чтобы не надо было отключать USB флеш-накопители отдельной командой? Хочу, чтобы как при работе с дискетами, окончание операции копирования (чтения или записи) означало, что USB флеш-накопитель можно вынимать.


Ответ

Втыкаем флешку. Идем в Диспетчер устройств, находим в нем флешку, правый клик - Свойства. Во второй вкладке активируем верхнюю опцию "Быстрое удаление".

Важно: окончание операции записи/копирования определяется не исчезновением индикатора процесса копирования, а тем, что на флешке перестал мигать светодиод.
PS. Это в Вин7. Если в Вин10 не так, то удалю ответ.

четверг, 25 апреля 2019 г.

delphi Отловить подключение usb

Нашел на просторах рунета код для отлова подключения к усб порту
unit usb_utils;
//http://www.swissdelphicenter.ch/en/tipsindex.php
interface
uses Windows, Messages, SysUtils, Classes, Forms;
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; // 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: 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 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; 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 if Assigned(FOnUSBArrival) then FOnUSBArrival(Self); end else begin if Assigned(FOnUSBRemove) then FOnUSBRemove(Self); 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; dbi.dbcc_name := 0;
r := RegisterDeviceNotification(FWindowHandle, @dbi, DEVICE_NOTIFY_WINDOW_HANDLE ); if Assigned(r) then Result := True; end;
end.
Все бы хорошо, но вот не особо у меня получается его совместить с dll (хочу потом заинжектить длл в процесс). Тобищь, нужно чтоб длл отлавливала подключения флешки, как я использовал код выше
library dll;
uses SysUtils, Classes,windows,dialogs,messages;
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; // 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: 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;

{$R *.res}
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 showmessage('error'); // 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; 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 showmessage('tada!'); if Assigned(FOnUSBArrival) then FOnUSBArrival(Self); end else begin if Assigned(FOnUSBRemove) then FOnUSBRemove(Self); 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; dbi.dbcc_name := 0;
r := RegisterDeviceNotification(FWindowHandle, @dbi, DEVICE_NOTIFY_WINDOW_HANDLE ); if Assigned(r) then Result := True else showmessage('bad');
end;
begin showmessage('good'); TComponentUSB.Create(nil); while true do sleep(100); end.
Инжектю длл, выходит сообщение good, значит заинжектилось норм, но вот при вставке флэшки не выходит сообщение tada!, хотя на форме все работает хорошо. Я думаю, что проблема в регистрации (USBRegister) мб хэндл не тот, можете мне подсказать ?


Ответ

Представленный в вопросе код содержит ошибки:
При инициализации dll (между begin и end, в секции initialization используемых модулей) крайне не рекомендуется использовать что-то "тяжелое". Объяснение легко тянет на отдельную статью (например - статья Gunsmoker-а ) Уведомления о подключении устройств к компьютеру используют штатный механизм сообщений Windows , т.е. код, реализующий этот функционал, должен выполняться в потоке, который реализует цикл выборки сообщений (Message loop).
Собственно, код из вопроса не работает "благодаря" пункту 2.

С учетом обоих замечаний, код должен выполнять следующие действия:
Максимально быстро завершить работу между "главными" begin и end кода dll. После "отложенной" инициализации нужно организовать цикл выборки сообщений, который должен работать до момента выгрузки dll (или любых других условий, на ваш выбор). По завершению работы цикла выборки сообщений - провести деинициализацию.
Пункт 1 будем выполнять при помощи потока. Т.е. при инициализации dll создаем свой поток и уже в нем проводим основную работу. Этот метод тоже не очень хорош, посему - если есть возможность, то при внедрении dll лучше вызвать отдельную функцию, экспортируемую этой dll и уже в ней производить указанные манипуляции.

Итого, общий код dll будет выглядеть примерно так:
var DelayedThread: TDelayedThread;
procedure LibProc(Reason: integer); begin case Reason of DLL_PROCESS_ATTACH: // нашу dll загрузили begin DelayedThread:=TDelayedThread.Create; // создаем отдельный поток // внутри которого и будем осуществлять основные "тяжелые" действия
DelayedThread.FreeOnTerminate:=True; // мы будем завершать поток при выгрузке dll // и из-за этого не будем ждать, пока поток завершится. Пусть он уничтожится после завершения самостоятельно. end; DLL_PROCESS_DETACH: // нашу dll выгружают begin // Завершаем поток. DelayedThread.Terminate; PostThreadMessage(DelayedThread.ThreadID, WM_QUIT, 0, 0); // отправляем нашему потоку сообщение // чтобы он "проснулся", если в данный момент он "спит" внутри GetMessage (см. код ниже). // и после пробуждения - вышел из цикла. end; end; end;
begin DLLProc := LibProc; LibProc(DLL_PROCESS_ATTACH); end.
Этот код выполняет действия №1 (не делать ничего "тяжелого" при инициализации dll, максимально быстро отдать управление) и №3 (деинициализация).
Теперь нужно реализовать основное действие №2. Объявление класса потока оставим на ваше усмотрение, здесь же остановимся именно на реализации. Код организации выборки сообщений для работы всех окон (созданных в этом потоке) может выглядеть так:
procedure TDelayedThread.Execute; var msg: TMSG; ComponentUSB: TComponentUSB; begin ComponentUSB:=TComponentUSB.Create(nil); // создание компонента, в котором есть необходимость получения сообщений // создаем именно внутри метода Execute, а не в конструкторе. // чтобы созданное внутри компонента окно принадлежало именно этому потоку. // Иначе дальнейшие действия окажутся бессмысленными. try PeekMessage(msg, 0, 0, 0, PM_NOREMOVE); // "говорим" ОС, что этот поток будет выбирать сообщения while not Terminated and GetMessage(msg, 0, 0, 0) do // и входим в цикл выборки сообщений // пока этот поток не прервут. begin TranslateMessage(msg); DispatchMessage(msg); // этот (стандартный) метод "отдает" принятое сообщение нужной оконной функции. // в данном случае - той, которая использовалась в AllocateHWND в конструкторе TComponentUSB end; finally ComponentUSB.Free; end; end;
В главном потоке обычного VCL-приложения выборкой сообщений (используя подобный цикл) занимается объект Application: TApplication, а конкретнее - его метод ProcessMessages (лирическое отступление: если вам приходится принудительно вызывать этот метод у себя в приложении - скорее всего, вы что-то делаете неправильно).

воскресенье, 14 апреля 2019 г.

Привязка контроллеров к USB-портам

Имеются два идентичных конторллера для управления шаговыми двигателями, подключенные по USB. Если подключать их при работающей ОС, то первый подключенный вешается на /dev/USB0, а второй на /dev/USB1. Как сделать так, чтобы при старте системы первый контроллер всегда вешался на /dev/USB0, а второй на /dev/USB1?


Ответ

Попробуйте создать правила для Ваших контроллеров через udev. Каждый раз при подключении или отключении устройства ядро посылает событие uevent, которое информирует udev о произошедших изменениях. Демон udev считывает правила для своей работы из каталога /etc/udev/rules.d/ единожды при своем запуске и затем хранит их в памяти. Каждое полученное событие сравнивается с набором загруженных правил. С помощью правил можно добавлять специфичные для окружения опции, создавать символические ссылки на создаваемый файл устройства или указать программу, запускаемую после того как файл устройства будет создан. События ядра uevents от драйверов устройств передаются через сокет ядра netlink. Нампример, здесь рассказывается, как создаются правила, но думаю, без труда найдете еще с десяток разных примеров и инструкций. Надеюсь, это то, что нужно! :)