Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.128.199.210] |
|
Сообщ.
#1
,
|
|
|
Всем привет!
Мне нужно получить имя (прошитый в устройстве идентификатор) физического диска. Не метку логического диска, не GUID, не "\Device\HarddiskVolume1" или т.п. А то, что выдаёт wmic diskdrive list brief в столбцах Caption и Model, например: Generic STORAGE DEVICE USB Device JetFlash Transcend 16GB USB Device ST2000DM006-2DM164 ST31000528AS ST2000DM001-1CH164 PLEXTOR PX-128M6Pro USB DISK 2.0 USB Device PowerShell и т.п. вещи не интересуют, нужно получить программно. Вроде есть вариант через WMI. Но хочется на чистом WinAPI. p.s. Есть ещё вариант через SMART, но это не прокатит с флешками (только харды) + нужны права админа. |
Сообщ.
#2
,
|
|
|
Может как-то так? или так
|
Сообщ.
#3
,
|
|
|
JoeUser, спасибо
Я, правда, сам тоже нашёл: IOCTL_STORAGE_QUERY_PROPERTY. Запрос StorageDeviceProperty, поле ProductIdOffset. Навороченный какой код (второй). Надо посмотреть, что там. Но там, я вижу, тоже есть этот IOCTL_STORAGE_QUERY_PROPERTY. |
Сообщ.
#4
,
|
|
|
Да, автор второго кода - мастер по жести!
switch (*cP) { case '0': i64Id += 0; break; case '1': i64Id += 1; break; case '2': i64Id += 2; break; case '3': i64Id += 3; break; case '4': i64Id += 4; break; case '5': i64Id += 5; break; case '6': i64Id += 6; break; case '7': i64Id += 7; break; case '8': i64Id += 8; break; case '9': i64Id += 9; break; case 'a': case 'A': i64Id += 10; break; case 'b': case 'B': i64Id += 11; break; case 'c': case 'C': i64Id += 12; break; case 'd': case 'D': i64Id += 13; break; case 'e': case 'E': i64Id += 14; break; case 'f': case 'F': i64Id += 15; break; case 'g': case 'G': i64Id += 16; break; case 'h': case 'H': i64Id += 17; break; case 'i': case 'I': i64Id += 18; break; case 'j': case 'J': i64Id += 19; break; case 'k': case 'K': i64Id += 20; break; case 'l': case 'L': i64Id += 21; break; case 'm': case 'M': i64Id += 22; break; case 'n': case 'N': i64Id += 23; break; case 'o': case 'O': i64Id += 24; break; case 'p': case 'P': i64Id += 25; break; case 'q': case 'Q': i64Id += 26; break; case 'r': case 'R': i64Id += 27; break; case 's': case 'S': i64Id += 28; break; case 't': case 'T': i64Id += 29; break; case 'u': case 'U': i64Id += 30; break; case 'v': case 'V': i64Id += 31; break; case 'w': case 'W': i64Id += 32; break; case 'x': case 'X': i64Id += 33; break; case 'y': case 'Y': i64Id += 34; break; case 'z': case 'Z': i64Id += 35; break; } } |
Сообщ.
#5
,
|
|
|
Цитата JoeUser @ Да, автор второго кода - мастер по жести! Начитаются бородатых анекдотов, а потом код пишут... https://www.anekdot.ru/id/-9934695/ |
Сообщ.
#6
,
|
|
|
Давай я облегчу жизъть
#include <windows.h> #include <iostream> #include <iomanip> #include <vector> #include <string> void getDevInfo(HANDLE hDev) { STORAGE_PROPERTY_QUERY inBuf; std::vector<unsigned char> buf; DWORD retSize; // unused inBuf.PropertyId = StorageDeviceProperty; inBuf.QueryType = PropertyStandardQuery; buf.resize(sizeof(STORAGE_DEVICE_DESCRIPTOR)); STORAGE_DEVICE_DESCRIPTOR *outBuf = reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(&buf.front()); outBuf->Version = sizeof(*outBuf); if (DeviceIoControl(hDev, IOCTL_STORAGE_QUERY_PROPERTY, &inBuf, sizeof(inBuf), outBuf, buf.size(), &retSize, NULL) == FALSE) { std::cerr << "DeviceIoControl (1st) failed. Code error is " << GetLastError() << std::endl; return; } buf.resize(outBuf->Size); outBuf = reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(&buf.front()); if (DeviceIoControl(hDev, IOCTL_STORAGE_QUERY_PROPERTY, &inBuf, sizeof(inBuf), outBuf, buf.size(), &retSize, NULL) == FALSE) { std::cerr << "DeviceIoControl (2nd) failed. Code error is " << GetLastError() << std::endl; return; } if (outBuf->VendorIdOffset != 0) std::cout << "Vendor is " << &buf[outBuf->VendorIdOffset] << '\n'; if (outBuf->ProductIdOffset != 0) std::cout << "Product is " << &buf[outBuf->ProductIdOffset] << '\n'; if (outBuf->ProductRevisionOffset != 0) std::cout << "Revision is " << &buf[outBuf->ProductRevisionOffset] << '\n'; if (outBuf->SerialNumberOffset != 0) std::cout << "S/N is " << &buf[outBuf->SerialNumberOffset] << '\n'; std::cout << "\nRawData is:" << '\n'; for (int i = 0; i < outBuf->RawPropertiesLength; ++i) { unsigned byte = static_cast<unsigned>(outBuf->RawDeviceProperties[i]) & 0xFF; std::cout << '[' << i << "]\t" << std::setfill('0') << " (0x" << std::setw(2) << std::hex << std::uppercase << byte << std::setfill(' ') << ") " << std::setw(3) << std::dec << byte << ' ' << outBuf->RawDeviceProperties[i] << '\n'; } std::cout << std::endl; } int main() { for (int i = 0; ; ++i) { std::string nameDev = "\\\\.\\PhysicalDrive" + std::to_string(i); HANDLE hDev = CreateFile(nameDev.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDev == INVALID_HANDLE_VALUE) break; std::cout << nameDev << " info\n" << std::string(nameDev.length() + 5, '=') << '\n'; getDevInfo(hDev); CloseHandle(hDev); } } Добавлено Но вообще как-то мало инфы. Подозреваю, что сюда ещё SMART можно затесать. |
Сообщ.
#7
,
|
|
|
Цитата Qraizer @ Кстати, номера могут иметь дыры.if (hDev == INVALID_HANDLE_VALUE) break; Т.е. запросто могут быть диски 0, 1, 3, 6, допустим. |
Сообщ.
#8
,
|
|
|
Я знаю, ну так это ж пример использования. Основное в getDevInfo(), ибо в ваших примерах как-то многословно всё. И на Сях, что не добавляет ясности.
Я вот не в курсе, как нормально дыры обходить. Только через SetupAPI получить все железки с нужным классом и переэнумить руками. Где-то был похожий код, но другой, там RSы ищутся. Если найду, приложу, там тоже не всё так гладко. |
Сообщ.
#9
,
|
|
|
Цитата Qraizer @ Да, я тоже через SetupAPI только видел. Сегодня ковырял rufus, там так же. Что такое RS'ы?Только через SetupAPI получить все железки с нужным классом и переэнумить руками. Где-то был похожий код, но другой, там RSы ищутся. Если найду, приложу, там тоже не всё так гладко. Я обычно тупо делаю перебор номеров от 0 до 15. Кстати, какое кол-во дисков может быть максимум? |
Сообщ.
#10
,
|
|
|
Цитата Jin X @ COM-порты. Но там и задача была сложнее: нужно было найти конкретный девайс по его COMномеру:, отыскать его родительное устройство, проверить, что оно конкретная USB-шелезяка и выторкнуть/перевоткнуть. Шелезяку, не COM.Что такое RS'ы? Цитата Jin X @ Теоретически олимпиллиард. Вот тут можно посмотреть на дикую смесь C и Плюсов, но он не даст полной инфы. Впрочем, это зависит от того, какие устройства вообще интересуют. Я обычно тупо делаю перебор номеров от 0 до 15. Кстати, какое кол-во дисков может быть максимум? |
Сообщ.
#11
,
|
|
|
Цитата Qraizer @ Там тоже ж SetupAPI.Вот тут можно посмотреть на дикую смесь C и Плюсов, но он не даст полной инфы. Почему не даст? |
Сообщ.
#12
,
|
|
|
Ну а как быть, например, с floppy или cdrom? Разве они не физические? Но я ж написал:
Цитата Qraizer @ Впрочем, это зависит от того, какие устройства вообще интересуют. |
Сообщ.
#13
,
|
|
|
Цитата Qraizer @ CD вообще перечисляются через \\.\CdRomX.Ну а как быть, например, с floppy или cdrom? А floppy есть в списках \\.\PsysicalDriveX ? |
Сообщ.
#14
,
|
|
|
Флешки должны быть. А их дофига воткнуть можно.
|
Сообщ.
#15
,
|
|
|
Jin X, посмотри тут (запусти), может тебе это даст какую-то полезную инфу перед непосредственным опросом устройств.
|
Сообщ.
#16
,
|
|
|
Цитата JoeUser @ Ух ты! Вот уж не думал. Спасибо! Да, там все "Physical Drives" присутствуют Jin X, посмотри тут (запусти), может тебе это даст какую-то полезную инфу перед непосредственным опросом устройств. |
Сообщ.
#17
,
|
|
|
Цитата Jin X @ Запрос StorageDeviceProperty, поле ProductIdOffset. У меня запрос "IOCTL_STORAGE_QUERY_PROPERTY" возвращает только модель и версию ProductId, а вот чтение смарта через "IOCTL_SMART_RCV_DRIVE_DATA" уже намного больше инфы, и среди прочего в буфере получаю валидный S/N. Правда байты в словах расположены наоборот, но это поправимо - вот логи (диск ST380011A, версия 3.06, серийник 5JV4L976): ;//====== IOCTL_STORAGE_QUERY_PROPERTY ===================================== ;//========================================================================= 00401040 28 00 00 00 A7 00 00 00 00 00 00 00 00 00 00 00 (...§........... 00401050 4C 00 00 00 75 00 00 00 7E 00 00 00 03 00 00 00 L...u...~... ... 00401060 24 00 00 00 00 00 00 00 00 00 00 02 20 00 00 00 $.......... ... 00401070 53 54 33 38 30 30 31 31 41 00 20 20 20 20 20 20 ST380011A. 00401080 20 20 20 20 20 20 20 20 33 2E 30 36 53 54 33 38 3.06ST38 00401090 30 30 31 31 41 00 20 20 20 20 20 20 20 20 20 20 0011A. 004010A0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 004010B0 20 20 20 20 00 33 2E 30 36 00 20 20 20 00 34 61 .3.06. .4a 004010C0 33 35 33 34 35 36 33 39 34 63 33 36 33 37 32 30 353456394c363720 004010D0 32 30 32 30 32 30 32 30 32 30 32 30 32 30 32 30 2020202020202020 004010E0 32 30 32 30 32 30 00 00 00 00 00 00 00 00 00 00 202020.......... 004010F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ;//====== IOCTL_SMART_RCV_DRIVE_DATA ======================================= ;//========================================================================= 00401040 18 00 00 00 D0 01 01 4F C2 A0 EC 00 00 00 00 00 ...Р OВ м..... 00401050 00 00 00 00 00 00 00 00 00 18 00 00 00 00 00 01 ......... ..... 00401060 4F C2 A0 EC 00 00 00 00 00 5A 0C FF 3F 37 C8 10 OВ м.....Z.я?7И 00401070 00 00 00 00 00 3F 00 00 00 00 00 00 00 4A 35 34 .....?.......J54 <---- 5JV4L976 00401080 56 39 4C 36 37 20 20 20 20 20 20 20 20 20 20 20 V9L67 00401090 20 00 00 00 10 04 00 2E 33 36 30 20 20 20 20 54 ... ..360 T 004010A0 53 38 33 30 30 31 31 20 41 20 20 20 20 20 20 20 S830011 A 004010B0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 004010C0 20 20 20 20 20 20 20 10 80 00 00 00 2F 00 00 00 Ђ.../... 004010D0 02 00 02 07 00 FF 3F 10 00 3F 00 10 FC FB 00 10 . .я? .?. ьы. 004010E0 01 B0 F8 50 09 00 00 07 00 03 00 78 00 78 00 F0 °шP... . .x.x.р 004010F0 00 78 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .x.............. 00401100 00 00 00 00 00 00 00 00 00 7E 00 1B 00 6B 34 01 .........~. .k4 00401110 7D 03 40 69 34 01 3C 03 40 3F 04 00 00 00 00 FE } @i4 < @? ....ю 00401120 FE 00 00 4B 40 00 80 00 00 00 00 00 00 00 00 00 ю..K@.Ђ......... 00401130 00 B0 F8 50 09 00 00 00 00 00 00 00 00 00 00 00 .°шP............ 00401140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00401150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00401160 00 00 00 00 00 00 00 00 00 09 00 B0 F8 50 09 B0 ...........°шP.° 00401170 F8 50 09 20 20 02 00 B6 42 00 00 00 8A 06 3C 0A шP. .¶B...Љ <. 00401180 3C FF FF C6 07 00 01 00 08 D0 09 00 04 02 00 30 <яяЖ . . Р.. .0 00401190 00 00 00 00 00 00 00 06 FE 00 00 02 00 00 00 00 ....... ю.. .... 004011A0 00 00 00 00 00 21 00 0B 00 00 00 00 00 00 00 00 .....!. ........ 004011B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 004011C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ |
Сообщ.
#18
,
|
|
|
Цитата core-i7 @ Так, это и нужно.ProductId Цитата core-i7 @ Проблема со SMART'ом в том, что его нет на флешках - раз, нужны права админа - два.а вот чтение смарта через "IOCTL_SMART_RCV_DRIVE_DATA" уже намного больше инфы Вот эта прога что выдаёт у тебя? Скрытый текст #include <windows.h> #include <memory> #include <string> //returns the serial number of the first physical drive in a std::string or an empty std::string in case of failure //based on http://codexpert.ro/blog/2013/10/26/get-physical-drive-serial-number-part-1/ std::string getFirstHddSerialNumber() { //get a handle to the first physical drive HANDLE h = CreateFileW(L"\\\\.\\PhysicalDrive0", 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(h == INVALID_HANDLE_VALUE) return {}; //an std::unique_ptr is used to perform cleanup automatically when returning (i.e. to avoid code duplication) std::unique_ptr<std::remove_pointer<HANDLE>::type, void(*)(HANDLE)> hDevice{h, [](HANDLE handle){CloseHandle(handle);}}; //initialize a STORAGE_PROPERTY_QUERY data structure (to be used as input to DeviceIoControl) STORAGE_PROPERTY_QUERY storagePropertyQuery{}; storagePropertyQuery.PropertyId= StorageDeviceProperty; storagePropertyQuery.QueryType= PropertyStandardQuery; //initialize a STORAGE_DESCRIPTOR_HEADER data structure (to be used as output from DeviceIoControl) STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader{}; //the next call to DeviceIoControl retrieves necessary size (in order to allocate a suitable buffer) //call DeviceIoControl and return an empty std::string on failure DWORD dwBytesReturned= 0; if(!DeviceIoControl(hDevice.get(), IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY), &storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER), &dwBytesReturned, NULL)) return {}; //allocate a suitable buffer const DWORD dwOutBufferSize= storageDescriptorHeader.Size; std::unique_ptr<BYTE[]> pOutBuffer{new BYTE[dwOutBufferSize]{}}; //call DeviceIoControl with the allocated buffer if(!DeviceIoControl(hDevice.get(), IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY), pOutBuffer.get(), dwOutBufferSize, &dwBytesReturned, NULL)) return {}; //read and return the serial number out of the output buffer STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor= reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(pOutBuffer.get()); const DWORD dwSerialNumberOffset= pDeviceDescriptor->SerialNumberOffset; if(dwSerialNumberOffset==0) return {}; const char* serialNumber= reinterpret_cast<const char*>(pOutBuffer.get() + dwSerialNumberOffset); return serialNumber; } #include <iostream> int main() { std::string serialNumber = getFirstHddSerialNumber(); if(serialNumber.empty()) std::cout << "failed to retrieve serial number\n"; else std::cout << "serial number: " << serialNumber << "\n"; return 0; } |
Сообщ.
#19
,
|
|
|
Цитата Jin X @ Вот эта прога что выдаёт у тебя? у меня плюсы не установлены, я на фасм переписывал и в буфере получал логи выше. |