C++ 如何判断一个驱动卷是本地硬盘,还是USB接入的移动硬盘?

yanchangwen7 2010-03-19 11:33:50
电脑机子上本来有C,D,E,F 四个盘,当USB接入一个移动硬盘后会增加 H ,I两个盘,我用GetDriveType()来获取各个盘的类型时,则得到返回值都是DRIVE_FIXED,无法区分这六个盘的类型。有什么办法可以区分H ,I盘属于USB接入的移动硬盘?我查了MSDN很久也无法解决,有人提出系统分区数+驱动卷判断,这个方法看似可行,然而我却不懂获取磁盘的分区表,请高手赐教。
...全文
1509 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
WizardK 2010-03-20
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 vb2010 的回复:]

引用 3 楼 wizardk 的回复:
在磁盘盘符发生变化是响应WM_DEVICECHANGE消息,记录下变化磁盘,即为DRIVE_REMOVABLE

或http://topic.csdn.net/t/20040706/12/3149643.html

这个好些 不过如果移动硬盘一直接在电脑上面不久不好办了吗?
[/Quote]

不是还有个或嘛,呵呵
密斯刘 2010-03-20
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 wizardk 的回复:]
在磁盘盘符发生变化是响应WM_DEVICECHANGE消息,记录下变化磁盘,即为DRIVE_REMOVABLE

或http://topic.csdn.net/t/20040706/12/3149643.html
[/Quote]
这个好些 不过如果移动硬盘一直接在电脑上面不久不好办了吗?
Tr1j5n 2010-03-20
  • 打赏
  • 举报
回复
移动硬盘普通方法是不好判断的。LS的说的只针对U盘
  • 打赏
  • 举报
回复
mark
ArcRain 2010-03-20
  • 打赏
  • 举报
回复
还是IoControl,不过可以通过判断总线类型来区分,主要功能函数:

BOOL GetDisksProperty(HANDLE hDevice, PSTORAGE_DEVICE_DESCRIPTOR pDevDesc)
{
STORAGE_PROPERTY_QUERY Query;// input param for query
DWORD dwOutBytes;// IOCTL output length
BOOL bResult;// IOCTL return val // specify the query type
Query.PropertyId = StorageDeviceProperty;
Query.QueryType = PropertyStandardQuery; // Query using IOCTL_STORAGE_QUERY_PROPERTY
bResult = ::DeviceIoControl(hDevice,// device handle
IOCTL_STORAGE_QUERY_PROPERTY,// info of device property
&Query, sizeof(STORAGE_PROPERTY_QUERY),//input data buffer
pDevDesc, pDevDesc->Size, // output data buffer
&dwOutBytes, //out length
NULL);
return bResult;
}
//调用过程:
....
hDevice = CreateFile(szBuf, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL); //打开设备,磁盘分区的路径
pDevDesc = (PSTORAGE_DEVICE_DESCRIPTOR)new BYTE[sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1];
pDevDesc->Size = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1;
if(GetDisksProperty(hDevice, pDevDesc))
{
if(pDevDesc->BusType == BusTypeUsb) //总线类型是USB
WizardK 2010-03-20
  • 打赏
  • 举报
回复
在磁盘盘符发生变化是响应WM_DEVICECHANGE消息,记录下变化磁盘,即为DRIVE_REMOVABLE

http://topic.csdn.net/t/20040706/12/3149643.html
yanchangwen7 2010-03-20
  • 打赏
  • 举报
回复
结贴吧,感谢大家的意见。
我跟我搭档想出了新的一个解决方法,有点取巧了,虽然不完美,但也可以解决当下的问题。
我大概说一下思路
使用FindFirstVolume ()和FindNextVolume()来获得逻辑卷驱动器名
逻辑卷驱动器名的格式是:\\?\Volume{e9233817-90be-11d6-88b7-00e04c3de005}
正是这个格式,我们发现了其中的规律,假如C盘的逻辑卷驱动器名是上面那个,则
D盘的逻辑卷驱动器名为:\\?\Volume{e9233818-90be-11d6-88b7-00e04c3de005}
E盘的逻辑卷驱动器名为:\\?\Volume{e9233819-90be-11d6-88b7-00e04c3de005}
……
也就是说在同一个磁盘下,逻辑卷驱动器名是递增的,而不同的磁盘下的逻辑驱动器名相差很多。
利用这个规律,我们就可以给磁盘归类了。





mszjk 2010-03-20
  • 打赏
  • 举报
回复
2楼钻石!
ArcRain 2010-03-20
  • 打赏
  • 举报
回复
另外一种方法就是用一系列SetupdiXXXX函数来枚举USB设备,通过一系列CM_XXX函数及设备实例树,利用设备实例的句柄来找设备的属性。就USB设备来说,其父节点或者根节点,一定会有USB的属性。
fly4free 2010-03-20
  • 打赏
  • 举报
回复
这个代码, 好像挺啰嗦的
在插入的时候就立刻调用该函数进行判断,会否有资源管理器或者别的什么窗口卡死一段时间的情况呢?
yanchangwen7 2010-03-20
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 sullensun 的回复:]

mark 来学习来了
[/Quote]

mark不行,mark只能判断U盘,要知道系统是把移动硬盘的类型当做DRIVE_FIXED来处理的,也就是说把移动硬盘和本地磁盘归为同一种类型。期待更好的方法解决这个问题……
SullenSun 2010-03-20
  • 打赏
  • 举报
回复
mark 来学习来了
z4none 2010-03-20
  • 打赏
  • 举报
回复
mark 学习了
LookSail 2010-03-20
  • 打赏
  • 举报
回复
没错,用Bus总线来判断,那个什么Removeable是没用的,移动硬盘分区稍微大一点,全部都是FIX
yanchangwen7 2010-03-20
  • 打赏
  • 举报
回复
1楼写得太好了,看一楼的代码让我受益匪浅,4楼的方法我也考虑过,只是两者都用到IoControl,这个函数正如1楼所说,需要管理员权限才能运行。这样做出来的软件就打了折扣了,或者说不合格。期待更好的方法出来……
oyljerry 2010-03-19
  • 打赏
  • 举报
回复
DeviceIoControl只能在管理员下才能运行
BOOL CCopyHook::IsIDE(CString DriveName)
{
////本段程序的前提是DriveName是已经过GetDriveType的判断是本地磁盘,否则报错,作用是判断是否是真正的本地磁盘////////
//////////////////111111111111111111111111111111111111111/////////////////////////////////////////////
///////////////////////获得某分区(目的地址)的信息/////////////////////////
HANDLE hDeviceDest = NULL;
DWORD nBytesRead = 0;//预设为0,当缓冲区的长度不够时,该值为所需的缓冲区的长度
DWORD nBufferSize = sizeof(PARTITION_INFORMATION);
PPARTITION_INFORMATION lpPartInfo = (PPARTITION_INFORMATION)malloc(nBufferSize);
if(lpPartInfo == NULL)
{
//MessageBox("缓冲区分配出错!","失败!",MB_OK);
return FALSE;
}
memset(lpPartInfo, 0, nBufferSize);//将缓冲区lpPartInfo的内容设为nDiskBufferSize个NULL
//CString DriveName="J:";//为判断提供接口
DriveName="\\\\.\\"+DriveName;

hDeviceDest = CreateFile(LPCTSTR(DriveName),//注意一定要是\\\\.\\的形式,CreateFile的要求 ""\\??\\Volume{e9233817-90be-11d6-88b7-00e04c3de005}
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
0, NULL);

if(hDeviceDest == NULL)
{
//MessageBox("CreateFile出错!","失败!",MB_OK);
return FALSE;
}
/////////////获得该分区信息/////////////////////////
BOOL ret1=DeviceIoControl(
hDeviceDest,
IOCTL_DISK_GET_PARTITION_INFO,
NULL,
0,
(LPVOID) lpPartInfo,
(DWORD) nBufferSize,
(LPDWORD) &nBytesRead,
NULL//指向一个异步的结构体
);

if (!ret1)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
//MessageBox( (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
LocalFree( lpMsgBuf );
//MessageBox("DeviceIoControl出错!","失败!",MB_OK);
return FALSE;
}
///////////////////导出该分区信息///////////////////////////////////
LARGE_INTEGER StartingOffset=lpPartInfo->StartingOffset;
LONGLONG QuadPart=StartingOffset.QuadPart;//取上面的值之一情形,支持64位整型
LARGE_INTEGER PartitionLength=lpPartInfo->PartitionLength;
LONGLONG QuadPart1=PartitionLength.QuadPart;//取上面的值之一情形,支持64位整型
DWORD HiddenSectors=lpPartInfo->HiddenSectors;
DWORD PartitionNumber=lpPartInfo->PartitionNumber;
BYTE PartitionType=lpPartInfo->PartitionType;
BOOLEAN BootIndicator=lpPartInfo->BootIndicator;
BOOLEAN RecognizedPartition=lpPartInfo->RecognizedPartition;
BOOLEAN RewritePartition=lpPartInfo->RewritePartition;

free(lpPartInfo);
CloseHandle(hDeviceDest);

/////////////////////查询注册表中COUNT(Disk)的值//////////////////////////////////////
UINT IDESeqNum;//IDE的序号
BOOL FindIDE=FALSE;

HKEY hKEY;
RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Services\\Disk\\Enum", 0, KEY_READ, &hKEY);
///////////接收DWORD型/////////////

DWORD Type;//仅仅用于接收数据类型
DWORD dwValue;
DWORD dwBufLen = sizeof(DWORD);
long ret2=::RegQueryValueEx(hKEY, _T("Count"), NULL, &Type, (BYTE*)&dwValue, &dwBufLen);
if(ret2!=ERROR_SUCCESS)
{
//MessageBox("找不到磁盘的个数","提示",MB_OK);
return FALSE;//失败
}
for (UINT k=0; k<dwValue; k++)
{
///////////接收字符型/////////////
char str[256];
DWORD sl = 256;
CString nDisk;
nDisk.Format("%u",k);
RegQueryValueEx(hKEY, nDisk, NULL, NULL, (LPBYTE)str, &sl); //注意第三项必须设为NULL,否则接收到的字符数据出错
CString temp=str;
if (temp.Left(3)=="IDE")
{
IDESeqNum=k;//IDE的序号
FindIDE=TRUE;
}

}
if (!FindIDE)
return FALSE; // IDESeqNum=0;
RegCloseKey(hKEY);

CString temp;
temp.Format("%u",IDESeqNum);
temp="\\\\.\\PHYSICALDRIVE"+temp;//为下一步检测作准备
//////////////////22222222222222222222222222222222222222222 /////////////////////////////////////////


HANDLE hDevice = NULL;
DWORD nDiskBytesRead = 0;//预设为0,当缓冲区的长度不够时,该值为所需的缓冲区的长度
DWORD nDiskBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) + sizeof(PARTITION_INFORMATION)*104;//26*4
PDRIVE_LAYOUT_INFORMATION lpDiskPartInfo = (PDRIVE_LAYOUT_INFORMATION)malloc(nDiskBufferSize);

if(lpDiskPartInfo == NULL)
{
//MessageBox("缓冲区分配出错!","失败!",MB_OK);
return FALSE;
}
memset(lpDiskPartInfo, 0, nDiskBufferSize);//将缓冲区lpDiskPartInfo的内容设为nDiskBufferSize个NULL

//////////////////////获得所有分区的信息///////////////////////////////////////
hDevice = CreateFile(LPCTSTR(temp),//注意一定要是\\\\.\\的形式,CreateFile的要求 ""\\??\\Volume{e9233817-90be-11d6-88b7-00e04c3de005}
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
0, NULL);

if(hDevice == NULL)
{
//MessageBox("CreateFile出错!","失败!",MB_OK);
return FALSE;
}

/////////////获得某磁盘上的所有分区信息/////////////////////////
BOOL ret=DeviceIoControl(
hDevice,
IOCTL_DISK_GET_DRIVE_LAYOUT,
NULL,
0,
(LPVOID) lpDiskPartInfo,
(DWORD) nDiskBufferSize,
(LPDWORD) &nDiskBytesRead,
NULL
);

if (!ret)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
//MessageBox( (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
LocalFree( lpMsgBuf );
//MessageBox("DeviceIoControl出错!","失败!",MB_OK);
return FALSE;
}

//////////////////////////////导出分区信息///////////////////////////////////////
DWORD PartitionCount=lpDiskPartInfo->PartitionCount; //永远是实际的分区数的4倍,不能用的分区将会显示类型PARTITION_ENTRY_UNUSED,即分区类型为0
///////////////////依次获取导出某分区信息,并与目的驱动器进行比较///////////////////////////////////
for (UINT i=0; i<PartitionCount; i=i+4)//+4是因为只有下标为4的整数倍的值才是正确的引用
{
PARTITION_INFORMATION DiskPartInfo=lpDiskPartInfo->PartitionEntry[i];//0为C:,4为D:,8为e:,12为F

LARGE_INTEGER DiskStartingOffset = DiskPartInfo.StartingOffset;
LONGLONG DiskQuadPart = DiskStartingOffset.QuadPart; //取上面的值之一情形,支持64位整型
LARGE_INTEGER DiskPartitionLength = DiskPartInfo.PartitionLength;
LONGLONG DiskQuadPart1 = DiskPartitionLength.QuadPart; //取上面的值之一情形,支持64位整型
DWORD DiskHiddenSectors = DiskPartInfo.HiddenSectors;
DWORD DiskPartitionNumber = DiskPartInfo.PartitionNumber;
BYTE DiskPartitionType = DiskPartInfo.PartitionType;
BOOLEAN DiskBootIndicator = DiskPartInfo.BootIndicator;
BOOLEAN DiskRecognizedPartition = DiskPartInfo.RecognizedPartition;
BOOLEAN DiskRewritePartition = DiskPartInfo.RewritePartition;
if ((DiskQuadPart==QuadPart) && (DiskQuadPart1==QuadPart1)
&& (DiskHiddenSectors==HiddenSectors) && (DiskPartitionNumber==PartitionNumber)
&& (DiskPartitionType==PartitionType ) && (DiskBootIndicator==BootIndicator)
&& (DiskRecognizedPartition==RecognizedPartition) && (DiskRewritePartition==RewritePartition))
{
free(lpDiskPartInfo);
CloseHandle(hDevice);
::MessageBox(NULL,"属于本地驱动器!","提示",MB_OK);
return TRUE;
}
}
free(lpDiskPartInfo);
CloseHandle(hDevice);
::MessageBox(NULL,"非本地驱动器!","提示",MB_OK);//改为return IDCANCEL;
return FALSE;
}

2,641

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 硬件/系统
社区管理员
  • 硬件/系统社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧