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

Результат работы программы вы можете видеть на рисунке, в последующем мне бы хотелось создать программу, которая будет для удобства иметь графический интерфейс.

На этом всё.

Оставить мнение

Check Also

Конкурс хаков: пишем на PowerShell скрипт, который уведомляет о днях рождения пользователей Active Directory

В компаниях часто встречается задача уведомлять сотрудников о приближающихся днях рождения…