В этой статье рассматривается создание программы монтирования жестких дисков в директории. По умолчанию Windows монтирует несъемные носители автоматически - если вы подключаете новый жесткий диск к компьютеру, то после загрузки операционной системы и установки необходимых драйверов вы можете увидеть его в проводнике. В операционных системах UNIX существует возможность монтирования жестких дисков в директории, так называемые точки монтирования. Начиная с Windows NT 4.0 в поставку операционной системы входит утилита mountvol.exe, которая через интерфейс командной строки позволяет создавать, удалять и выводит список точек подключения дисков. Результат работы которой вы видите на рисунке:
После непродолжительной работы с данной утилитой мне захотелось реализовать предоставленные возможности самому, программно. Первым шагом нужно было, выяснить какие API функции использует mountvol.exe, для этого использовалась программа Dependency Walker, входящая в состав поставки среды разработки.
Из результата работы 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\\”, второй параметр - уникальный идентификатор тома.
Предупреждение: Точка куда будет монтироваться том, в нашем случае директория должна быть пустой! На содержимое монтируемого тома это условие не распространяется.
А теперь пробуем все вместе. Ниже приведен исходный текст программы которая сначала выводит двумя способами уникальные идентификаторы томов, их файловую систему, тип тома и метку, дальше она производит демонтирование заданного диска и последующее его монтирование в точку 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); }
Результат работы программы вы можете видеть на рисунке, в последующем мне бы хотелось создать программу, которая будет для удобства иметь графический интерфейс.
На этом всё.