(50分求助)通过API函数识别U盘和移动硬盘的盘符问题(在线等)

aaa_zzz_000 2009-05-03 11:23:32
大家好啊,向大家请教个问题,如何识别移动硬盘的盘符;
下面代码主要功能是:每有移动存储设备插入电脑,接受到一个消息,
通过API函数禁用移动存储设备;移动硬盘一直无法识别。。。


#include <Dbt.h>
#include <Winioctl.h>

//查找可移动磁盘
CString CUSBMngDlg::FindFdisk()
{
CString strdir="";
for(char cc='A';cc<='Z';cc++)
{
strdir.Format("%c:",cc);
if(GetDriveType((LPCTSTR)strdir)==DRIVE_REMOVABLE) //只能识别U盘,无法识别移动硬盘
//if(GetDriveType((LPCTSTR)strdir)==DRIVE_FIXED)
return strdir;
}
return strdir="";
}

//每当有优盘插入时,接收一次系统发给的消息
LRESULT CUSBMngDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_DEVICECHANGE)
{
switch(wParam)
{
case DBT_DEVICEARRIVAL: //设备插入消息
{
HANDLE hDevice;
DWORD dwOutBytes;
bool bResult;
CString logicalDisk;

m_NewFdisk = FindFdisk();

//if(m_NewFdisk != m_OldFdisk && m_NewFdisk!= "")
//if(m_NewFdisk !=“”)
if (m_NewFdisk !="")
{
logicalDisk = "\\\\.\\"+m_NewFdisk;
hDevice = CreateFile(
logicalDisk, //要打开的驱动名称
GENERIC_READ|GENERIC_WRITE, //访问方式
FILE_SHARE_READ|FILE_SHARE_WRITE, //共享方式
NULL, //安全描述符指针
OPEN_EXISTING, //创建方式
0, //文件属性及标志
NULL //模板文件的句柄
);

bResult = DeviceIoControl(hDevice,FSCTL_LOCK_VOLUME,NULL,0,NULL,0,&dwOutBytes,(LPOVERLAPPED)NULL);
}

if(m_NewFdisk!="")
{
m_OldFdisk=m_NewFdisk;
}
else
{
m_OldFdisk="";
}
}
//break;
}
}

return CDialog::WindowProc(message, wParam, lParam);
}
...全文
2512 42 打赏 收藏 转发到动态 举报
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2012-03-01
  • 打赏
  • 举报
回复
我对这方面 没有深入研究 但是不论是U盘还是移动硬盘 插入的时候 系统都会增加新的分区 可以通过判断分区 来判断移动设备的插入
Fypher 2011-05-05
  • 打赏
  • 举报
回复
http://hi.baidu.com/nmn714/blog/item/cf193959d8c7393c2934f051.html
fly4free 2010-09-01
  • 打赏
  • 举报
回复
晕了,我当初摸索的时候怎么没有发现这个帖子呢?

那可是在去年10月份啊……
jiereliyi 2010-09-01
  • 打赏
  • 举报
回复
怎么看不懂啊
Caber 2010-05-07
  • 打赏
  • 举报
回复
ddddddddddddddddddddddddddddddddddddd
ringphone 2009-07-10
  • 打赏
  • 举报
回复
mark
jscn123789abc 2009-06-03
  • 打赏
  • 举报
回复
CreateFile在管理员权限下可以使用,
但是在普通用户权限下不可以使用。。。
jscn123789abc 2009-06-03
  • 打赏
  • 举报
回复
ding...
aaa_zzz_000 2009-05-20
  • 打赏
  • 举报
回复
GetLogicalDrives()
  该函数功能是返回一个代表当前变量磁盘驱动器的位掩码;
  该函数原型为:DWORD GetLogicalDrives(VOID);
  该函数如果调用成功,返回值为一个代表当前变量磁盘驱动器的位屏蔽掩码,位的位置0为驱动器A,1为驱动器B,2为驱动器C等。如果函数调用失败,返回值为0。

  举例:如果某台电脑上驱动器为A、C、D、E,则函数调用成功后的返回值是00011101,其中最低位代表驱动器A,由A存在所以该位掩码为1,而由于B不存在,所以倒数第二位掩码为0。
aaa_zzz_000 2009-05-20
  • 打赏
  • 举报
回复
[b]发表于:2009-05-03 13:34:293楼 得分:0
GetDriveType是针对逻辑盘符的。依靠我的记忆,DBT_DEVICEARRIVAL也是对应逻辑盘符的,有几个盘符就有几次消息。
GetDriveType(strdir)的参数strdir请用“X:\\”的形式,所以逻辑盘符都能得到属性,与是否移动硬盘没有关系

另外给你个建议用GetLogicalDrives可以带到当前的所有逻辑盘符,不需要用for(char cc='A';cc <='Z';cc++) 全部循环
[/b]



使用For循环,只能获取移动硬盘的第一个盘符,两次接收的消息,都锁第一个盘符。。。。
如何使用GetDriveType,获取移动硬盘的多个盘符?谢谢。。。
aaa_zzz_000 2009-05-20
  • 打赏
  • 举报
回复

加上8楼朋友提供的判断是否本地硬盘的代码,
现在可以锁住移动硬盘的第一个盘符,第二个盘符锁不住。。。。


//获取移动磁盘的盘符
CString CusbmngDlg::FindFdisk()
{
CString strdir;
CString ret_mobiledir;
bool is_ide = true;

for(char cc='A';cc<='Z';cc++)
{
strdir.Format(L"%c:",cc);

if(GetDriveType((LPCTSTR)strdir)==DRIVE_REMOVABLE) //获取U盘的盘符
{
return strdir;
}

else if(GetDriveType((LPCTSTR)strdir)==DRIVE_FIXED) //获取移动硬盘的盘符
{
//判断该盘符是否为USB盘符
is_ide = IsIDE(strdir);


if (is_ide == false)
{
return strdir;
}
}
}

return strdir ="";
}



//回调函数的实现
LRESULT CusbmngDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_DEVICECHANGE)
{
switch(wParam)
{
case DBT_DEVICEARRIVAL: //判断是否有设备插入的消息
{
HANDLE hDevice;
DWORD dwOutBytes;
bool bResult;
bool lock_flag = false;
CString logicalDisk; //有设备插入,则跳转到该行

//查注册表
HKEY hkey;
char sz[256];
DWORD dwtype,sl = 256;

for(int i=1;i<8;i++)
{
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\Services\\Disk\\Enum",\
NULL, KEY_ALL_ACCESS, &hkey)==ERROR_SUCCESS)
{
CString id;
id.Format(L"%d",i);

if(RegQueryValueEx(hkey,id,NULL,&dwtype,(LPBYTE)sz,&sl)==ERROR_SUCCESS)
{
LPCTSTR str = (LPCTSTR)sz;
m_select.AddString(str);
}
}
}
RegCloseKey(hkey);

if(m_select.GetCount()==0)
{
lock_flag = false;
SetDlgItemText(IDC_EDIT_DRIVERNAME,L"没有发现移动设备....");

}

if(m_select.GetCount()>0)
{
lock_flag = true;
SetDlgItemText(IDC_EDIT_DRIVERNAME,L"发现移动设备....");
}

if (lock_flag == true)
{
m_NewFdisk = FindFdisk();

if (m_NewFdisk !="")
{
logicalDisk = L"\\\\.\\"+m_NewFdisk;

hDevice = CreateFile(
logicalDisk, //驱动器名称
GENERIC_READ|GENERIC_WRITE, //打开方式(可读可写)
FILE_SHARE_READ|FILE_SHARE_WRITE, //共享方式
NULL, //安全描述符指针
OPEN_EXISTING, //创建方式
0, //文件属性及标志
NULL //模板文件的句柄
);

//锁移动设备卷标
bResult = DeviceIoControl(hDevice,FSCTL_LOCK_VOLUME,NULL,0,NULL,0,&dwOutBytes,(LPOVERLAPPED)NULL);
} //end of if (m_NewFdisk !="")

if(m_NewFdisk!="")
{
m_OldFdisk=m_NewFdisk;
}
else
{
m_OldFdisk="";
}
} //end of if (lock_flag == true)
} // end of case DBT_DEVICEARRIVAL:
//break;
} //end of switch(wParam)
} //end of if(message == WM_DEVICECHANGE)

return CDialog::WindowProc(message, wParam, lParam);
}
jscn123789abc 2009-05-20
  • 打赏
  • 举报
回复
8楼朋友提供的判断是否本地硬盘的代码,很强悍。。。
jscn123789abc 2009-05-20
  • 打赏
  • 举报
回复
ding...
aaa_zzz_000 2009-05-20
  • 打赏
  • 举报
回复
CString GetDiskNumber(CString name)
{
HKEY hkey;
char sz[256];
DWORD dwtype,sl = 256;
int number=0;

// 确定选择的磁盘
for(int i=1;i<8;i++)
{
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Services\\Disk\\Enum",\
NULL,KEY_ALL_ACCESS,&hkey)==ERROR_SUCCESS)
{
CString id;
id.Format("%d",i);
if(RegQueryValueEx(hkey,id,NULL,&dwtype,(LPBYTE)sz,&sl)==ERROR_SUCCESS)
{
CString str=(CString)sz;
if(str.Compare(name)==0)
{
number=i;
break;
}
}
}
}
CString driver="\\\\.\\PHYSICALDRIVE";
CString num;
num.Format("%d",number);
driver+=num;
return driver;
}



// 确定选择的磁盘
driver=GetDiskNumber(name);
////////////////////////////////////////////////////////////////////////
U盘返回值
name = {"USBSTOR\Disk&Ven_CBM&Prod_Flash_Disk&Rev_5.00\0210010065721303&0"}
driver = {"\\.\PHYSICALDRIVE1"}

移动硬盘返回值
name = {"USBSTOR\Disk&Ven_Hitachi&Prod_HTS542516K9SA00&Rev_0002\000000000033&0"}
driver = {"\\.\PHYSICALDRIVE1"}

//////添加下面几行代码,来锁优盘和移动硬盘是否可行
logicalDisk = driver; //物理驱动,之前用的是逻辑驱动
hDevice = CreateFile(
logicalDisk, //要打开的驱动名称
GENERIC_READ|GENERIC_WRITE, //访问方式
FILE_SHARE_READ|FILE_SHARE_WRITE, //共享方式
NULL, //安全描述符指针
OPEN_EXISTING, //创建方式
0, //文件属性及标志
NULL //模板文件的句柄
);
bResult = DeviceIoControl(hDevice,FSCTL_LOCK_VOLUME,NULL,0,NULL,0,&dwOutBytes,(LPOVERLAPPED)NULL);
cloResult= CloseHandle(hDevice);
////////////////////////////////////////////////////////////////////////

gmsgms 2009-05-20
  • 打赏
  • 举报
回复
mark
aaa_zzz_000 2009-05-18
  • 打赏
  • 举报
回复
谢谢楼上各位朋友的回复,这几天抓紧试下,周末结帖。。。
会思考的草 2009-05-16
  • 打赏
  • 举报
回复

typedef struct _DEVICE_DESCRIPTOR
{
wstring wstrRing3Interface;
wstring wstrFriendlyName;
wstring wstrDeviceDesc;
wstring wstrPhysicalDeviceObjectName;
wstring wstrService;
wstring wstrParentInstanceID;
wstring wstrParentDeviceDesc;
wstring wstrStorageManagerName;
DWORD dwStorageDeviceNumber;
DWORD dwSectors;
DWORD dwBytesPerSector;
DISK_PARAMETER DiskGeometry;
}DEVICE_DESCRIPTOR, *PDEVICE_DESCRIPTOR;
会思考的草 2009-05-16
  • 打赏
  • 举报
回复
这个……根据DISK和Volume的GUID,用SetupDi函数族去取得设备的描述信息,然后判断哪些卷带有USB字样就可以了。


/*************************************************************************
* Function Name : GetDeviceInfo(LPGUID, vector<DEVICE_DESCRIPTOR>&)
*
* Introduction : Get storage device description
*
* Input parameter : lpGuid, DeviceVect
*
* Output parameter :None
*
* Return : None
*************************************************************************/
DWORD GetDeviceInfo(LPGUID lpGuid, vector<DEVICE_DESCRIPTOR>& DeviceVector)
{
SP_INTERFACE_DEVICE_DATA InterfaceData = {0}; //存储设备接口信息的结构体
PSP_INTERFACE_DEVICE_DETAIL_DATA_W pDetail = NULL;

SP_DEVINFO_DATA DevInfoData = {0};
HDEVINFO hDevInfoSet = NULL;
DWORD dwErrorCount = 0;
DWORD dwDevIndex = 0;
DEVINST ParentInstance = 0;
BOOL bResult = FALSE;
DEVICE_DESCRIPTOR tmpDevInfo;
DWORD dwNeededSize = 0;

//SetupDiEnumDeviceInterfaces函数取得设备属性集中某个设备接口的上下文环境
//每次调用都返回一个设备接口的相关信息.此函数可以被再三调用以获取一或多个
//设备暴露的、数个接口的信息,这里我们用来枚举符合该GUID的设备接口,调用成功
//的话,ifdata中将得到一个完成的SP_DEVICE_INTERFACE_DATA结构,该结构体将指明
//和枚举参数对应的,设备的接口信息.在调用该参数之前,必须填写ifdata的cbSize域
hDevInfoSet = SetupDiGetClassDevsW(
lpGuid, // 设备类的GUID
NULL, // 不指定关键字
NULL, // 不指定父窗口句柄
DIGCF_PRESENT| // 只枚举目前存在的设备
DIGCF_INTERFACEDEVICE //取得接口信息
);
if(hDevInfoSet == INVALID_HANDLE_VALUE) //失败??
{
MessageBox(NULL,"Sorry,Failed to retrive information set!","Error",MB_OK|MB_ICONERROR);
return 0;
}
// 成功!填写InterfaceData的cbSize域,准备调用SetupDiEnumDeviceInterfaces
InterfaceData.cbSize = sizeof(InterfaceData);
dwDevIndex = 0;
do
{
bResult = SetupDiEnumDeviceInterfaces(
hDevInfoSet, // 设备信息集句柄
NULL, // 不需额外的设备描述
lpGuid, // GUID
dwDevIndex, // 设备信息集里的设备序号
&InterfaceData // 设备接口信息(出口buffer)
);
if(!bResult) //失败?
{
break;
}

//成功,继续进行下列操作
dwNeededSize = 0;

//如果在调用SetupDiGetDeviceInterfaceDetail函数时,指定DeviceInterfaceDetailData,
//DeviceInterfaceDetailDataSize为NULL,并且RequiredSize变量有效的话,将得到需要的
//出口缓冲区的大小
SetupDiGetDeviceInterfaceDetailW(
hDevInfoSet,
&InterfaceData,
NULL,
0,
&dwNeededSize,
NULL
);

//上一次调用,我们在dwNeededSize中得到了PSP_DEVICE_INTERFACE_DETAIL_DATA
//结构体需要的缓冲区的大小,现在我们分配并初始化之.
pDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA_W)new char[dwNeededSize];
pDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA_W);
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

//OK,分配完毕,再次调用SetupDiGetDeviceInterfaceDetail得到特定接口的详细信息
bResult = SetupDiGetDeviceInterfaceDetailW
(
hDevInfoSet, // 设备信息集句柄,包含接口和下层设备信息(入口)
&InterfaceData, // 设备接口信息,表明我们要获取哪个接口的信息(入口)
pDetail, // 存储要查询的设备接口的详细细节(设备路径,出口)
dwNeededSize, // 指定输出缓冲区大小(入口)
&dwNeededSize, // 不需计算输出缓冲区大小(直接用设定值,出口)
&DevInfoData // 不需额外的设备描述(出口)
);
if(!bResult) //失败,则清场
{
dwErrorCount++;
delete []pDetail;
pDetail = NULL;
dwNeededSize = 0;
continue;
}
//取出设备路径(3环的应用程序所看到的设备路径)
tmpDevInfo.wstrRing3Interface = pDetail->DevicePath;
delete [](char*)pDetail;
pDetail = NULL;

dwNeededSize = 0;

tmpDevInfo.wstrFriendlyName = GetRegistryPropertyW(hDevInfoSet,DevInfoData,SPDRP_FRIENDLYNAME);
tmpDevInfo.wstrDeviceDesc = GetRegistryPropertyW(hDevInfoSet,DevInfoData,SPDRP_DEVICEDESC);
tmpDevInfo.wstrPhysicalDeviceObjectName = GetRegistryPropertyW(hDevInfoSet,DevInfoData,SPDRP_PHYSICAL_DEVICE_OBJECT_NAME);
tmpDevInfo.wstrService = GetRegistryPropertyW(hDevInfoSet,DevInfoData,SPDRP_SERVICE);

//获取本地设备树中父节点的ID
GetParentID(
DevInfoData.DevInst,
ParentInstance,
tmpDevInfo.wstrParentInstanceID,
tmpDevInfo.wstrParentDeviceDesc
);

GetStorageInfo(
tmpDevInfo.wstrRing3Interface,
tmpDevInfo.dwStorageDeviceNumber,
tmpDevInfo.wstrStorageManagerName
);

dwDevIndex++;

DeviceVector.push_back(tmpDevInfo);
}while(bResult);

SetupDiDestroyDeviceInfoList(hDevInfoSet);
return dwErrorCount;
}
aaa_zzz_000 2009-05-16
  • 打赏
  • 举报
回复
谢谢楼上朋友的回复,代码还没看太明白。。。
biweilun 2009-05-16
  • 打赏
  • 举报
回复
难道我说的不能用么?
加载更多回复(20)

16,550

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Creator Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

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