В этой статье рассматривается, как программно монтировать жесткие диски в директории. По умолчанию Windows монтирует несъемные носители автоматически, то есть если вы подключаете новый жесткий диск к компьютеру и после загрузки операционной системы, и установки необходимых драйверов, вы можете увидеть его в проводнике.
В операционных системах UNIX существует возможность монтирования жестких дисков в директории, так называемые точки монтирования. Начиная с Windows NT 4.0 в поставку операционной системы входит утилита mountvol.exe, которая через интерфейс командной строки позволяет создавать, удалять и выводит список точек подключения дисков. Результат работы которой вы видите на рисунке:
После не продолжительной работы с данной утилитой, мне захотелось реализовать предоставленные возможности самому, программно. Первым шагом, нужно было, выяснить какие API функции использует mountvol.exe, для этого использовалась программа Dependency Walker входящая в состав поставки среды разработки, ниже на рисунке предоставлено основное окно программы с загруженной в нее утилиты mountvol.exe:
Из результата работы Dependency Walker мы видим какие API функции использует mountvol.exe. Для создания программы-примера использовалась среда разработки MS Visual C++ 6.0, тип приложения «Win 32 Console Application».Для начала рассмотрим функций, которые будут использоваться в приложении, и так по порядку:
HANDLE FindFirstVolume(LPTSTR lpszVolumeName,DWORD cchBufferLength);
Данная функция используется для начала сканирования компьютера на наличие томов, возвращаемое значение хендел который используется для последующего поиска, в переменную lpszVolumeName возвращается указатель на буфер, содержащий уникальный индефикатор (GUID) первого найденного тома.
Для дальнейшего поиска используется функция:
BOOL FindNextVolume(HANDLE hFindVolume, LPTSTR lpszVolumeName, DWORD cchBufferLength);
Первым параметром, которой является хендел, полученный при помощи вызова функции FindFirstVolume, в переменную lpszVolumeName возвращаются последующие найденные индефикаторы(GUID) томов.
Для завершения поиска необходимо осуществить вызов функции:
BOOL FindVolumeClose(HANDLE hFindVolume);
Единственным параметром функции, которой является хендел поиска.
Для определения типа тома использовалась функция:
UINT GetDriveType( LPCTSTR lpRootPathName);
Параметром которой является индефикатор тома, возвращаемое значение:
DRIVE_UNKNOWN Не известный тип
DRIVE_NO_ROOT_DIR Не точек подключения
DRIVE_REMOVABLE Съёмный диск
DRIVE_FIXED Фиксированный диск
DRIVE_REMOTE Удалённый или network диск
DRIVE_CDROM CD-ROM диск
DRIVE_RAMDISK RAM диск
Для определения файловой системы и метки тома использовалась функция:
BOOL GetVolumeInformation(
LPCTSTR lpRootPathName,
LPTSTR lpVolumeNameBuffer,
DWORD nVolumeNameSize,
LPDWORD lpVolumeSerialNumber,
LPDWORD lpMaximumComponentLength,
LPDWORD lpFileSystemFlags,
LPTSTR lpFileSystemNameBuffer,
DWORD nFileSystemNameSize);
Первый параметр которой является уникальный индефикатор тома, в параметра lpVolumeNameBuffer возвращается метка тома, в параметр lpFileSystemNameBuffer возвращается указатель на буфер содержащий имя файловой системы.
Мною также был найден еще один способ получения уникальных индефикаторов томов, для этого использовалась связка функций GetLogicalDrives и GetVolumeNameForVolumeMountPoint, подробней о их параметрах:
DWORD GetLogicalDrives(void);
Функция возвращает битовую маску, которая содержит все доступные тома в системе.
BOOL GetVolumeNameForVolumeMountPoint(
LPCTSTR lpszVolumeMountPoint,
LPTSTR lpszVolumeName,
DWORD cchBufferLength);
Функция возвращает уникальный индефикатор тома по его точке монтирования.
На рисунке представлен результат работы этих двух способов:
Для удаления точки монтирования использовалась функция:
BOOL DeleteVolumeMountPoint(LPCTSTR lpszVolumeMountPoint);
Параметром которой является точка монтирования.
И самая главная функция по монтированию томов:
BOOL SetVolumeMountPoint(
LPCTSTR lpszVolumeMountPoint,
LPCTSTR lpszVolumeName);
Первый параметр которой является точка последующего монтирования, в нашем случае это директория, например “C:\\mnt\\”, второй параметр это уникальный индефикатор тома.
<strong>Предупреждение:</strong>
Точка куда будет монтироваться том, в нашем случае директория должна быть пустой!!!
На содержимое монтируемого тома это условие не распространяется.
А теперь пробуем все вместе, далее приведен исходный текст программы, которая сначала выводит двумя способами уникальные индефикаторы томов, так же файловую систему, тип тома и метку, дальше она производит демонтирование заданного диска и последующее его монтирование в точку C:\\mnt\\ после паузы возвращает первоначальную точку.
#include <iostream.h>
#include <windows.h>
#include <conio.h>
HANDLE (WINAPI * FindFirstVolume)(LPTSTR,DWORD);
BOOL (WINAPI * FindNextVolume)(HANDLE,LPTSTR,DWORD);
BOOL (WINAPI * FindVolumeClose)(HANDLE);
BOOL (WINAPI * GetVolumeNameForVolumeMountPoint)(LPCTSTR,LPTSTR,DWORD);
BOOL (WINAPI * DeleteVolumeMountPoint)(LPCTSTR);
BOOL (WINAPI * SetVolumeMountPoint)(LPCTSTR,LPCTSTR);
void ErrorView();
int main()
{
HANDLE hMount;
char szPath[MAX_PATH],
szRecvBuff[MAX_PATH+1],
szFileSystem[MAX_PATH+1];
HMODULE hmod;
if((hmod = LoadLibrary("Kernel32.dll")))
{
if(!(FindFirstVolume = (HANDLE(WINAPI *)
(LPTSTR,DWORD))GetProcAddress(hmod,"FindFirstVolumeA")))
{cout<<"Error GetProcAddress...1"<<endl;return -1;}
if(!(FindNextVolume = (BOOL(WINAPI *)
(HANDLE,LPTSTR,DWORD))GetProcAddress(hmod,"FindNextVolumeA")))
{cout<<"Error GetProcAddress...2"<<endl;return -1;}
if(!(FindVolumeClose = (BOOL(WINAPI *)
(HANDLE))GetProcAddress(hmod,"FindVolumeClose")))
{cout<<"Error GetProcAddress...3"<<endl;return -1;}
if(!(GetVolumeNameForVolumeMountPoint = (BOOL(WINAPI *)
(LPCTSTR,LPTSTR,DWORD))GetProcAddress(hmod,
"GetVolumeNameForVolumeMountPointA")))
{cout<<"Error GetProcAddress...4"<<endl;return -1;}
if(!(DeleteVolumeMountPoint = (BOOL(WINAPI *)
(LPCTSTR))GetProcAddress(hmod,"DeleteVolumeMountPointA")))
{cout<<"Error GetProcAddress...5"<<endl;return -1;}
if(!(SetVolumeMountPoint = (BOOL(WINAPI *)
(LPCTSTR,LPCTSTR))GetProcAddress(hmod,"SetVolumeMountPointA")))
{cout<<"Error GetProcAddress...6"<<endl;return -1;}
hMount = FindFirstVolume(szPath,sizeof(szPath));
UINT uin;
if(hMount!=INVALID_HANDLE_VALUE)
{
do
{
uin = GetDriveType(szPath);
if(uin==DRIVE_CDROM) {cout<<"CDROM: ";}
if(uin==DRIVE_UNKNOWN) {cout<<"UNKNOWN: ";}
if(uin==DRIVE_NO_ROOT_DIR){cout<<"NO_ROOT_DIR: ";}
if(uin==DRIVE_REMOVABLE) {cout<<"REMOV: ";}
if(uin==DRIVE_FIXED) {cout<<"FIXED: ";}
if(uin==DRIVE_REMOTE) {cout<<"REMOTE: ";}
if(uin==DRIVE_RAMDISK) {cout<<"RAMDISK: ";}
GetVolumeInformation(szPath,
szRecvBuff,
sizeof(szRecvBuff),
NULL,NULL,NULL,
szFileSystem,
sizeof(szFileSystem));
cout<<"("<<szRecvBuff
<<"|"<<szFileSystem
<<") "<<szPath<<endl<<endl;
ZeroMemory(szRecvBuff,sizeof(szRecvBuff));
ZeroMemory(szFileSystem,sizeof(szFileSystem));
}while(FindNextVolume(hMount,szPath,sizeof(szPath))!=0);
FindVolumeClose(hMount);
}else{cout<<"Error FindFirstVolume"<<endl;}
FreeLibrary(hmod);
}else{cout<<"Error LoadLibrary"<<endl;}
ZeroMemory(szRecvBuff,sizeof(szRecvBuff));
char szDrive[4];DWORD dwID = GetLogicalDrives();
for(int i = 0;i < 26;i++)
{
if(((dwID>>i)&0x00000001)==1)
{
szDrive[0] = char(65+i);
szDrive[1] = ':';
szDrive[2] = '\\';
szDrive[3] = 0;
GetVolumeNameForVolumeMountPoint(szDrive,
szRecvBuff,
sizeof(szRecvBuff));
cout <<szDrive<<" "<<szRecvBuff<<endl;
}
}
/************************************/
if(DeleteVolumeMountPoint("G:\\"))
{cout<<"DeleteVolumeMountPoint status:OK"<<endl;}
else
{cout<<"DeleteVolumeMountPoint status:ERROR"<<endl;ErrorView();}
if(SetVolumeMountPoint("C:\\mnt\\",
"\\\\?\\Volume{e7aaf23a-8560-11db-97d5-806d6172696f}\\"))
{cout<<"SetVolumeMountPoint status:OK"<<endl;}
else
{cout<<"SetVolumeMountPoint status:ERROR"<<endl;ErrorView();}
/////////////////
cout<<"(PAUSE)Press any key..."<<endl;
while(!getch());
/////////////////
if(DeleteVolumeMountPoint("C:\\mnt\\"))
{cout<<"DeleteVolumeMountPoint status:OK"<<endl;}
else
{cout<<"DeleteVolumeMountPoint status:ERROR"<<endl;ErrorView();}
if(SetVolumeMountPoint("G:\\",
"\\\\?\\Volume{e7aaf23a-8560-11db-97d5-806d6172696f}\\"))
{cout<<"SetVolumeMountPoint status:OK"<<endl;}
else
{cout<<"SetVolumeMountPoint status:ERROR"<<endl;ErrorView();}
/************************************/
cout<<"Press any key to exit..."<<endl;
while(!getch());
return 0;
}
void ErrorView()
{
LPVOID lpMsgBuf = NULL;
FormatMessage
(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL,GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf, 0, NULL);
CharToOem((LPTSTR)lpMsgBuf,(LPTSTR)lpMsgBuf);
cout<<(LPCTSTR)lpMsgBuf<<endl;
LocalFree(lpMsgBuf);
}
А теперь подробней, по шагам:
HANDLE (WINAPI * FindFirstVolume) (LPTSTR,DWORD);
BOOL (WINAPI * FindNextVolume) (HANDLE,LPTSTR,DWORD);
BOOL (WINAPI * FindVolumeClose)(HANDLE);
BOOL (WINAPI * GetVolumeNameForVolumeMountPoint) (LPCTSTR,LPTSTR,DWORD);
BOOL (WINAPI * DeleteVolumeMountPoint) (LPCTSTR);
BOOL (WINAPI * SetVolumeMountPoint) (LPCTSTR,LPCTSTR);
Создаются указатели на прототипы функций для последующей загрузки в них адресов функций.
hmod = LoadLibrary("Kernel32.dll"));
Загружаем необходимую библиотеку.
if(!(FindFirstVolume = (HANDLE(WINAPI *)
(LPTSTR,DWORD))GetProcAddress(hmod,"FindFirstVolumeA")))
{cout<<"Error GetProcAddress...1"<<endl;return -1;}
if(!(FindNextVolume = (BOOL(WINAPI *)
(HANDLE,LPTSTR,DWORD))GetProcAddress(hmod,"FindNextVolumeA")))
{cout<<"Error GetProcAddress...2"<<endl;return -1;}
if(!(FindVolumeClose = (BOOL(WINAPI *)
(HANDLE))GetProcAddress(hmod,"FindVolumeClose")))
{cout<<"Error GetProcAddress...3"<<endl;return -1;}
if(!(GetVolumeNameForVolumeMountPoint = (BOOL(WINAPI *)
(LPCTSTR,LPTSTR,DWORD))GetProcAddress(hmod,
"GetVolumeNameForVolumeMountPointA")))
{cout<<"Error GetProcAddress...4"<<endl;return -1;}
if(!(DeleteVolumeMountPoint = (BOOL(WINAPI *)
(LPCTSTR))GetProcAddress(hmod,"DeleteVolumeMountPointA")))
{cout<<"Error GetProcAddress...5"<<endl;return -1;}
if(!(SetVolumeMountPoint = (BOOL(WINAPI *)
(LPCTSTR,LPCTSTR))GetProcAddress(hmod,"SetVolumeMountPointA")))
{cout<<"Error GetProcAddress...6"<<endl;return -1;}
Далее получаем адреса необходимых нам функций.
hMount = FindFirstVolume(szPath,sizeof(szPath));
UINT uin;
if(hMount!=INVALID_HANDLE_VALUE)
{
do
{
uin = GetDriveType(szPath);
if(uin==DRIVE_CDROM) {cout<<"CDROM: ";}
if(uin==DRIVE_UNKNOWN) {cout<<"UNKNOWN: ";}
if(uin==DRIVE_NO_ROOT_DIR){cout<<"NO_ROOT_DIR: ";}
if(uin==DRIVE_REMOVABLE) {cout<<"REMOV: ";}
if(uin==DRIVE_FIXED) {cout<<"FIXED: ";}
if(uin==DRIVE_REMOTE) {cout<<"REMOTE: ";}
if(uin==DRIVE_RAMDISK) {cout<<"RAMDISK: ";}
GetVolumeInformation(szPath, szRecvBuff,
sizeof(szRecvBuff), NULL,NULL,NULL,
szFileSystem,sizeof(szFileSystem));
cout<<"("<<szrecvbuff
<<"|"<<szFileSystem
<<") "<<szPath<<endl<<endl;
ZeroMemory(szRecvBuff,sizeof(szRecvBuff));
ZeroMemory(szFileSystem,sizeof(szFileSystem));
}while(FindNextVolume(hMount,szPath,sizeof(szPath))!=0);
}
Производится поиск томов и вывод информации о них.
ZeroMemory(szRecvBuff,sizeof(szRecvBuff));
char szDrive[4];DWORD dwID = GetLogicalDrives();
for(int i = 0;i < 26;i++)
{
if(((dwID>>i)&0x00000001)==1)
{
szDrive[0] = char(65+i);
szDrive[1] = ':';
szDrive[2] = '\\';
szDrive[3] = 0;
GetVolumeNameForVolumeMountPoint(szDrive,
szRecvBuff,
sizeof(szRecvBuff));
cout <<szDrive<<" "<<szRecvBuff<<endl;
}
}
Здесь идет вывод информации вторым способом.
if(DeleteVolumeMountPoint("G:\\"))
{cout<<"DeleteVolumeMountPoint status:OK"<<endl;}
else
{cout<<"DeleteVolumeMountPoint status:ERROR"<<endl;ErrorView();}
Удаление точки монтирования, после выполнения данного участка кода, утилита mountvol покажет вам следующее:
Далее устанавливаем новую точку монтирования:
if(SetVolumeMountPoint("C:\\mnt\\",
"\\\\?\\Volume{e7aaf23a-8560-11db-97d5-806d6172696f}\\"))
{cout<<"SetVolumeMountPoint status:OK"<<endl;}
else
{cout<<"SetVolumeMountPoint status:ERROR"<<endl;ErrorView();}
и смотрим результат работы mountvol а также заходим в точку монтирования C:\mnt\ и видим там содержимое жесткого диска:
Ну а теперь возвращаем все как было, для этого следующий участок кода:
if(DeleteVolumeMountPoint("C:\\mnt\\"))
{cout<<"DeleteVolumeMountPoint status:OK"<<endl;}
else
{cout<<"DeleteVolumeMountPoint status:ERROR"<<endl;ErrorView();}
if(SetVolumeMountPoint("G:\\",
"\\\\?\\Volume{e7aaf23a-8560-11db-97d5-806d6172696f}\\"))
{cout<<"SetVolumeMountPoint status:OK"<<endl;}
else
{cout<<"SetVolumeMountPoint status:ERROR"<<endl;ErrorView();}
Результат работы программы вы можете видеть на рисунке, в последующем мне хотелось бы создать программу, которая будет для удобства иметь графический интерфейс….
[/code]