Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Получить букву диски или ms-dos name

19K
04 ноября 2009 года
Mhael
54 / / 20.03.2008
Есть устройство: usb mass storage, я знаю его VidPid и имя Mymegadevice Storage USB Device (оно видно в свойства диска-оборудование) .
Я умею находить через SetupDi-функции данное устройство (по гуид отбираю класс USB и в нем по vidpid сам девайс) SymbolicName, но его не воспринимает DeviceIoControl , а мне надо.
Я знаю, что можно получить буквы всех дисков, их дос-имена и даже кой-какие параметры с пом. Volume Management Functions .
Могу я сделать CreateFile на SymbolicName и наверное что-то узнать - размер там.. писать туда и читать наверное смогу файлы. Но, я не знаю моё ли это устройство, у меня ведь есть только vidpid и имя !
Вот такая незадача, надо найти устройство и получить имя, подходящее для DeviceIoControl , но как сделать - непонятно!
Прошу помощи.
14
05 ноября 2009 года
Phodopus
3.3K / / 19.06.2008
DeviceIOControl() вообще не работает с именами
19K
06 ноября 2009 года
Mhael
54 / / 20.03.2008
Вот пример моего кода с описанием:

Код:
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, 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;

Что здесь (в DeviceIoControl) происходит! Я получаю ERROR_NOT_SUPPORTED на SymbolicName , а если я CreateFile делаю на L"\\\\.\\j:" или на L"\\\\.PhysicalDrive1" , то все отлично - читает нулевой сектор и причем
содержимое там правильное, т.е. читается ок.


Соответственно мне надо по VendorId_ProductId получить букву диска или дос-имя. Пока я не понял как, кроме перебора всех букв с помощью Volume Management Functions и слать им ээ.. IOCTL_SCSI_GET_INQUIRY_DATA наверное?
14
09 ноября 2009 года
Phodopus
3.3K / / 19.06.2008
Я еще раз обращу ваше внимание на следующее недоразумение:
при чем здесь SymbolicName и DeviceIOControl()?
Где конкретно происходит ошибка? Как выглядит SymbolicName?
19K
09 ноября 2009 года
Mhael
54 / / 20.03.2008
\??\USB#Vid_xxxxxPid_yyyy#1000000000000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed} это символьное имя.
Я и не утверждаю, что надо через него пытаться работать с устройством. Я показываю, что его-то (имя), найти я могу без особых проблем, а вот то что надо - дос-имя или букву диска я пока не могу (не знаю) найти по vendorId_productId ! А ведь явно это можно сделать, я вот читаю семейство функций Public PnP Configuration Manager Functions типа CM_.. и похоже там то, что надо. Только пока еще не разобрался. ((
Если вы ясно представляете последовательность действий для получения буквы диска/дос-имени по vendorId_productId , то прошу написать. Отправлять каждому устройству запросы, мне бы не хотелось, лучше все-таки всзять значения из системы.
14
10 ноября 2009 года
Phodopus
3.3K / / 19.06.2008
Сам этого ни разу не делал, хотя ведь где-то был код.
Пока хочу посоветовать изучить IOCTL_MOUNTDEV_QUERY_UNIQUE_ID и связанные функции. По этому IOCTL по-идее устройство должно вернуть свою \\Volume\{..} по которой уже определяется буква. Это, если я ничего не путаю, и есть ниточка связывающая Device и Volume. Как проясните этот момент - напишите сюда.
7
16 ноября 2009 года
@pixo $oft
3.4K / / 20.09.2006
Не знаю,актуально ли ещё,и то ли это,что надо…
В общем,случайно наткнулся на функцию QueryDOSDevice,прочитал описание и вспомнил про тему.Возможно,она подойдёт
Она по букве диска возвращает имя в формате \Device\<…>.Т.е.,перебирая значения,вы можете наткнуться на нужное.Ибо я понял,что вы имя получаете в формате \Device\<…>

Надеюсь,вам поможет
19K
16 ноября 2009 года
Mhael
54 / / 20.03.2008
Это мне не поможет, т.к. не работает. По крайней мере у меня.
Я решил свою проблему, однако сразу вылезла еще одна - spti работает только под администратором. Один раз, почему-то программа работала под пользователем, но почему я не знаю, возможно все-таки там была ошибка.. или это был глюк. Сейчас, как я не бьюсь, под юзером CreateFile выдает access denied.
Ниже будет пост по поиску буквы диска, имея на руках vendor id and product id и отправке устройству scsi команд. Надеюсь кому-нибудь пригодится
19K
16 ноября 2009 года
Mhael
54 / / 20.03.2008
Итак, напоминаю предысторию:
Создано устройство, подключаемое по юсб и в системе определяемое как mass storage. Т.е. не надо писать своих драйверов, всё за нас написано микрософтом. Мы хотим в него отправлять команды через DeviceIoControl, т.к. просто работы с файлами нам не хватает - мы вводим в устройство еще свои некоторые команды и функционал.
Поехали.
Выбираем технологию spti. В ней есть недостаток - нужны права админа. Пока я могу это игнорировать, но в будущем мне придется найти другой путь.
DeviceIoControl требует хэндл устройства, а spti требует, чтобы устройство это было \\.\K: or \\.\PhysicalDrive1 - к примеру . Иначе DeviceIoControl вернет ошибку.
Как найти эти имена? Второй тип имени я так и не нашел, но есть предположения что он находится через посылку шине запроса типа inquiry/query ну и последующего перебора и отправке запросов inquiry/query уже устройствам.
Первый тип имени находится достаточно легко.
Я искал через USB устройства.
SetupDiGetClassDevs на GUID_DEVINTERFACE_USB_DEVICE выдает нам хэндл на список usb device interface, не забудьте DIGCF_PRESENT|DIGCF_DEVICEINTERFACE .
Затем в цикле выполняем вызовы 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. Единственная проблема в примере - почему-то после общения с устройство возникает неприятный глюк - после перезагрузки компа загрузка не идет дальше биоса. Либо нужно еще что-то послать в устройство, какую-то команду закрытия или.. хз чего, либо наш девайс глючит (
14
17 ноября 2009 года
Phodopus
3.3K / / 19.06.2008
Цитата: Mhael

Как найти эти имена? Второй тип имени я так и не нашел,


Можно через IOCTL_STORAGE_GET_DEVICE_NUMBER.
В целом принцип понятен, но выскажу свои соображения из того что успел изучить.
Действительно, мы когда-то делали нечто подобное для определения шины устройства, но шины эти были IDE и SCSI. Там оказывается несколько проще. Здесь же проблема в том, что за VID/PID отвечает драйвер usbhub (могу попутать имя) а за Ven/Disk/STORAGE - usbstor. И прозрачной схемы связи между объектами создаваемыми этими двумя драйверами я не нашел :(. Дело в том что когда юсб-класс=8 подкласс=6 это сторейдж и тогда подгружается usbstor и начинает свою магию. Далее по протоколу юсб я не разбирался, но знаю, что явно связаны они через этот магический номер типа 000018451960C42C&0. Проблема как раз в том что мне не понятен источник этого номера, т.к. для "нормальных" юсб девайсов он выглядит более-менее, но для юсб-салазок которые я использую он 0 для всех сторейдж устройств которые воткнуты в систему. Следовательно, предположил я, если мы возьмем еще одни подобные (а возможно и такие же) салазки и подключим и их, получим связь типа Х где тот самый 0 будет в центре и появится неопределенность какому vid/pid принадлежит данный сторейдж. Если бы стал понятен принцип формирования этого номера, можно было бы построить законченную схему.

14
30 ноября 2009 года
Phodopus
3.3K / / 19.06.2008
А принцип формирования номерка оказался серийником. А для устройств не богатых серийником система генерит его самостоятельно. Затем usbstor подключается к стеку usbhub и связывается в двусторонний список, позволяя гулять по нему функциями SetupDi*() CM_*(). Вот вроде и ясность появилась.
19K
09 декабря 2009 года
Mhael
54 / / 20.03.2008
Кстати, предупреждаю тех, кто решил также искать похожие устройства. В семерке это не работает. Там не поднимается на уровень STORAGE вообще :( Вот.. сижу, курю. :)
19K
22 декабря 2009 года
Mhael
54 / / 20.03.2008
Вспомнил про тему и решил довести до логического конца. В висте и семерке надо стразу браться за STORAGE (не забывая про DIGCF_PRESENT , но без DIGCF_DEVICEINTERFACE). Получив deivce id с помощью SetupDiGetDeviceInstanceId получаем строку, которая почти полностью будет присутствовать в данных параметра \DosDevice\X: в HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices .
...
PROFIT!
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог