昨天,在CSDN中看见
帖子寻求解决挂载盘符的问题,今天把它搞定了。
本文只要用最新的SDK(或者2k以上)然后定义Windows版本_WIN32_WINNT为0x0500以上就能编译通过了。 改变盘符主要是用
SetVolumeMountPoint和DeleteVolumeMountPoint 两个函数。DeleteVolumeMountPoint 很简单就不多说了。SetVolumeMountPoint 的使用主要是要找到被挂载设备的VolumeName。但是设备被卸载以后用GetVolumeNameForVolumeMountPoint根本取不到VolumeName,怎么办呢?
微软XP的系统文件夹里面有一个叫diskpart.exe的命令行工具,用它可以改变盘符。那么它是怎么做到的呢?简单的分析(用VC6自带的工具DEPENDS.EXE)就可以看见这个程序使用了很多Setup API函数,我判断使用SetupDiEnumDeviceInfo来取得VolumeName的ClassGUID,但是结果发现取到的ClassGUID和用GetVolumeNameForVolumeMountPoint获取的没有卸载前的VolumeName中的ClassGUID不一样。怎么办呢?
没关系,让我们祭出屠龙刀:IDA Pro。如何反汇编分析不在本文的介绍了(挺麻烦,而我这人又比较懒嘿嘿)。我一阵海扁它,发现关键是要通过DefineDosDevice 函数将设备Attach到盘符上,然后用GetVolumeNameForVolumeMountPoint取到VolumeName,之后就可以用SetVolumeMountPoint将设备挂载到盘符上了。我把它写成了函数如果要加载盘符就可以使用(前提是盘符未被占用):
ChangeMountPoint( _T("H:\\"), _T("\\Device\\HarddiskVolume2"),true);
卸载的话用:
ChangeMountPoint( _T("H:\\"),NULL, false);
下面是ChangeMountPoint函数的实现:
bool ChangeMountPoint(LPCTSTR lpDriveLetter,LPCTSTR lpDevice,bool bAddMountPoint)
{
bool bRet = false;
TCHAR szDriveLetterAndSlash[4] = {0};
TCHAR szDriveLetter[3] = {0};
TCHAR szUniqueVolumeName[MAX_PATH] = {0};
if(lpDriveLetter && lpDevice)
{
szDriveLetter[0] = lpDriveLetter[0];
szDriveLetter[1] = TEXT(':');
szDriveLetter[2] = TEXT('\0');
szDriveLetterAndSlash[0] = lpDriveLetter[0];
szDriveLetterAndSlash[1] = TEXT(':');
szDriveLetterAndSlash[2] = TEXT('\\');
szDriveLetterAndSlash[3] = TEXT('\0');
if ( bAddMountPoint )
{
//Try to Attach lpDevice to lpDriveLetter
bRet = DefineDosDevice (DDD_RAW_TARGET_PATH, szDriveLetter,
lpDevice);
if (bRet)
{
if (!GetVolumeNameForVolumeMountPoint (szDriveLetterAndSlash,
szUniqueVolumeName,
MAX_PATH))
{
//Can't Find Attached lpDevice 's VolumeName
szUniqueVolumeName[0] = '\0';
}
bRet = DefineDosDevice (
DDD_RAW_TARGET_PATH|DDD_REMOVE_DEFINITION|
DDD_EXACT_MATCH_ON_REMOVE, szDriveLetter,
lpDevice);
if (!bRet)
return bRet;
bRet = SetVolumeMountPoint(szDriveLetterAndSlash,
szUniqueVolumeName);
}
}
else
{
bRet = DeleteVolumeMountPoint (szDriveLetterAndSlash);
}
}
return bRet;
}