Получить букву диска или ms-dos name
От: Mhael Беларусь  
Дата: 04.11.09 13:05
Оценка:
Есть устройство: usb mass storage, я знаю его VidPid и имя Mymegadevice Storage USB Device (оно видно в свойства диска-оборудование) .
Я умею находить через SetupDi-функции данное устройство (по гуид отбираю класс USB и в нем по vidpid сам девайс) SymbolicName, но его не воспринимает DeviceIoControl , а мне надо.
Я знаю, что можно получить буквы всех дисков, их дос-имена и даже кой-какие параметры с пом. Volume Management Functions .
Могу я сделать CreateFile на SymbolicName и наверное что-то узнать — размер там.. писать туда и читать наверное смогу файлы. Но, я не знаю моё ли это устройство, у меня ведь есть только vidpid и имя !
Вот такая незадача, надо найти устройство и получить имя, подходящее для DeviceIoControl , но как сделать — непонятно!
Прошу помощи.
P.S. Я знаю, что можно было бы, перебирая все диски (тут даже можно отсечь сразу hdd наверное..), посылать им через DeviceIoControl какую-нить команду на запрос данных об устройстве, но неужели в винде нет способа проще?
Также я нашел интересный раздел HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices , там как раз лежат дос-имена и манят.. но опять таки не понятно как определить имя моего устройства
Re: Получить букву диска или ms-dos name
От: x64 Россия http://x64blog.name
Дата: 04.11.09 23:22
Оценка:
M>Я умею находить через SetupDi-функции данное устройство (по гуид отбираю класс USB и в нем по vidpid сам девайс) SymbolicName...

Для начала в каком формате ты получаешь этот SymbolicName? Приведи пример.

M>Я знаю, что можно получить буквы всех дисков, их дос-имена и даже кой-какие параметры с пом. Volume Management Functions .


Через эти функции можно получить всё, что тебе нужно, но как именно зависит от того, что у тебя уже есть на руках, — см. вопрос выше.

M>Также я нашел интересный раздел HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices...


Сюда тебе точно не надо, это только для Mount Manager'а.
JID: x64j@jabber.ru
Re: Получить букву диска или ms-dos name
От: Pavel Dvorkin Россия  
Дата: 05.11.09 05:47
Оценка:
Здравствуйте, Mhael, Вы писали:

M>Есть устройство: usb mass storage, я знаю его VidPid и имя Mymegadevice Storage USB Device (оно видно в свойства диска-оборудование) .

M>Я умею находить через SetupDi-функции данное устройство (по гуид отбираю класс USB и в нем по vidpid сам девайс) SymbolicName, но его не воспринимает DeviceIoControl , а мне надо.
M>Я знаю, что можно получить буквы всех дисков, их дос-имена и даже кой-какие параметры с пом. Volume Management Functions .
M>Могу я сделать CreateFile на SymbolicName и наверное что-то узнать — размер там.. писать туда и читать наверное смогу файлы. Но, я не знаю моё ли это устройство, у меня ведь есть только vidpid и имя !
M>Вот такая незадача, надо найти устройство и получить имя, подходящее для DeviceIoControl , но как сделать — непонятно!

QueryDosDevice по всем имеющимся дискам ?
With best regards
Pavel Dvorkin
Re: Получить букву диска или ms-dos name
От: Alexey Frolov Беларусь  
Дата: 06.11.09 08:32
Оценка:
Здравствуйте, Mhael, Вы писали:

M>Я умею находить через SetupDi-функции данное устройство (по гуид отбираю класс USB и в нем по vidpid сам девайс) SymbolicName, но его не воспринимает DeviceIoControl , а мне надо.


Что значит его не воспринимает DeviceIoControl? Можно конкретнее?

Какой IOCTL_CODE вы хотите отправить девайсу, у меня есть подозрение что вы находите не тот девайс и вам надо немного выше по цепочке пройтись.
По классу USB (VID_PID)вы получите девайс который воспринимает только SCSI команды, выше находится Disk (скорее всего он вам нужен), а еще выше Volume (может быть и он ваша цель)
Re[2]: Получить букву диска или ms-dos name
От: Mhael Беларусь  
Дата: 06.11.09 10:47
Оценка:
Здравствуйте, Alexey Frolov, Вы писали:

AF>Здравствуйте, Mhael, Вы писали:


M>>Я умею находить через SetupDi-функции данное устройство (по гуид отбираю класс USB и в нем по vidpid сам девайс) SymbolicName, но его не воспринимает DeviceIoControl , а мне надо.


AF>Что значит его не воспринимает DeviceIoControl? Можно конкретнее?


AF>Какой IOCTL_CODE вы хотите отправить девайсу, у меня есть подозрение что вы находите не тот девайс и вам надо немного выше по цепочке пройтись.

AF>По классу USB (VID_PID)вы получите девайс который воспринимает только SCSI команды, выше находится Disk (скорее всего он вам нужен), а еще выше Volume (может быть и он ваша цель)

Вот пример моего кода с описанием:

    GUID tmpguid = {0xA5DCBF10, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}; //ddk GUID_DEVINTERFACE_USB_DEVICE;
    // Строим список подключённых устройств с заданными параметрами и получаем дескриптор на него
    hDeviceList = SetupDiGetClassDevs(&tmpguid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (hDeviceList == INVALID_HANDLE_VALUE) return 1;

    DWORD errCode = 0, tmpsize = 0, countDev = 0, countMyDev = 0;
    SP_DEVINFO_DATA Devinfo; //инфа об устройстве
    SP_DEVICE_INTERFACE_DATA Interface;
    PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailed;
    wchar_t wcVidPidStr[512] = {0}; //for hardwareid

    for (countDev = 0; countDev < 10000;)
    {
        memset(&Devinfo, 0, sizeof(SP_DEVINFO_DATA));
        Devinfo.cbSize = sizeof(SP_DEVINFO_DATA); // Нужно установить.
        if (!SetupDiEnumDeviceInfo(hDeviceList, countDev, &Devinfo)) //Получаем информацию об очередном устройстве из списка. 
        {
            if(GetLastError()== ERROR_NO_MORE_ITEMS) break;
            else return 1;
        }//!SetupDiEnumDeviceInfo

        memset(wcVidPidStr, 0, sizeof(wcVidPidStr));
        if ( !SetupDiGetDeviceRegistryProperty(hDeviceList, &Devinfo, SPDRP_HARDWAREID, NULL, (byte*)wcVidPidStr,
            sizeof(wcVidPidStr), &tmpsize) )  //получаем строку с vidpid
        {
            if(!SetupDiDeleteDeviceInfo(hDeviceList, &Devinfo)) countDev++; 
            continue; //пробуем следующее по списку
        }

        _wcslwr_s(wcVidPidStr, 512); //в нижний регистр
        if(wcsstr(wcVidPidStr, MY_VID_PID) == NULL) //ищем наше устройство (по vidpid)
        {
            if(!SetupDiDeleteDeviceInfo(hDeviceList, &Devinfo)) countDev++; //если не нашли, то идем за следующим
            continue;
        }
        else
        {
            memset(&Interface, 0, sizeof(SP_DEVICE_INTERFACE_DATA));
            Interface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); // Фиксировано            
            if(!SetupDiEnumDeviceInterfaces(hDeviceList, NULL, &tmpguid, countMyDev, &Interface)) //Получаем информацию об интерфейсе (нужно для вызова функций далее)
            {
                if(!SetupDiDeleteDeviceInfo(hDeviceList, &Devinfo)) countDev++; 
                continue; //пробуем следующее по списку
            }

            SetupDiGetDeviceInterfaceDetail(hDeviceList, &Interface, NULL, NULL, &tmpsize, NULL); //Получаем путь к устройству. Сначала получим размер необходимой памяти.
            errCode = GetLastError();
            if(errCode != ERROR_INSUFFICIENT_BUFFER)
            {
                if(!SetupDiDeleteDeviceInfo(hDeviceList, &Devinfo)) countDev++; 
                continue; //пробуем следующее по списку
            }

            pInterfaceDetailed = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(tmpsize);
            if (pInterfaceDetailed == NULL)
            {
                if(!SetupDiDeleteDeviceInfo(hDeviceList, &Devinfo)) countDev++; 
                continue; //пробуем следующее по списку
            }
            pInterfaceDetailed->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

            // Считываем подробную информацию об интерфейсе
            if(!SetupDiGetDeviceInterfaceDetail(hDeviceList, &Interface, pInterfaceDetailed, tmpsize, NULL, NULL))
            {
                free(pInterfaceDetailed);
                if(!SetupDiDeleteDeviceInfo(hDeviceList, &Devinfo)) countDev++; 
                continue; //пробуем следующее по списку
            }
            countMyDev++; //это наш клиент
            free(pInterfaceDetailed);
            vstrSymLinks.push_back(pInterfaceDetailed->DevicePath);
            if(!SetupDiDeleteDeviceInfo(hDeviceList, &Devinfo)) countDev++; 
        }//our vidpid
    }//for

//И вот я получил SymbolicName
//Посылаю устройству команду читать нулевой сектор

    struct scsi_st 
    {
        SCSI_PASS_THROUGH_DIRECT t_spti;
        DWORD tmp;
        byte sensebuf[32];
    } myspti;
    vector<byte> vbuf;
        hDevice = CreateFile(vstrSymLinks[i], GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); //Устройство открылось, хэндл получен
        if (hDevice == INVALID_HANDLE_VALUE) return 1;

            memset(&myspti, 0, sizeof(scsi_st));
            myspti.t_spti.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
            myspti.t_spti.Lun = 0;
            myspti.t_spti.TargetId = 0;
            myspti.t_spti.PathId = 0;
            myspti.t_spti.CdbLength = 10;
            myspti.t_spti.DataIn = SCSI_IOCTL_DATA_IN;
            myspti.t_spti.SenseInfoLength = 32;
            myspti.t_spti.SenseInfoOffset = sizeof(SCSI_PASS_THROUGH_DIRECT) + sizeof(DWORD);
            myspti.t_spti.TimeOutValue = 10; //2
            vbuf.assign(512, 0);
            myspti.t_spti.DataTransferLength = (DWORD)vbuf.size();
            myspti.t_spti.DataBuffer = &vbuf[0];
            myspti.t_spti.Cdb[0] = READ_10;
            myspti.t_spti.Cdb[1] = 0;
            myspti.t_spti.Cdb[2] = addr[3];
            myspti.t_spti.Cdb[3] = addr[2];
            myspti.t_spti.Cdb[4] = addr[1];
            myspti.t_spti.Cdb[5] = addr[0];
            myspti.t_spti.Cdb[6] = 0;
            myspti.t_spti.Cdb[7] = len[1];
            myspti.t_spti.Cdb[8] = len[0];
            myspti.t_spti.Cdb[9] = 0;

            DWORD returned = 0;
            if(!DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &myspti, sizeof(scsi_st), &myspti, sizeof(scsi_st), &returned, NULL))
                return 1;
//Что здесь происходит! Я получаю ERROR_NOT_SUPPORTED на SymbolicName , а если я CreateFile делаю на L"\\\\.\\j:" или на L"\\\\.\\PhysicalDrive1" , то все отлично - читает нулевой сектор и причем
//содержимое там правильное, т.е. читается ок.


Соответственно мне надо по VendorId_ProductId получить букву диски или дос-имя. Пока я не понял как, кроме перебора всех букв с помощью QueryDosDevice и слать им ээ.. IOCTL_SCSI_GET_INQUIRY_DATA наверное?
Re[2]: Получить букву диска или ms-dos name
От: Mhael Беларусь  
Дата: 06.11.09 13:30
Оценка:
Здравствуйте, x64, Вы писали:

M>>Я умею находить через SetupDi-функции данное устройство (по гуид отбираю класс USB и в нем по vidpid сам девайс) SymbolicName...


x64>Для начала в каком формате ты получаешь этот SymbolicName? Приведи пример.


\??\USB#Vid_xxxx&Pid_yyyy#1000000000000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
Re: Получить букву диска или ms-dos name
От: Mhael Беларусь  
Дата: 06.11.09 13:32
Оценка:
Здравствуйте, Mhael, Вы писали:

M>Есть устройство: usb mass storage, я знаю его VidPid и имя Mymegadevice Storage USB Device (оно видно в свойства диска-оборудование) .

M>Я умею находить через SetupDi-функции данное устройство (по гуид отбираю класс USB и в нем по vidpid сам девайс) SymbolicName, но его не воспринимает DeviceIoControl , а мне надо.
M>Я знаю, что можно получить буквы всех дисков, их дос-имена и даже кой-какие параметры с пом. Volume Management Functions .
M>Могу я сделать CreateFile на SymbolicName и наверное что-то узнать — размер там.. писать туда и читать наверное смогу файлы. Но, я не знаю моё ли это устройство, у меня ведь есть только vidpid и имя !
M>Вот такая незадача, надо найти устройство и получить имя, подходящее для DeviceIoControl , но как сделать — непонятно!
M>Прошу помощи.
M>P.S. Я знаю, что можно было бы, перебирая все диски (тут даже можно отсечь сразу hdd наверное..), посылать им через DeviceIoControl какую-нить команду на запрос данных об устройстве, но неужели в винде нет способа проще?
M>Также я нашел интересный раздел HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices , там как раз лежат дос-имена и манят.. но опять таки не понятно как определить имя моего устройства

И вот только что наткнулся в теме про device class interface на мсдн
When a driver registers an instance of a device interface class, the I/O manager associates the device and the device interface class GUID with a symbolic link name. The link name is stored in the registry and persists across system starts. An application that uses the interface can query for instances of the interface and receive a symbolic link name representing a device that supports the interface. The application can then use the symbolic link name as a target for I/O requests.

во блин, получается DeviceIoControl должон работать с SymbolicName . Или это уже приколы конкретно реализации SCSI Pass Through Interface ((
Re[2]: Получить букву диска или ms-dos name
От: Alexey Frolov Беларусь  
Дата: 09.11.09 10:09
Оценка: +1
Здравствуйте, Mhael, Вы писали:

M>во блин, получается DeviceIoControl должон работать с SymbolicName . Или это уже приколы конкретно реализации SCSI Pass Through Interface ((


Видимо вы что то неправильно поняли в описании. DeviceIoControl работает с девайсами через открытый хэндл — эта часть у вас проблем не вызвала. Проблема в том что вы используете не тот девайс, либо не так его используете
Re[3]: Получить букву диска или ms-dos name
От: Alexey Frolov Беларусь  
Дата: 09.11.09 10:59
Оценка:
Здравствуйте, Mhael, Вы писали:

M>Вот пример моего кода с описанием:


M>
M>//И вот я получил SymbolicName
M>//Посылаю устройству команду читать нулевой сектор

M>        hDevice = CreateFile(vstrSymLinks[i], GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); //Устройство открылось, хэндл получен
M>            if(!DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &myspti, sizeof(scsi_st), &myspti, sizeof(scsi_st), &returned, NULL))
M>                return 1;
M>//Что здесь происходит! Я получаю ERROR_NOT_SUPPORTED на SymbolicName , а если я CreateFile делаю на L"\\\\.\\j:" или на L"\\\\.\\PhysicalDrive1" , то все отлично - читает нулевой сектор и причем
M>//содержимое там правильное, т.е. читается ок.

M>


M>Соответственно мне надо по VendorId_ProductId получить букву диски или дос-имя. Пока я не понял как, кроме перебора всех букв с помощью QueryDosDevice и слать им ээ.. IOCTL_SCSI_GET_INQUIRY_DATA наверное?


Конкретно в данном случае вы отправляете IOCTL_SCSI_PASS_THROUGH_DIRECT не тому устройству, pass through фактически означает передать SCSI команду вниз по стеку адресату (порт\ минипорт драйвер), это сделано для возможности слать такие команды из user mode через deviceiocontrol прямо на диск либо том, а там в kernel разберутся . Ваше устройство само является адресатом и выполняет SCSI команды путем обработки IRP_MJ_SCSI (IRP_MJ_INTERNAL_DEVICE_CONTROL), соответственно pass through оно не поддерживает по определению, дальше некуда передавать.

Вы не могли бы поточнее обрисовать задачу, потому что здесь я вижу несколько вариантов решения. Какие устройства вас интересуют понятно (в смысле критерия), а вот что вы хотите с ними делать не совсем ясно. Если считать нулевой сектор, то можно и не прибегая к SCSI, если слать другие SCSI команды, тогда понятно.

Навскидку могу предложить пару вариантов
1) идем снизу от этих найденных устройств CM_Get_Child, CM_Get_Sibling и находим нужные нам disk либо volume (в зависимости от задачи) и работаем с ними IOCTL_SCSI_PASS_THROUGH_DIRECT или может сразу сектора читать с устройства через ReadFile
2) поиск начинаем сразу среди устройств диск или том, и проверяем критерии, либо вниз CM_Get_Parent (мне такой метод не очень нравится), либо отправляем запрос IOCTL_STORAGE_QUERY_PROPERTY (StorageDeviceProperty), читаем эту структуру

typedef struct _STORAGE_DEVICE_DESCRIPTOR {
  ULONG  Version;
  ULONG  Size;
  UCHAR  DeviceType;
  UCHAR  DeviceTypeModifier;
  BOOLEAN  RemovableMedia;
  BOOLEAN  CommandQueueing;
  ULONG  VendorIdOffset;
  ULONG  ProductIdOffset;
  ULONG  ProductRevisionOffset;
  ULONG  SerialNumberOffset;
  STORAGE_BUS_TYPE  BusType;
  ULONG  RawPropertiesLength;
  UCHAR  RawDeviceProperties[1];
} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;


и фильтруем по критериям USB, vendor, product
Re[4]: Получить букву диска или ms-dos name
От: Mhael Беларусь  
Дата: 11.11.09 14:27
Оценка:
Здравствуйте, Alexey Frolov, Вы писали:

...

AF>Конкретно в данном случае вы отправляете IOCTL_SCSI_PASS_THROUGH_DIRECT не тому устройству, pass through фактически означает передать SCSI команду вниз по стеку адресату (порт\ минипорт драйвер), это сделано для возможности слать такие команды из user mode через deviceiocontrol прямо на диск либо том, а там в kernel разберутся . Ваше устройство само является адресатом и выполняет SCSI команды путем обработки IRP_MJ_SCSI (IRP_MJ_INTERNAL_DEVICE_CONTROL), соответственно pass through оно не поддерживает по определению, дальше некуда передавать.


AF>Вы не могли бы поточнее обрисовать задачу, потому что здесь я вижу несколько вариантов решения. Какие устройства вас интересуют понятно (в смысле критерия), а вот что вы хотите с ними делать не совсем ясно. Если считать нулевой сектор, то можно и не прибегая к SCSI, если слать другие SCSI команды, тогда понятно.


AF>Навскидку могу предложить пару вариантов

AF>1) идем снизу от этих найденных устройств CM_Get_Child, CM_Get_Sibling и находим нужные нам disk либо volume (в зависимости от задачи) и работаем с ними IOCTL_SCSI_PASS_THROUGH_DIRECT или может сразу сектора читать с устройства через ReadFile
AF>2) поиск начинаем сразу среди устройств диск или том, и проверяем критерии, либо вниз CM_Get_Parent (мне такой метод не очень нравится), либо отправляем запрос IOCTL_STORAGE_QUERY_PROPERTY (StorageDeviceProperty), читаем эту структуру

AF>и фильтруем по критериям USB, vendor, product


...

Устройство подключается по USB и определяется системой как mass storage. Требуется, кроме работы с устройством как с обычной флэшкой (с помощью обычных CreateFile, ReadFile и т.п.), еще и обмениваться с ним командами, заданными разработчиком. Как мы поняли, такое возможно. Или нет?
Вот сижу мучаю Public PnP Configuration Manager Functions , но пока не могу прийти к решению своей проблемы, описанной в постах выше(( Отсылать команду типа _QUERY_PROPERTY каждому диску я не хочу. Ведь есть же другой путь определения моего устройства. В данный момент я гуляю с помощью CM_Get_Child CM_Get_Parent CM_Get_Sibling и CM_Get_Device_ID по device tree (http://msdn.microsoft.com/en-us/library/aa489660.aspx) пытаясь найти связь между vidId_pidId и буквой диска. Надеюсь, что есть какое-то связующее звено, между теми данными, что я могу получить от Volume Management Functions (задав букву диска например) и тем, что я могу получить от Public PnP Configuration Manager Functions или Public Device Installation Functions , однако пока ничего не получается (( Но чувствую надо копать здесь. Неужели никто не делал такого и не в курсе что именно искать!?
Re[5]: Получить букву диска или ms-dos name
От: Alexey Frolov Беларусь  
Дата: 11.11.09 16:57
Оценка:
Здравствуйте, Mhael, Вы писали:

M>Устройство подключается по USB и определяется системой как mass storage. Требуется, кроме работы с устройством как с обычной флэшкой (с помощью обычных CreateFile, ReadFile и т.п.), еще и обмениваться с ним командами, заданными разработчиком. Как мы поняли, такое возможно. Или нет?

Да, возможно. Только как вы правильно начали надо отправлять DeviceIoControl, причем диску. Впрочем насколько я слышал, есть юзермодная либа, которая шлет запросы (URB — USB request block) конкретному USB-устройству. Сразу не подскажу где искать, если вспомню — напишу, может еще кто подскажет, да и поиск по форуму должен помочь

M>Вот сижу мучаю Public PnP Configuration Manager Functions , но пока не могу прийти к решению своей проблемы, описанной в постах выше(( Отсылать команду типа _QUERY_PROPERTY каждому диску я не хочу. Ведь есть же другой путь определения моего устройства.

Путь есть и вы в самом первом посте правильно начали, но тогда чтобы добраться до диска нужно идти вверх через CM_Get_Child, напишите что именно не получается? Да и вообще зачем букву определять? Если команду отправлять не хотите, ну что ж ваше право, но я не понимаю как она может помешать, ну да ладно.

M>В данный момент я гуляю с помощью CM_Get_Child CM_Get_Parent CM_Get_Sibling и CM_Get_Device_ID по device tree (http://msdn.microsoft.com/en-us/library/aa489660.aspx) пытаясь найти связь между vidId_pidId и буквой диска. Надеюсь, что есть какое-то связующее звено, между теми данными, что я могу получить от Volume Management Functions (задав букву диска например) и тем, что я могу получить от Public PnP Configuration Manager Functions или Public Device Installation Functions , однако пока ничего не получается (( Но чувствую надо копать здесь. Неужели никто не делал такого и не в курсе что именно искать!?

Копать надо здесь, делали и в форуме пример вроде был, просто непонятно что именно не получается, вы поподробнее, плиз.
А по той схеме что вы привели, вы находитесь на уровне USB Controller + SCSI adapter в одном флаконе, реализовано драйвером usbstor.sys, следовательно вам надо либо вверх чтобы слать SCSI pass through, либо вы уже на месте, но надо найти библиотеку для работы с usb
Re[6]: Получить букву диска или ms-dos name
От: Mhael Беларусь  
Дата: 16.11.09 15:12
Оценка:
Здравствуйте, Alexey Frolov, Вы писали:

AF>Здравствуйте, Mhael, Вы писали:


M>>Устройство подключается по USB и определяется системой как mass storage. Требуется, кроме работы с устройством как с обычной флэшкой (с помощью обычных CreateFile, ReadFile и т.п.), еще и обмениваться с ним командами, заданными разработчиком. Как мы поняли, такое возможно. Или нет?

AF> Да, возможно. Только как вы правильно начали надо отправлять DeviceIoControl, причем диску. Впрочем насколько я слышал, есть юзермодная либа, которая шлет запросы (URB — USB request block) конкретному USB-устройству. Сразу не подскажу где искать, если вспомню — напишу, может еще кто подскажет, да и поиск по форуму должен помочь

M>>Вот сижу мучаю Public PnP Configuration Manager Functions , но пока не могу прийти к решению своей проблемы, описанной в постах выше(( Отсылать команду типа _QUERY_PROPERTY каждому диску я не хочу. Ведь есть же другой путь определения моего устройства.

AF>Путь есть и вы в самом первом посте правильно начали, но тогда чтобы добраться до диска нужно идти вверх через CM_Get_Child, напишите что именно не получается? Да и вообще зачем букву определять? Если команду отправлять не хотите, ну что ж ваше право, но я не понимаю как она может помешать, ну да ладно.

M>>В данный момент я гуляю с помощью CM_Get_Child CM_Get_Parent CM_Get_Sibling и CM_Get_Device_ID по device tree (http://msdn.microsoft.com/en-us/library/aa489660.aspx) пытаясь найти связь между vidId_pidId и буквой диска. Надеюсь, что есть какое-то связующее звено, между теми данными, что я могу получить от Volume Management Functions (задав букву диска например) и тем, что я могу получить от Public PnP Configuration Manager Functions или Public Device Installation Functions , однако пока ничего не получается (( Но чувствую надо копать здесь. Неужели никто не делал такого и не в курсе что именно искать!?

AF> Копать надо здесь, делали и в форуме пример вроде был, просто непонятно что именно не получается, вы поподробнее, плиз.
AF> А по той схеме что вы привели, вы находитесь на уровне USB Controller + SCSI adapter в одном флаконе, реализовано драйвером usbstor.sys, следовательно вам надо либо вверх чтобы слать SCSI pass through, либо вы уже на месте, но надо найти библиотеку для работы с usb

Вот, что у меня получилось.
Пока юзаю технологию spti. В ней есть недостаток — нужны права админа ((. Пока я могу это игнорировать, но в будущем мне придется найти другой путь.
DeviceIoControl требует хэндл устройства, а spti требует, чтобы устройство это было \\.\K: или \\.\PhysicalDrive1 — к примеру . Иначе DeviceIoControl или CreateFile вернет ошибку.
Как найти эти имена? Второй тип имени я так и не нашел, но есть предположения что он находится через посылку шине/хабу запроса типа inquiry/query ну и последующего перебора и отправке запросов inquiry/query уже устройствам.

Первый тип имени я искал через USB устройства.
SetupDiGetClassDevs на GUID_DEVINTERFACE_USB_DEVICE выдает нам хэндл на список usb device interface.
Затем в цикле выполняем вызовы SetupDiEnumDeviceInfo -> SetupDiGetDeviceRegistryProperty (с запросом SPDRP_HARDWAREID) . Сверяем HARDWAREID с нашими vendorId_productId и если наше усторйство идем далее, разве что можно вызвать SetupDiGetDeviceInstanceId для определения серийного номера (мы его внесли в дескрипторы устройства и поэтому для его определения нам не надо опрашивать девайс лишний раз — \USB\Vid_xxxxxPid_yyyy\1000000000000000 где 10000.. это наш серийник).
Поднимаемся выше по device tree с помощью функций CM_Get_Child -> CM_Get_Device_ID и ищем уровень \STORAGE\RemovableMedia, там видим имя вида \STORAGE\RemovableMedia\8&10849428&0&RM например, где 8&10849428&0&RM — некий рандомный идентификатор диска, который в течении сессии неизменен .
Далее открываем HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices и перебираем параметры ключа (с пом-ю RegEnumValue например). Нас интересуют параметры с именами \DosDevice\X: где Х — буквы дисков. Среди них мы ищем в значениях параметров (а это массивы юникодных символов, по крайней мере для стандартных mass storage без извращений) наш 8&10849428&0&RM . Значит это наш диск. Выгрызаем из имени X: и.. собственно все, можно общаться с устройством.
CreateFile("\\.\x:", ..) -> DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, ...)

Описанная мною последовательность не единственная, можно и через другие функции/параметры/ключи реестра. Я выбрал этот путь, мне он показался не слишком длинный и достаточно надежным.
Увы, если разрабатывать массовое коммерческое приложение, то требование админских прав делают spti практически нереальным вариантом работы с устройством. Буду биться над данной проблемой в ближайшем будущем, наверное придется браться за ASPI, т.к. писать свой драйвер я вряд ли осилю

Ниже исходник примера, требуется вставить свои vendorID_productId. Единственная проблема в примере — почему-то после общения с устройство возникает неприятный глюк — после перезагрузки компа загрузка не идет дальше биоса. Либо нужно еще что-то послать в устройство, какую-то команду закрытия или.. хз чего, либо наш девайс глючит ( Если кто имеет мысли, почему так происходит — напишите.
Вот исходник http://files.rsdn.ru/58991/test.cpp
Re[7]: Получить букву диска или ms-dos name
От: Alexey Frolov Беларусь  
Дата: 16.11.09 16:43
Оценка:
Здравствуйте, Mhael, Вы писали:

M>Вот, что у меня получилось.

M>Пока юзаю технологию spti. В ней есть недостаток — нужны права админа ((. Пока я могу это игнорировать, но в будущем мне придется найти другой путь.
M>DeviceIoControl требует хэндл устройства, а spti требует, чтобы устройство это было \\.\K: или \\.\PhysicalDrive1 — к примеру . Иначе DeviceIoControl или CreateFile вернет ошибку.
M>Как найти эти имена? Второй тип имени я так и не нашел, но есть предположения что он находится через посылку шине/хабу запроса типа inquiry/query ну и последующего перебора и отправке запросов inquiry/query уже устройствам.

Второй тип ищется примерно так как вы и написали, надо найти номер диска и подставить в "\\.\PhysicalDrive%u". Но тут я не уверен можно ли спросить номер диска у того девайса с которым вы работаете или нет.

M>Первый тип имени я искал через USB устройства.

M>SetupDiGetClassDevs на GUID_DEVINTERFACE_USB_DEVICE выдает нам хэндл на список usb device interface.
M>Затем в цикле выполняем вызовы SetupDiEnumDeviceInfo -> SetupDiGetDeviceRegistryProperty (с запросом SPDRP_HARDWAREID) . Сверяем HARDWAREID с нашими vendorId_productId и если наше усторйство идем далее, разве что можно вызвать SetupDiGetDeviceInstanceId для определения серийного номера (мы его внесли в дескрипторы устройства и поэтому для его определения нам не надо опрашивать девайс лишний раз — \USB\Vid_xxxxxPid_yyyy\1000000000000000 где 10000.. это наш серийник).
M>Поднимаемся выше по device tree с помощью функций CM_Get_Child -> CM_Get_Device_ID и ищем уровень \STORAGE\RemovableMedia, там видим имя вида \STORAGE\RemovableMedia\8&10849428&0&RM например, где 8&10849428&0&RM — некий рандомный идентификатор диска, который в течении сессии неизменен .
M>Далее открываем HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices и перебираем параметры ключа (с пом-ю RegEnumValue например). Нас интересуют параметры с именами \DosDevice\X: где Х — буквы дисков. Среди них мы ищем в значениях параметров (а это массивы юникодных символов, по крайней мере для стандартных mass storage без извращений) наш 8&10849428&0&RM . Значит это наш диск. Выгрызаем из имени X: и.. собственно все, можно общаться с устройством.
M>CreateFile("\\.\x:", ..) -> DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, ...)

В принципе для того чтобы общаться с устройством через DeviceIoControl вполне достаточно будет открыть его по этому самому имени вида
\\?\STORAGE\RemovableMedia\7&13ec81c&0&RM#{53f5630a-b6bf-11d0-94f2-00a0c91efb8b}
Re[8]: Получить букву диска или ms-dos name
От: Mhael Беларусь  
Дата: 17.11.09 16:01
Оценка:
Здравствуйте, Alexey Frolov, Вы писали:

AF>В принципе для того чтобы общаться с устройством через DeviceIoControl вполне достаточно будет открыть его по этому самому имени вида

AF>\\?\STORAGE\RemovableMedia\7&13ec81c&0&RM#{53f5630a-b6bf-11d0-94f2-00a0c91efb8b}

CreateFile возвращает ошибку. Похоже это не воспринимается как путь.
Есть ли решение проблемы требования администраторских прав при работе с диском? Что вы посоветуете как альтернативу spti, если решения предыдущего моего вопроса нет? Чтобы попроще конечно хотелось бы. Хид не катит, там скорости маленькие (( , мне надо хотя бы 700 кило выжимать в секунду.
Re[9]: Получить букву диска или ms-dos name
От: Alexey Frolov Беларусь  
Дата: 18.11.09 10:29
Оценка:
Здравствуйте, Mhael, Вы писали:

M>Здравствуйте, Alexey Frolov, Вы писали:


AF>>В принципе для того чтобы общаться с устройством через DeviceIoControl вполне достаточно будет открыть его по этому самому имени вида

AF>>\\?\STORAGE\RemovableMedia\7&13ec81c&0&RM#{53f5630a-b6bf-11d0-94f2-00a0c91efb8b}

M>CreateFile возвращает ошибку. Похоже это не воспринимается как путь.

M>Есть ли решение проблемы требования администраторских прав при работе с диском? Что вы посоветуете как альтернативу spti, если решения предыдущего моего вопроса нет? Чтобы попроще конечно хотелось бы. Хид не катит, там скорости маленькие (( , мне надо хотя бы 700 кило выжимать в секунду.

Ну да с форматом имени я немного ошибся, но его надо получать через SetupDi... функцию и интерфейс GUID_DEVINTERFACE_VOLUME. В частности вот такой код работает, вместо IOCTL_STORAGE_GET_DEVICE_NUMBER можно вызвать IOCTL_SCSI_PASS_THROUGH. Посмотрите код ошибки, который возвращает CreateFile

    DWORD error = NO_ERROR;
    HANDLE hVolume = CreateFile(L"\\\\?\\storage#removablemedia#7&176630d9&0&rm#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}",
                          FILE_READ_ACCESS, 
                          FILE_SHARE_READ | FILE_SHARE_WRITE,
                          NULL, OPEN_EXISTING, 
                          FILE_ATTRIBUTE_DEVICE, 
                          NULL);


    if (INVALID_HANDLE_VALUE != hVolume)
    {
        STORAGE_DEVICE_NUMBER sdn = {0, -1, -1};
        DWORD dwRequired = sizeof(sdn);

        if (!DeviceIoControl(hVolume, 
                            IOCTL_STORAGE_GET_DEVICE_NUMBER, 
                            NULL, 0, 
                            &sdn, sizeof(sdn), 
                            &dwRequired, NULL))
        {
            error = GetLastError();
        }

        CloseHandle(hVolume);
    }
    else
    {
        error = GetLastError();
    }
Re[9]: Получить букву диска или ms-dos name
От: Alexey Frolov Беларусь  
Дата: 18.11.09 11:03
Оценка:
Здравствуйте, Mhael, Вы писали:

M>Здравствуйте, Alexey Frolov, Вы писали:


AF>>В принципе для того чтобы общаться с устройством через DeviceIoControl вполне достаточно будет открыть его по этому самому имени вида

AF>>\\?\STORAGE\RemovableMedia\7&13ec81c&0&RM#{53f5630a-b6bf-11d0-94f2-00a0c91efb8b}

M>CreateFile возвращает ошибку. Похоже это не воспринимается как путь.

M>Есть ли решение проблемы требования администраторских прав при работе с диском? Что вы посоветуете как альтернативу spti, если решения предыдущего моего вопроса нет? Чтобы попроще конечно хотелось бы. Хид не катит, там скорости маленькие (( , мне надо хотя бы 700 кило выжимать в секунду.

Боюсь только что проблему с админскими правами путем отсыла SCSI pass through не решить, так как
#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
требуют прав на запись, разве что через

#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)

но это зависит от железа. Что за команда такая хитрая если не секрет?
Re[9]: Получить букву диска или ms-dos name
От: Alexey Frolov Беларусь  
Дата: 18.11.09 11:20
Оценка:
Здравствуйте, Mhael, Вы писали:

M>Здравствуйте, Alexey Frolov, Вы писали:


AF>>В принципе для того чтобы общаться с устройством через DeviceIoControl вполне достаточно будет открыть его по этому самому имени вида

AF>>\\?\STORAGE\RemovableMedia\7&13ec81c&0&RM#{53f5630a-b6bf-11d0-94f2-00a0c91efb8b}

M>CreateFile возвращает ошибку. Похоже это не воспринимается как путь.

M>Есть ли решение проблемы требования администраторских прав при работе с диском? Что вы посоветуете как альтернативу spti, если решения предыдущего моего вопроса нет? Чтобы попроще конечно хотелось бы. Хид не катит, там скорости маленькие (( , мне надо хотя бы 700 кило выжимать в секунду.

Кстати, по поводу драйвера, вы побоялись что не осилите. А есть ли вообще возможность поставить драйвер? Дело в том что можно написать полноценный PnP драйвер (минипорт если я не ошибаюсь) и реализовать в нем обработку своих IOCTL команд, а можно сделать проще, написать legacy driver-helper, который и будет помогать преодолевать барьер администратора, только он должен быть безопасным и не давать злоумышленникам лишнего доступа в систему кроме обработки ваших команд к устройству
Re[10]: Получить букву диска или ms-dos name
От: Mhael Беларусь  
Дата: 19.11.09 11:35
Оценка:
Здравствуйте, Alexey Frolov, Вы писали:

AF>Здравствуйте, Mhael, Вы писали:


M>>Здравствуйте, Alexey Frolov, Вы писали:


AF>>>В принципе для того чтобы общаться с устройством через DeviceIoControl вполне достаточно будет открыть его по этому самому имени вида

AF>>>\\?\STORAGE\RemovableMedia\7&13ec81c&0&RM#{53f5630a-b6bf-11d0-94f2-00a0c91efb8b}

M>>CreateFile возвращает ошибку. Похоже это не воспринимается как путь.

M>>Есть ли решение проблемы требования администраторских прав при работе с диском? Что вы посоветуете как альтернативу spti, если решения предыдущего моего вопроса нет? Чтобы попроще конечно хотелось бы. Хид не катит, там скорости маленькие (( , мне надо хотя бы 700 кило выжимать в секунду.

AF>Боюсь только что проблему с админскими правами путем отсыла SCSI pass through не решить, так как

AF>#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
AF>#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
AF>требуют прав на запись, разве что через

AF>#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)

AF>#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)

AF>но это зависит от железа. Что за команда такая хитрая если не секрет?



Не совсем понял, что вы имеете в виду. Какая команда?
Re[10]: Получить букву диска или ms-dos name
От: Mhael Беларусь  
Дата: 19.11.09 11:42
Оценка:
Здравствуйте, Alexey Frolov, Вы писали:

AF>Здравствуйте, Mhael, Вы писали:


M>>Здравствуйте, Alexey Frolov, Вы писали:


AF>>>В принципе для того чтобы общаться с устройством через DeviceIoControl вполне достаточно будет открыть его по этому самому имени вида

AF>>>\\?\STORAGE\RemovableMedia\7&13ec81c&0&RM#{53f5630a-b6bf-11d0-94f2-00a0c91efb8b}

M>>CreateFile возвращает ошибку. Похоже это не воспринимается как путь.

M>>Есть ли решение проблемы требования администраторских прав при работе с диском? Что вы посоветуете как альтернативу spti, если решения предыдущего моего вопроса нет? Чтобы попроще конечно хотелось бы. Хид не катит, там скорости маленькие (( , мне надо хотя бы 700 кило выжимать в секунду.

AF>Кстати, по поводу драйвера, вы побоялись что не осилите. А есть ли вообще возможность поставить драйвер? Дело в том что можно написать полноценный PnP драйвер (минипорт если я не ошибаюсь) и реализовать в нем обработку своих IOCTL команд, а можно сделать проще, написать legacy driver-helper, который и будет помогать преодолевать барьер администратора, только он должен быть безопасным и не давать злоумышленникам лишнего доступа в систему кроме обработки ваших команд к устройству


Я не очень разбираюсь в драйверах и их написании. Для установки драйвера надо права администратора, это я знаю. Однако, я слышал от знакомого про устройства (тоже usb mass storage), которые банально можно принести в комп. клуб, где у вас естественно нет прав администратора и они работают и обмениваются с компом своими командами типа шифровать данные и т.п. (это какие-то электронные ключи). Как-то это же сделано, может через aspi ?
Re[11]: Получить букву диска или ms-dos name
От: Alexey Frolov Беларусь  
Дата: 19.11.09 17:10
Оценка:
Здравствуйте, Mhael, Вы писали:

M>Не совсем понял, что вы имеете в виду. Какая команда?


"Требуется, кроме работы с устройством как с обычной флэшкой (с помощью обычных CreateFile, ReadFile и т.п.), еще и обмениваться с ним командами, заданными разработчиком"

вот это я имел ввиду
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.