В этой статье рассматривается, как программно монтировать жесткие диски в директории. По умолчанию 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]