ntstatus driverentry(in pdriver_object driverobject, in punicode_string registrypath )
{
driverobject->majorfunction[irp_mj_create] = usbdrv_create;
driverobject->majorfunction[irp_mj_close] = usbdrv_close;
driverobject->majorfunction[irp_mj_device_control] = usbdrv _processioctl;
driverobject->majorfunction[irp_mj_write] = usbdrv_write;
driverobject->majorfunction[irp_mj_read] = usbdrv_read;
driverobject->majorfunction[irp_mj_system_control] = usbdrv _processsyscontrolirp;
driverobject->majorfunction[irp_mj_pnp] = usbdrv_processpnpirp;
driverobject->majorfunction[irp_mj_power] = usbdrv_processpowerirp;
driverobject->driverextension->adddevice = usbdrv_adddevice;
driverobject->driverunload = usbdrv_unload;
return status_success; }
как можно в С++ перехватить USB устройство
Люди кто нибудь знает как можно в С++ перехватить USB устройство, что бы его вначале определяла программа и при этом операционка не выполняла никаких действий(не конфигурировала его, не искала драва).программа сама выполняет набор определенных действий и решает отдавать операционке устройство или отклучить его.Может като управлять портами?
1)Каждое usb устройство должно обслуживаться собственным драйвером. На шину usb нельзя просто передать сырой поток данных.
2)Все usb контроллеры соответствуют спецификации acpi, т.е поддерживают функции pnp и управления питанием. Поэтому работать с устройством можно только если оно подключено к шине (как это ни удивительно j ).
3)Драйвера в windows образуют т.н стек, по которому и передаются данные вверх и вниз, не следует пытаться работать напрямую с портами контроллера.
В операционной системе есть уже универсальный драйвер для корневых концентраторов. В данном случае драйвер корневого концентратора (usbhub.sys) создает логическое устройство позволяющие для драйверов абстрагироваться от подробностей работы драйвера usb контроллера. Его интерфейс документирован в ddk. Это набор управляющих кодов для диспетчера (просто процедура, обрабатывающая запросы) запросов типа irp_mj_internal_device_control. С помощью этих запросов можно получить разнообразную информацию о состоянии шины, количестве портов, их статусе и пр. Все эти коды имеют символические имена вида: ioctl_internal_usb_ХХХХ. И т.д. и т.п.
При буферизованном выводе происходит следующее:
1)Пользовательское приложение вызывает функцию writefile, передав указатель на буфер содержащий данные;
2)ОС вызывает диспетчер irp_mj_write драйвера и передает туда (через структуру irp) указатель на буфер данных
3)Драйвер копирует данные в свой внутренний буфер. После этого, возможно, сообщает, что данные переданы или откладывает это сообщение до момента актуальной передачи.
4)Актуальная передача осуществляется когда-то позже.
Любой драйвер, удовлетворяющий модели драйверов nt или wdm, начинается стандартной точки входа – driverentry.
В этой процедуре должны быть заданы диспетчеры – процедуры, по средством которых драйвер взаимодействует с системой.
Код:
1. с помощью этого диспетчера можно и отказать в открытии файла – достаточно вернуть что-то отличное от status_success;
2. в диспетчер через имя файла может быть передана дополнительная текстовая информация – она просто "прицепляется" к имени сзади.
После того, как система обнаруживает устройство, обслуживаемое драйвером, она вызывает функцию adddevice:
Код:
ntstatus usbdrv_pnpadddevice(in pdriver_object driverobject, in pdevice_object physicaldeviceobject )
{
ntstatus ntstatus = status_success;
pdevice_object deviceobject = null;
pdevice_extension deviceextension;
unicode_string devicelink;
ulong i;
ntstatus = ioregisterdeviceinterface(physicaldeviceobject, (lpguid)&guid_class_usb_drv, null, &devicelink);
ntstatus = iosetdeviceinterfacestate(&devicelink, true);
ntstatus = iocreatedevice (driverobject,
sizeof (device_extension),
null,
file_device_unknown,
file_autogenerated_device_name, false,
&deviceobject);
deviceextension = (deviceobject)->deviceextension;
rtlcopymemory(deviceextension ->devicelinknamebuffer, devicelink.buffer, devicelink.length);
deviceextension ->pdo = physicaldeviceobject;
deviceextension ->topstackdevice =
ioattachdevicetodevicestack(deviceobject, physicaldeviceobject);
deviceobject ->flags |= do_direct_io;
deviceobject ->flags &= ~do_device_initializing;
return status_success;
}
{
ntstatus ntstatus = status_success;
pdevice_object deviceobject = null;
pdevice_extension deviceextension;
unicode_string devicelink;
ulong i;
ntstatus = ioregisterdeviceinterface(physicaldeviceobject, (lpguid)&guid_class_usb_drv, null, &devicelink);
ntstatus = iosetdeviceinterfacestate(&devicelink, true);
ntstatus = iocreatedevice (driverobject,
sizeof (device_extension),
null,
file_device_unknown,
file_autogenerated_device_name, false,
&deviceobject);
deviceextension = (deviceobject)->deviceextension;
rtlcopymemory(deviceextension ->devicelinknamebuffer, devicelink.buffer, devicelink.length);
deviceextension ->pdo = physicaldeviceobject;
deviceextension ->topstackdevice =
ioattachdevicetodevicestack(deviceobject, physicaldeviceobject);
deviceobject ->flags |= do_direct_io;
deviceobject ->flags &= ~do_device_initializing;
return status_success;
}
Кроме того, драйвер сможет отправлять irp запросы вниз по стеку, к которому он приаттачился. Одним из первых будет получен pnp запрос irp_mn_start_device, с помощью которого драйвер получит всю необходимую информацию об устройстве:
Код:
ntstatus usbdrv_onstartdevice(in pdevice_object deviceobject )
{
ntstatus ntstatus = status_success;
pdevice_extension pdevext = null;
purb purb = null;
pusb_device_descriptor pdevdesc = null;
pusb_configuration_descriptor pconfigdesc = null;
pdevext = deviceobject->deviceextension;
purb = exallocatepool(nonpagedpool, sizeof(struct _urb_control_descriptor_request) ) ;
pdevdesc = exallocatepool(nonpagedpool, sizeof(usb_device_descriptor) );
usbbuildgetdescriptorrequest(purb,(ushort)sizeof(struct _urb_control_descriptor_request),
usb_device_descriptor_type, 0, 0, pdevdesc, null, sizeof(usb_device_descriptor), null);
pirp = iobuilddeviceiocontrolrequest(ioctl_internal_usb_submit_urb,
pdevext ->topstackdevice, null, 0, null, 0, true, &event, &iostatus);
nextstack = iogetnextirpstacklocation(pirp);
nextstack->parameters.others.argument1 = urb;
//При нормальном стечении обстоятельств, вот тебе инфа об устройстве))))
kdprint(("usblink device descriptor:n"));
kdprint(("-------------------------n"));
kdprint(("blength %dn", pdevdesc->blength));
kdprint(("bdescriptortype 0x%xn", pdevdesc->bdescriptortype));
kdprint(("bcdusb 0x%xn", pdevdesc->bcdusb));
kdprint(("bdeviceclass 0x%xn", pdevdesc->bdeviceclass));
kdprint(("bdevicesubclass 0x%xn", pdevdesc->bdevicesubclass));
kdprint(("bdeviceprotocol 0x%xn", pdevdesc->bdeviceprotocol));
kdprint(("bmaxpacketsize0 0x%xn", pdevdesc->bmaxpacketsize0));
kdprint(("idvendor 0x%xn", pdevdesc->idvendor));
kdprint(("idproduct 0x%xn", pdevdesc->idproduct));
kdprint(("bcddevice 0x%xn", pdevdesc->bcddevice));
kdprint(("imanufacturer 0x%xn", pdevdesc->imanufacturer));
kdprint(("iproduct 0x%xn", pdevdesc->iproduct));
kdprint(("iserialnumber 0x%xn", pdevdesc->iserialnumber));
kdprint(("bnumconfigurations 0x%xn", pdevdesc->bnumconfigurations));
//Запомним эту информацию в контексте устройства
pdevext ->usbdevicedescriptor = pdevdesc;
//Теперь используем полученную информацию для инициализации устройства:
Построим еще один urb запрос
pconfigdesc = exallocatepool(nonpagedpool, sizeof(usb_configuration_descriptor) );
usbbuildgetdescriptorrequest(purb,
(ushort) sizeof (struct _urb_control_descriptor_request), usb_configuration_descriptor_type, 0, 0, pconfigdesc, null, sizeof(usb_configuration_descriptor), null);
pirp = iobuilddeviceiocontrolrequest(ioctl_internal_usb_submit_urb,
pdevext ->topstackdevice, null, 0, null, 0, true, &event, &iostatus);
nextstack = iogetnextirpstacklocation(pirp);
nextstack->parameters.others.argument1 = urb;
iocalldriver(pdevext ->topstackdevice, pirp);
//А вот теперь попробуем получить актуальную конфигурационную информацию:
pdevext ->usbconfigdescriptor = exallocatepool(nonpagedpool, pconfigdesc ->wtotallength);
usbbuildgetdescriptorrequest(purb, (ushort) sizeof (struct _urb_control_descriptor_request),
usb_configuration_descriptor_type, 0, 0, pdevext ->usbconfigdescriptor, null,
pconfigdesc ->wtotallength, null);
nextstack = iogetnextirpstacklocation(pirp);
nextstack->parameters.others.argument1 = urb;
iocalldriver(pdevext ->topstackdevice, pirp);
kdprint(("usblink configuration descriptor:n"));
kdprint(("-------------------------n"));
kdprint(("bdescriptortype 0x%xn", pdevext ->usbconfigdescriptor->bdescriptortype));
kdprint(("wtotallength 0x%xn", pdevext ->usbconfigdescriptor-> wtotallength));
kdprint(("bnuminterfaces 0x%xn", pdevext ->usbconfigdescriptor->bnuminterfaces));
kdprint(("iconfiguration 0x%xn", pdevext ->usbconfigdescriptor->iconfiguration));
kdprint(("bmattributes 0x%xn", pdevext ->usbconfigdescriptor->bmattributes));
kdprint(("maxpower 0x%xn", pdevext ->usbconfigdescriptor->maxpower));
exfreepool(pconfigdesc);
exfreepool(purb);
//Получив конфигурационный описатель (дескриптор) получим список интерфейсов, предоставляемых устройством. Этим занимается usbd.sys.
pusbd_interface_list_entry pinterfaceslist;
pusb_interface_descriptor pcurrentdescriptor;
ulong i;
pinterfaceslist = exallocatepool(nonpagedpool, sizeof(usbd_interface_list_entry)*
(pdevext ->usbconfigdescriptor -> bnuminterfaces + 1) );
for (i = 0; i < pdevext ->usbconfigdescriptor ->bnuminterfaces; i++ )
{
pcurrentdescriptor = usbd_parseconfigurationdescriptorex(pdevext->usbconfigdescriptor,
pdevext->usbconfigdescriptor, i, 0, -1, -1, -1 );
pinterfaceslist.interfacedescriptor = pcurrentdescriptor;
pinterfaceslist.interface = null;
}
pinterfaceslist.interfacedescriptor = null;
pinterfaceslist.interface = null;
purb = usbd_createconfigurationrequestex(pdevext ->usbconfigdescriptor, pinterfaceslist);
for (i = 0; i < pinterfaceslist[0].interface->numberofpipes; ++i)
pinterfaceslist[0].interface -> pipes.maximumtransfersize = max_transfer_size;
usbbuildselectconfigurationrequest(purb, sizeof(struct _urb_select_configuration),
pdevext->usbconfigdescriptor);
pirp = iobuilddeviceiocontrolrequest(ioctl_internal_usb_submit_urb,
pdevext ->topstackdevice, null, 0, null, 0, true, &event, &iostatus);
nextstack = iogetnextirpstacklocation(pirp);
nextstack->parameters.others.argument1 = urb;
iocalldriver(pdevext ->topstackdevice, pirp);
/*После обработки запроса, сформированного с помощью usbd_createconfigurationrequestex для каждого элемента списка интерфейсов мы получим кое-что интересное: pinterfaceslist[num].interface ->pipes – список пайпов данного интерфейса (массив структур usbd_pipe_information). Запись в пайп производится либо по инициативе драйвера, либо по инициативе клиента драйвера – при обработке запроса irp_mj_write. */
ntstatus ntstatus = status_success;
pdevice_extension pdevext;
pio_stack_location pirpstack, pnextstack;
ulong length = 0;
purb purb = null, pprevurb = null, pfirsturb = null;
pmdl pmdl;
pdevext = deviceobject -> deviceextension;
pirpstack = iogetcurrentirpstacklocation (irp);
if (irp->mdladdress) length = mmgetmdlbytecount(irp->mdladdress);
purb = exallocatepool(nonpagedpool,
sizeof(struct _urb_bulk_or_interrupt_transfer) );
rtlzeromemory(purb, sizeof(struct _urb_bulk_or_interrupt_transfer));
purb ->urbbulkorinterrupttransfer.hdr.length = (ushort) sizeof(struct _urb_bulk_or_interrupt_transfer);
purb ->urbbulkorinterrupttransfer.hdr.function = urb_function_bulk_or_interrupt_transfer;
purb ->urbbulkorinterrupttransfer.pipehandle = pdevext ->writepipehandle;
purb ->urbbulkorinterrupttransfer.transferflags = usbd_transfer_direction_in ;
purb ->urbbulkorinterrupttransfer.transferflags |= usbd_short_transfer_ok;
purb ->urbbulkorinterrupttransfer.urblink = null;
purb ->urbbulkorinterrupttransfer.transferbuffermdl = irp->mdladdress;
purb->urbbulkorinterrupttransfer.transferbufferlength = length;
pnextstack = iogetnextirpstacklocation(irp);
pnextstack->parameters.others.argument1 = purb;
pnextstack->majorfunction = irp_mj_internal_device_control;
pnextstack->parameters.deviceiocontrol.iocontrolcode = ioctl_internal_usb_submit_urb;
iocalldriver(pdevext ->topstackdevice, irp );
}
{
ntstatus ntstatus = status_success;
pdevice_extension pdevext = null;
purb purb = null;
pusb_device_descriptor pdevdesc = null;
pusb_configuration_descriptor pconfigdesc = null;
pdevext = deviceobject->deviceextension;
purb = exallocatepool(nonpagedpool, sizeof(struct _urb_control_descriptor_request) ) ;
pdevdesc = exallocatepool(nonpagedpool, sizeof(usb_device_descriptor) );
usbbuildgetdescriptorrequest(purb,(ushort)sizeof(struct _urb_control_descriptor_request),
usb_device_descriptor_type, 0, 0, pdevdesc, null, sizeof(usb_device_descriptor), null);
pirp = iobuilddeviceiocontrolrequest(ioctl_internal_usb_submit_urb,
pdevext ->topstackdevice, null, 0, null, 0, true, &event, &iostatus);
nextstack = iogetnextirpstacklocation(pirp);
nextstack->parameters.others.argument1 = urb;
//При нормальном стечении обстоятельств, вот тебе инфа об устройстве))))
kdprint(("usblink device descriptor:n"));
kdprint(("-------------------------n"));
kdprint(("blength %dn", pdevdesc->blength));
kdprint(("bdescriptortype 0x%xn", pdevdesc->bdescriptortype));
kdprint(("bcdusb 0x%xn", pdevdesc->bcdusb));
kdprint(("bdeviceclass 0x%xn", pdevdesc->bdeviceclass));
kdprint(("bdevicesubclass 0x%xn", pdevdesc->bdevicesubclass));
kdprint(("bdeviceprotocol 0x%xn", pdevdesc->bdeviceprotocol));
kdprint(("bmaxpacketsize0 0x%xn", pdevdesc->bmaxpacketsize0));
kdprint(("idvendor 0x%xn", pdevdesc->idvendor));
kdprint(("idproduct 0x%xn", pdevdesc->idproduct));
kdprint(("bcddevice 0x%xn", pdevdesc->bcddevice));
kdprint(("imanufacturer 0x%xn", pdevdesc->imanufacturer));
kdprint(("iproduct 0x%xn", pdevdesc->iproduct));
kdprint(("iserialnumber 0x%xn", pdevdesc->iserialnumber));
kdprint(("bnumconfigurations 0x%xn", pdevdesc->bnumconfigurations));
//Запомним эту информацию в контексте устройства
pdevext ->usbdevicedescriptor = pdevdesc;
//Теперь используем полученную информацию для инициализации устройства:
Построим еще один urb запрос
pconfigdesc = exallocatepool(nonpagedpool, sizeof(usb_configuration_descriptor) );
usbbuildgetdescriptorrequest(purb,
(ushort) sizeof (struct _urb_control_descriptor_request), usb_configuration_descriptor_type, 0, 0, pconfigdesc, null, sizeof(usb_configuration_descriptor), null);
pirp = iobuilddeviceiocontrolrequest(ioctl_internal_usb_submit_urb,
pdevext ->topstackdevice, null, 0, null, 0, true, &event, &iostatus);
nextstack = iogetnextirpstacklocation(pirp);
nextstack->parameters.others.argument1 = urb;
iocalldriver(pdevext ->topstackdevice, pirp);
//А вот теперь попробуем получить актуальную конфигурационную информацию:
pdevext ->usbconfigdescriptor = exallocatepool(nonpagedpool, pconfigdesc ->wtotallength);
usbbuildgetdescriptorrequest(purb, (ushort) sizeof (struct _urb_control_descriptor_request),
usb_configuration_descriptor_type, 0, 0, pdevext ->usbconfigdescriptor, null,
pconfigdesc ->wtotallength, null);
nextstack = iogetnextirpstacklocation(pirp);
nextstack->parameters.others.argument1 = urb;
iocalldriver(pdevext ->topstackdevice, pirp);
kdprint(("usblink configuration descriptor:n"));
kdprint(("-------------------------n"));
kdprint(("bdescriptortype 0x%xn", pdevext ->usbconfigdescriptor->bdescriptortype));
kdprint(("wtotallength 0x%xn", pdevext ->usbconfigdescriptor-> wtotallength));
kdprint(("bnuminterfaces 0x%xn", pdevext ->usbconfigdescriptor->bnuminterfaces));
kdprint(("iconfiguration 0x%xn", pdevext ->usbconfigdescriptor->iconfiguration));
kdprint(("bmattributes 0x%xn", pdevext ->usbconfigdescriptor->bmattributes));
kdprint(("maxpower 0x%xn", pdevext ->usbconfigdescriptor->maxpower));
exfreepool(pconfigdesc);
exfreepool(purb);
//Получив конфигурационный описатель (дескриптор) получим список интерфейсов, предоставляемых устройством. Этим занимается usbd.sys.
pusbd_interface_list_entry pinterfaceslist;
pusb_interface_descriptor pcurrentdescriptor;
ulong i;
pinterfaceslist = exallocatepool(nonpagedpool, sizeof(usbd_interface_list_entry)*
(pdevext ->usbconfigdescriptor -> bnuminterfaces + 1) );
for (i = 0; i < pdevext ->usbconfigdescriptor ->bnuminterfaces; i++ )
{
pcurrentdescriptor = usbd_parseconfigurationdescriptorex(pdevext->usbconfigdescriptor,
pdevext->usbconfigdescriptor, i, 0, -1, -1, -1 );
pinterfaceslist.interfacedescriptor = pcurrentdescriptor;
pinterfaceslist.interface = null;
}
pinterfaceslist.interfacedescriptor = null;
pinterfaceslist.interface = null;
purb = usbd_createconfigurationrequestex(pdevext ->usbconfigdescriptor, pinterfaceslist);
for (i = 0; i < pinterfaceslist[0].interface->numberofpipes; ++i)
pinterfaceslist[0].interface -> pipes.maximumtransfersize = max_transfer_size;
usbbuildselectconfigurationrequest(purb, sizeof(struct _urb_select_configuration),
pdevext->usbconfigdescriptor);
pirp = iobuilddeviceiocontrolrequest(ioctl_internal_usb_submit_urb,
pdevext ->topstackdevice, null, 0, null, 0, true, &event, &iostatus);
nextstack = iogetnextirpstacklocation(pirp);
nextstack->parameters.others.argument1 = urb;
iocalldriver(pdevext ->topstackdevice, pirp);
/*После обработки запроса, сформированного с помощью usbd_createconfigurationrequestex для каждого элемента списка интерфейсов мы получим кое-что интересное: pinterfaceslist[num].interface ->pipes – список пайпов данного интерфейса (массив структур usbd_pipe_information). Запись в пайп производится либо по инициативе драйвера, либо по инициативе клиента драйвера – при обработке запроса irp_mj_write. */
ntstatus ntstatus = status_success;
pdevice_extension pdevext;
pio_stack_location pirpstack, pnextstack;
ulong length = 0;
purb purb = null, pprevurb = null, pfirsturb = null;
pmdl pmdl;
pdevext = deviceobject -> deviceextension;
pirpstack = iogetcurrentirpstacklocation (irp);
if (irp->mdladdress) length = mmgetmdlbytecount(irp->mdladdress);
purb = exallocatepool(nonpagedpool,
sizeof(struct _urb_bulk_or_interrupt_transfer) );
rtlzeromemory(purb, sizeof(struct _urb_bulk_or_interrupt_transfer));
purb ->urbbulkorinterrupttransfer.hdr.length = (ushort) sizeof(struct _urb_bulk_or_interrupt_transfer);
purb ->urbbulkorinterrupttransfer.hdr.function = urb_function_bulk_or_interrupt_transfer;
purb ->urbbulkorinterrupttransfer.pipehandle = pdevext ->writepipehandle;
purb ->urbbulkorinterrupttransfer.transferflags = usbd_transfer_direction_in ;
purb ->urbbulkorinterrupttransfer.transferflags |= usbd_short_transfer_ok;
purb ->urbbulkorinterrupttransfer.urblink = null;
purb ->urbbulkorinterrupttransfer.transferbuffermdl = irp->mdladdress;
purb->urbbulkorinterrupttransfer.transferbufferlength = length;
pnextstack = iogetnextirpstacklocation(irp);
pnextstack->parameters.others.argument1 = purb;
pnextstack->majorfunction = irp_mj_internal_device_control;
pnextstack->parameters.deviceiocontrol.iocontrolcode = ioctl_internal_usb_submit_urb;
iocalldriver(pdevext ->topstackdevice, irp );
}
Пользовательское приложение взаимодействует с устройством опосредованно – через драйвер этого устройства.
Рассмотрим код, позволяющий получить доступ к драйверу устройства как к файлу. Сначала нужно получить описатель класса устройства:
Код:
hdevinfo hdevinfo = setupdigetclassdevs ( (guid*)& guid_class_usb_drv, null, null, digcf_present | digcf_interfacedevice );
Далее получаем краткую информацию для интерфейсов (в данном случае, для первого интерфейса в списке с подходящим guid):
Код:
psp_device_interface_data devinfodata =
(psp_device_interface_data)malloc(sizeof(sp_device_interface_data));
devinfodata ->cbsize = sizeof(sp_device_interface_data);
setupdienumdeviceinterfaces(hdevinfo, null, (guid*)&guid_class_usb_link, 0,
devinfodata);
//После того, можно попытаться узнать символическое имя для устройства с заданным интерфейсом. Но для этого сначала определим необходимую для хранения этого имени длину буфера:
ulong requiredlength;
setupdigetinterfacedevicedetail (hdevinfo, devinfodata, null, 0, &requiredlength, null);
//А теперь можно наконец узнать имя, присвоенное устройству:
psp_device_interface_detail_data devinfodetail =
(psp_device_interface_detail_data)malloc(requiredlength);
devinfodetail ->cbsize = sizeof(sp_device_interface_detail_data);
setupdigetinterfacedevicedetail (hdevinfo, devinfodata, devinfodetail,
requiredlength, &requiredlength, null);
(psp_device_interface_data)malloc(sizeof(sp_device_interface_data));
devinfodata ->cbsize = sizeof(sp_device_interface_data);
setupdienumdeviceinterfaces(hdevinfo, null, (guid*)&guid_class_usb_link, 0,
devinfodata);
//После того, можно попытаться узнать символическое имя для устройства с заданным интерфейсом. Но для этого сначала определим необходимую для хранения этого имени длину буфера:
ulong requiredlength;
setupdigetinterfacedevicedetail (hdevinfo, devinfodata, null, 0, &requiredlength, null);
//А теперь можно наконец узнать имя, присвоенное устройству:
psp_device_interface_detail_data devinfodetail =
(psp_device_interface_detail_data)malloc(requiredlength);
devinfodetail ->cbsize = sizeof(sp_device_interface_detail_data);
setupdigetinterfacedevicedetail (hdevinfo, devinfodata, devinfodetail,
requiredlength, &requiredlength, null);
После этого, открываем устройство как файл:
Код:
husbdevice = createfile ( devinfodetail->devicepath, generic_read | generic_write, file_share_read | file_share_write, null, open_existing, 0, null);
После этого, с устройством можно работать как с обычным файлом: используя функции readfile(ex), writefile(ex), deviceiocontrol.
Я задолбался это описывать, будут вопросы пиши! Объясню, что и как если не понял. :rolleyes:
Кстати, есть такая полезная тулзовина: HHD USB Monitor называется.
Цитата:
The USB Monitor installs the filter driver between the host controller and the device driver, which allows it to monitor all the data transferred and display it to the user in the easily readable format.
Что наводит на мысли о возможном решении поставленной задачи.
Цитата:
Ой, накропал-то сколько :)
Ужасно устал писать)))))))))
Цитата:
Кстати, есть такая полезная тулзовина: HHD USB Monitor называется.
Прога то есть, но может чувак хочет заняться написанием собственной.