Стоит задача — получить для всех флешек информацию о них (серийный номер, производитель и т.д.) и ее букву диска. Для получения информации я воспользовался стандартным примером из DDK — usbview, но получение буквы диска оказалось сложнее чем я думал. В usbview структура PUSB_NODE_CONNECTION_INFORMATION является единственным идентификатором usb устройства, нет никаких имен и нет хэнделов.
Из полей этой структуры я могу получить имя устройсва usb следующего вида: "USB#Vid_14e4&Pid_1000#5&29899c85&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}", которое можно передать в CreateFile и получить хэндл устройства. Но как по этому хэндлу узнать букву диска я к сожалению не нашел
Здравствуйте, Serg1983, Вы писали:
S>Стоит задача — получить для всех флешек информацию о них (серийный номер, производитель и т.д.) и ее букву диска. Для получения информации я воспользовался стандартным примером из DDK — usbview, но получение буквы диска оказалось сложнее чем я думал. В usbview структура PUSB_NODE_CONNECTION_INFORMATION является единственным идентификатором usb устройства, нет никаких имен и нет хэнделов. S>Из полей этой структуры я могу получить имя устройсва usb следующего вида: "USB#Vid_14e4&Pid_1000#5&29899c85&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}", которое можно передать в CreateFile и получить хэндл устройства. Но как по этому хэндлу узнать букву диска я к сожалению не нашел
S>Буду рад любой информации
На счет любой информации:
Попробуй вызвать GetLogicalDrives для получения всех дисков и в цикле проверять GetDriveType для каждого. Флэшки — DRIVE_REMOVABLE.
Правда как ты это будешь контачить с данными из DDK я не знаю
Здравствуйте, Serg1983, Вы писали:
S>Из полей этой структуры я могу получить имя устройсва usb следующего вида: "USB#Vid_14e4&Pid_1000#5&29899c85&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}", которое можно передать в CreateFile и получить хэндл устройства. Но как по этому хэндлу узнать букву диска я к сожалению не нашел
Думаю, что в MSD: раздел
Naming a Volume
и возможно функция ( возможно потому как я сам не вникал):
Здравствуйте, Nocturne, Вы писали:
N>На счет любой информации: N>Попробуй вызвать GetLogicalDrives для получения всех дисков и в цикле проверять GetDriveType для каждого. Флэшки — DRIVE_REMOVABLE. N>Правда как ты это будешь контачить с данными из DDK я не знаю
Спасибо за ответ.
Я пытался пойти с обратной стороны. Т.е. по букве диска получить что-нибудь, идентифицирующее флешку. Максимум что я получил это номер PhysicalDrive.
S>К сожалению, GetVolumeInformation для флешки не выдает ничего
Ок, если я не ошибся в корне и Флышка и есть Volume
ТО может помочь:
Enumerating Mount Points
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define BUFSIZE MAX_PATH
#define FILESYSNAMEBUFSIZE MAX_PATH
// Process each mount point found here. This makes maintenance easier
// than doing it in line. The result indicates whether there is
// another mount point to be scanned.
// This routine prints out the path to a mount point and its target.
BOOL ProcessVolumeMountPoint (HANDLE hPt,
char *PtBuf, DWORD dwPtBufSize,
char *Buf, DWORD dwBufSize)
{
BOOL bFlag; // Boolean result char Path[BUFSIZE]; // construct a complete path here
HANDLE hFf, hFile; // file search, file handles
WIN32_FIND_DATA fd; // find data for a file search
DWORD BytesReturned; // from DeviceIoControl callchar Target[BUFSIZE]; // target of mount at mount point
printf ("\tVolume mount point found is \"%s\"\n", PtBuf);
// Detect the volume mounted there. Unfortunately, there is no
// simple way to map a unique volume name to a DOS drive letter.
// One way to do that is to build an associative array, which we
// will "leave as an exercise for the student."
// Build a unique path to the mount point
strcpy (Path, Buf);
strcat (Path, PtBuf);
bFlag = GetVolumeNameForVolumeMountPoint(
Path, // input volume mount point or directory
Target, // output volume name buffer
BUFSIZE // size of volume name buffer
);
if (!bFlag)
printf ("\tAttempt to get volume name for %s failed.\n", Path);
else
printf ("\tTarget of the volume mount point is %s.\n", Target);
// Now, either get the next mount point and return it, or return a
// value indicating there are no more mount points.
bFlag = FindNextVolumeMountPoint(
hPt, // handle to scan
PtBuf, // pointer to output string
dwPtBufSize // size of output buffer
);
return (bFlag);
}
// Process each volume. This makes maintenance easier than doing it
// in line. The Boolean result indicates whether there is another
// volume to be scanned.
BOOL ProcessVolume (HANDLE hVol, char *Buf, int iBufSize)
{
BOOL bFlag; // generic results flag for return
HANDLE hPt; // handle for mount point scanchar PtBuf[BUFSIZE]; // string buffer for mount points
DWORD dwSysFlags; // flags that describe the file systemchar FileSysNameBuf[FILESYSNAMEBUFSIZE];
printf ("Volume found is \"%s\".\n", Buf);
// Is this volume NTFS?
GetVolumeInformation( Buf, NULL, 0, NULL, NULL,
&dwSysFlags, FileSysNameBuf,
FILESYSNAMEBUFSIZE);
// Detect support for reparse points, and therefore for volume
// mount points, which are implemented using reparse points.if (! (dwSysFlags & FILE_SUPPORTS_REPARSE_POINTS))
{
printf ("\tThis file system does not support volume mount points.\n");
}
else
{
// Start processing mount points on this volume.
hPt = FindFirstVolumeMountPoint(
Buf, // root path of volume to be scanned
PtBuf, // pointer to output string
BUFSIZE // size of output buffer
);
if (hPt == INVALID_HANDLE_VALUE)
{
printf ("\tNo volume mount points found!\n");
}
else
{
// Process the volume mount point.
bFlag = ProcessVolumeMountPoint (hPt, PtBuf, BUFSIZE, Buf, BUFSIZE);
// Do while we have volume mount points to process.while (bFlag)
bFlag = ProcessVolumeMountPoint (hPt, PtBuf, BUFSIZE, Buf, BUFSIZE);
FindVolumeMountPointClose(hPt);
}
}
// Stop processing mount points on this volume.
bFlag = FindNextVolume(
hVol, // handle to scan being conducted
Buf, // pointer to output
iBufSize // size of output buffer
);
return (bFlag);
}
int main(void)
{
char buf[BUFSIZE]; // buffer for unique volume identifiers
HANDLE hVol; // handle for the volume scan
BOOL bFlag; // generic results flag
// Open a scan for volumes.
hVol = FindFirstVolume (buf, BUFSIZE );
if (hVol == INVALID_HANDLE_VALUE)
{
printf ("No volumes found!\n");
return (-1);
}
// We have a volume; process it.
bFlag = ProcessVolume (hVol, buf, BUFSIZE);
// Do while we have volumes to process.while (bFlag)
{
bFlag = ProcessVolume (hVol, buf, BUFSIZE);
}
// Close out the volume scan.
bFlag = FindVolumeClose(
hVol // handle to be closed
);
return (bFlag);
}
S>Из полей этой структуры я могу получить имя устройсва usb следующего вида: "USB#Vid_14e4&Pid_1000#5&29899c85&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}", которое можно передать в CreateFile и получить хэндл устройства. Но как по этому хэндлу узнать букву диска я к сожалению не нашел
Не слишком умная идея, но
Попробовать GetFileInformationByHandle. Вопрос — вернет он все что нужно, или нет. Там написано
Depending on the underlying network components of the operating system and the type of server connected to, the GetFileInformationByHandle function may fail, return partial information, or full information for the given file.
А хотелось бы от нее dwVolumeSerialNumber . После этого GetVolumeInformation
для всех подозрительных дисков и найти нужный.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Попробовать GetFileInformationByHandle. Вопрос — вернет он все что нужно, или нет. Там написано
PD>Depending on the underlying network components of the operating system and the type of server connected to, the GetFileInformationByHandle function may fail, return partial information, or full information for the given file.
PD>А хотелось бы от нее dwVolumeSerialNumber . После этого GetVolumeInformation PD> для всех подозрительных дисков и найти нужный.
Для имен файлов на диске (например "c:\\boot.ini") она возвращает правильный серийный номер. Но если передать "USB#Vid_14e4&Pid_1000#5&29899c85&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}" результат плачевный . GetLastError() показывает ошибку с номером 1
Здравствуйте, Serg1983, Вы писали:
S>Стоит задача — получить для всех флешек информацию о них (серийный номер, производитель и т.д.) и ее букву диска. Для получения информации я воспользовался стандартным примером из DDK — usbview, но получение буквы диска оказалось сложнее чем я думал. В usbview структура PUSB_NODE_CONNECTION_INFORMATION является единственным идентификатором usb устройства, нет никаких имен и нет хэнделов. S>Из полей этой структуры я могу получить имя устройсва usb следующего вида: "USB#Vid_14e4&Pid_1000#5&29899c85&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}", которое можно передать в CreateFile и получить хэндл устройства. Но как по этому хэндлу узнать букву диска я к сожалению не нашел
S>Буду рад любой информации
Попробуй использовать IShellFolder и его метод GetAttributesOf().
Сейчас проверил на своём тестовом приложении
флаг SFGAO_REMOVABLE выдал для A: и флешки G:
Под XP этот флаг OS установила и для CD/DVD накопителей — это может быть
проблемой
Здравствуйте, Serg1983, Вы писали:
S>Стоит задача — получить для всех флешек информацию о них (серийный номер, производитель и т.д.) и ее букву диска. Для получения информации я воспользовался стандартным примером из DDK — usbview, но получение буквы диска оказалось сложнее чем я думал. В usbview структура PUSB_NODE_CONNECTION_INFORMATION является единственным идентификатором usb устройства, нет никаких имен и нет хэнделов. S>Из полей этой структуры я могу получить имя устройсва usb следующего вида: "USB#Vid_14e4&Pid_1000#5&29899c85&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}", которое можно передать в CreateFile и получить хэндл устройства. Но как по этому хэндлу узнать букву диска я к сожалению не нашел
S>Буду рад любой информации
Вот готовый класс, работает пока без нареканий. Основная идея, как уже подсказывали — использование volume, только все немного сложнее CSimpleMap & CSimpleArray — контейнеры из ATL, но если что переделывается под STL на раз
#include <cfgmgr32.h>
#include <SetupAPI.h>
#pragma comment(lib,"Setupapi.lib")
#pragma once
class UsbDrives
{
CSimpleMap<CString, TCHAR> m_map;
CSimpleArray<TCHAR> m_drives;
public:
UsbDrives()
{
refresh();
}
int count() { return m_drives.GetSize(); }
TCHAR drive(int index )
{
if( m_drives.GetSize() > index )
return m_drives[index];
return NULL;
}
bool check(TCHAR ch)
{
return -1 != m_drives.Find(ch);
}
void refresh()
{
m_map.RemoveAll();
m_drives.RemoveAll();
if( getAllRemovable() )
{
populate();
}
}
private:
const static int bufferSize = 256;
bool getAllRemovable()
{
TCHAR drive[4] = _T("A:\\");
TCHAR volume[bufferSize];
DWORD mask = ::GetLogicalDrives();
if( !mask )
return false;
else
{
for( int i=0; i<26; i++ )
{
if( mask & 1)
{
drive[0] = 'A' + i;
if( ::GetDriveType(drive) == DRIVE_REMOVABLE )
{
if( ::GetVolumeNameForVolumeMountPoint(drive, volume, bufferSize) )
{
m_map.Add(volume,drive[0]);
}
}
}
mask >>= 1;
}
}
return m_map.GetSize() > 0;
}
void populate()
{
GUID guid = GUID_DEVINTERFACE_VOLUME;
// hDevInfo = SetupDiGetClassDevs(NULL,
// _T("USBSTOR"), // Enumerator
// 0,
// DIGCF_PRESENT | DIGCF_ALLCLASSES );
HDEVINFO info = ::SetupDiGetClassDevs(&guid,NULL,NULL,
DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if( INVALID_HANDLE_VALUE != info )
{
SP_DEVICE_INTERFACE_DATA ifaceData;
SP_DEVINFO_DATA data;
BYTE buffer[bufferSize];
TCHAR buf[bufferSize];
TCHAR volume[bufferSize];
for( int i=0; ; i++ )
{
ZeroMemory(&ifaceData,sizeof(ifaceData));
ifaceData.cbSize = sizeof(ifaceData);
ZeroMemory(&data,sizeof(data));
data.cbSize = sizeof(data);
if( !::SetupDiEnumDeviceInterfaces(info,NULL,&guid,i,&ifaceData) )
break;
PSP_DEVICE_INTERFACE_DETAIL_DATA detail = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(buffer);
detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
DWORD size;
SetupDiGetDeviceInterfaceDetail(info,&ifaceData,detail,bufferSize,&size,&data);
DEVINST parent;
// Get the device instance of parent. This points to USBSTOR.
CM_Get_Parent(&parent,data.DevInst, 0);
// Get the device instance of grand parent. This points to USB root.
CM_Get_Parent(&parent,parent, 0);
// Get the device ID of the USB root.
CM_Get_Device_ID(parent, buf, bufferSize,0);
if( buf && buf[0] )
{
int len = lstrlen(detail->DevicePath);
detail->DevicePath[len] = _T('\\');
detail->DevicePath[len+1] = 0;
CString tmp = detail->DevicePath;
if( 0 == tmp.Find(_T("\\\\?\\storage#removablemedia#")) )
{
if( ::GetVolumeNameForVolumeMountPoint(detail->DevicePath, volume, bufferSize) )
{
int idx = m_map.FindKey(volume);
if( -1 != idx )
{
TCHAR drive = m_map.GetValueAt(idx);
if( -1 == m_drives.Find(drive) )
m_drives.Add(drive);
}
}
}
}
}
}
}
};
Здравствуйте, Conr, Вы писали:
C>Вот готовый класс, работает пока без нареканий. Основная идея, как уже подсказывали — использование volume, только все немного сложнее
А есть возможность найти не только USB как диски, но и "подключенные как папки"?
Doc>А есть возможность найти не только USB как диски, но и "подключенные как папки"?
— Перебираешь все тома в системе ( FindFirstVolume, FindNextVolume )
— Для каждого тома перебираешь его MountPoints ( FindFirstVolumeMountPoint, FindNextVolumeMountPoint )
— Для каждого MountPoint вызываешь GetVolumeNameForVolumeMountPoint
— Сравниваешь полученное имя с именем тома, для которого нужно найти все MountPoint "подключенные как папки".
Здравствуйте, MShura, Вы писали:
MS>- Перебираешь все тома в системе ( FindFirstVolume, FindNextVolume ) MS>- Для каждого тома перебираешь его MountPoints ( FindFirstVolumeMountPoint, FindNextVolumeMountPoint ) MS>- Для каждого MountPoint вызываешь GetVolumeNameForVolumeMountPoint MS>- Сравниваешь полученное имя с именем тома, для которого нужно найти все MountPoint "подключенные как папки".
Пошел другоим путем
— перебираем тома
— для каждого тома GetVolumePathNamesForVolumeName что бы узнать путь
— для пути GetDriveType что бы узнать является ли том DRIVE_REMOVABLE
— проверить все выбранные данные тома как в populate класса выше.
Минус — XP и выше. Может у GetVolumePathNamesForVolumeName есть аналоги под Win2k и ниже?