Здравствуйте,
уважаемые господа-программеры!
Перед вами очередная
статья из этого цикла.
Сегодня
мы поговорим о
стандартных API-функциях
для создания и
управления
виртуальными девайсами.
В частности QueryDosDevice()
и DefineDosDevice(). А так же
напишем программу-пример,
которая будет
реализовывать
возможности этих
функций. Описание
функций:
BOOL
DefineDosDevice(
DWORD
dwFlags, // параметры
LPCTSTR
lpDeviceName, // имя
устройства
LPCTSTR
lpTargetPath // путь к
каталогу
);
Описание:
Предназначена
для создания,
изменения и удаления
MS-DOS девайсов. Вообще-то
эта
функция не
предназначена для
работы с настоящими
девайсами, она может
управлять лишь
символическими
ссылками (symbolic links) на
определенный каталог
на локальном диске
или на сетевой ресурс.
Совместимость:
Windows NT/2000/XP
Библиотека:
Kernel32.lib (Kernel32.dll)
DWORD
QueryDosDevice(
LPCTSTR
lpDeviceName, // имя
устройства MS-DOS
LPTSTR lpTargetPath, // буффер
результатов запроса
DWORD
ucchMax // максимальный
размер буффера
);
Описание:
Функция
возвращает путь к MS-DOS
девайсу.
Совместимость:
Windows 95/98/Me/NT/2000/XP
Библиотека:
Kernel32.lib (Kernel32.dll)
Разберем
по-подробнее функцию
DefineDosDevice():
Параметр
dwFlags может принимать
следующие значения (взято
из MSDN):
¦---------------------------¦------------¦---------------------------------------¦
¦
Константа ¦ Значение
¦ Описание¦
¦---------------------------¦------------¦---------------------------------------¦
¦
DDD_RAW_TARGET_PATH ¦ 0x00000001 ¦ If
this value is specified, the ¦
¦ ¦ ¦
function does not convert the ¦
¦ ¦ ¦
lpTargetPath string from an MS-DOS ¦
¦ ¦ ¦
path to a path, but takes it as is. ¦
¦---------------------------¦------------¦---------------------------------------¦
¦
DDD_REMOVE_DEFINITION ¦ 0x00000002 ¦
If this value is specified, the ¦
¦ ¦ ¦
function removes the specified ¦
¦ ¦ ¦
definition for the specified device. ¦
¦ ¦ ¦
To determine which definition to ¦
¦ ¦ ¦
remove, the function walks the list ¦
¦ ¦ ¦
of mappings for the device, looking ¦
¦ ¦ ¦
for a match of lpTargetPath against ¦
¦ ¦ ¦
a prefix of each mapping associated ¦
¦ ¦ ¦
with this device. The first mapping ¦
¦ ¦ ¦
that matches is the one removed, ¦
¦ ¦ ¦
and then the function returns. ¦
¦ ¦ ¦
¦
¦ ¦ ¦
If lpTargetPath is NULL or a pointer ¦
¦ ¦ ¦
to a NULL string, the function will ¦
¦ ¦ ¦
remove the first mapping associated ¦
¦ ¦ ¦
with the device and pop the most ¦
¦ ¦ ¦
recent one pushed. If there is ¦
¦ ¦ ¦
nothing left to pop, the device name ¦
¦ ¦ ¦
will be removed. ¦
¦ ¦ ¦
¦
¦ ¦ ¦
If this value is NOT specified, the ¦
¦ ¦ ¦
string pointed to bythe lpTargetPath ¦
¦ ¦ ¦
parameter will become the new mapping ¦
¦ ¦ ¦
for this device. ¦
¦---------------------------¦------------¦---------------------------------------¦
¦
DDD_EXACT_MATCH_ON_REMOVE ¦ 0x00000004
¦ If this value is specified along with
¦
¦ ¦ ¦
DDD_REMOVE_DEFINITION, the function ¦
¦ ¦ ¦
will use an exact match to determine ¦
¦ ¦ ¦
which mapping to remove. Use this ¦
¦ ¦ ¦
value to insure that you do not ¦
¦ ¦ ¦
delete something that you did not ¦
¦ ¦ ¦ define. ¦
¦---------------------------¦------------¦---------------------------------------¦
Для
тех, кто в танке,
поясню: DDD_RAW_TARGET_PATH -
принять путь к
устройству без конвертации,
DDD_REMOVE_DEFINITION - удаление
устройства,
DDD_EXACT_MATCH_ON_REMOVE - используется
вместе с DDD_REMOVE_DEFINITION,
не позволит удалить
ненароком чего-либо
лишнего ;) Остальные
параметры функции, я
думаю, не нуждаются в
пояснении.
А c
QueryDosDevice() еще проще: в
lpDeviceName задается имя
девайса, в lpTargetPath -
адрес буфера в памяти, а в
ucchMax - максимальный
размер этого буфера.
Ну а
сейчас, как я уже
говорил, перейдем
непосредственно к
практике. Для примера
давайте закодим
простую программу для
управления
виртуальными
девайсами. Основные
возможности проги:
создать новый девайс,
удалить существующий
девайс, получить
путь к девайсу. Для
большего удобства
наша программа должна
обладать GUI
интерфейсом. Давайте
не будем
писать его на 'чистом'
API, т.к. при этом нам
придется
собственноручно создавать
и описывать каждый
элемент в окне.
Согласитесь, это
слишком долго и не
удобно. Гораздо проще
использовать ресурсы.
Для этого при помощи
того же Visual C++ 6
мы создадим диалог,
набросаем на него
необходимых нам
контролов, а затем в нашей
программе опишем
функцию обработки
сообщений. Итак,
приступим...
Запускайте
свой Visual C++ и
создавайте новый
пустой win32 проект (File->New->Project->Win32
Application->An empty project).
Теперь необходимо добавить
в него пустой cpp файл и
файл ресурсов. Я не
буду заострять на
этом особое внимание,
т.к. вы должны уметь
делать это
самостоятельно (иначе
какой же вы
программист? :). Далее
создаем новый диалог
и кидаем на него
некоторые контролы.
Вот их список:
Group Box
(5 шт.)
Static
Text (3 шт.)
Edit Box
(5 шт.)
У вас
должна получиться
примерно такая
картина:
<img
src="dialog.jpg">
Поясню
назначение некоторых
элементов:
Группа
Control Center, Поле Create, EditBox
1 - символ диска (c,d,e....)
Группа
Control Center, Поле Create, EditBox
2 - Путь к диску
Группа
Control Center, Поле Create, Button
- создание нового
диска
Группа
Control Center, Поле Remove, EditBox
- символ диска (c,d,e....)
Группа
Control Center, Поле Remove, Button
- удаление диска
Группа
Control Center, Поле Get path,
EditBox - символ диска (c,d,e....)
Группа
Control Center, Поле Get path,
Button - получение пути к
диску
Группа
Messages, EditBox - сообщения
программы
А
теперь перейдем к
кодингу...
Для
начала подключим
необходимые
заголовочные файлы:
#include
<windows.h>
#include
<CommCtrl.h>
#include
<stdio.h>
#include
"resource.h"
и
объявим некоторые
переменные:
#define
IDM_ABOUT 0
HMENU
hmenuChart; //пункт меню
HMENU
hmain; //главное меню
диалога
После
этого необходимо
подключить к проекту
следующие библиотеки:
msvcrt.lib
kernel32.lib user32.lib comctl32.lib. Также
нужно написать
функцию вывода
сообщений программы в
IDC_EDIT4. Вот ее код:
void
__stdcall WriteLog(HWND hwnd, char* str)
{
EnableWindow(GetDlgItem(hwnd,IDC_EDIT4),TRUE);
for(unsigned
int i = 0; i < strlen(str); i++)
SendDlgItemMessage((HWND)hwnd,IDC_EDIT4,WM_CHAR,str[i],0);
//посимвольно
заполняем IDC_EDIT4
EnableWindow(GetDlgItem(hwnd,IDC_EDIT4),FALSE);
}
В
функции WinMain мы
инициализируем
контролы
InitCommonControls();
И
создаем наш диалог
DialogBox(hinst,MAKEINTRESOURCE(IDD_DIALOG1),NULL,Dlg_Proc);
Здесь
предполагается, что
IDD_DIALOG1 - это название
диалога, а Dlg_Proc - функция
обработки сообщений.
Т.к. этой функции у нас
еще нет, то нам нужно
будет
ее написать. В
целях экономии места,
я приведу только ее
основные параметры.
Сама
функция имеет
следующий вид:
int
__stdcall Dlg_Proc(HWND hwnd, UINT wMsg,
WPARAM wParam, LPARAM lParam), где
hwnd -
хандл окна, wMsg -
сообщение, wParam и lParam
параметры сообщения.
Объявление
переменных:
char dl,
drv[255];
OSVERSIONINFO os;
RECT
r,r2;
char*
path, *path2, *temp;
Обработка
сообщения WM_INITDIALOG:
hmenuChart
= CreatePopupMenu(); //создаем
новый пункт меню
hmain =
CreateMenu(); //и само меню
AppendMenu(hmenuChart,
MF_STRING, IDM_ABOUT, "About");
AppendMenu(hmain,
MF_STRING | MF_POPUP, (UINT_PTR)hmenuChart,
"Help"); //добавим к
нему этот пункт в
раздел Help
SetMenu(hwnd, hmain); //добавим меню к
диалогу
EnableWindow(GetDlgItem(hwnd,IDC_EDIT4),FALSE);
//"выключаем"
IDC_EDIT4 (сообщения
программы)
GetWindowRect(GetDesktopWindow(),&r);
GetWindowRect(hwnd,&r2);
SetWindowPos(hwnd, NULL, r.right/2-373/2,
r.bottom/2-420/2,
373, 420, 0); //window pos = desktop
center
Обработка
сообщения WM_CLOSE:
EndDialog(hwnd,1);
Далее
у нас идет обработчик
команд. В нем я
реализовал все
основные функции
программы, т.ч.
вникай в комментарии
к коду... Обработка
IDM_ABOUT:
MessageBox(hwnd,
"VDD2 - Copyright (C) NeTxXx. <develop@list.ru>","About",MB_OK+MB_ICONINFORMATION);
//о программе
Обработка
IDC_BUTTON3:
//получить путь
к девайсу
GetDlgItemText(hwnd,IDC_EDIT3,drv,255);
//получаем строку из
IDC_EDIT3
dl = drv[0];
//в dl запишем I символ
drv
temp = (char*)malloc((size_t)255);
//выделяем память для
temp
memset(temp,0,(size_t)255);
//заполняем temp нулями
path = (char*)malloc((size_t)255);
//выделяем память для
path
memset(path,0,(size_t)255);
//заполняем path нулями
os.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO); //инициализируем
структуру OSVERSIONINFO
if (GetVersionEx(&os)==0)
//получаем системную
информацию
{
WriteLog(hwnd,"ERROR
getting windows version!");
return 1;
}
if (os.dwPlatformId
== VER_PLATFORM_WIN32_NT) //если
платформа = WinNT
{
char
buff2[2];
buff2[0]
= dl;
buff2[1]
= ':';
buff2[2]
= '0';
QueryDosDevice(buff2,path,255);
//получаем путь к
девайсу
sprintf(temp,
"Local path to virtual drive %c:%s",
dl, path);
WriteLog(hwnd, temp);
} else
{
WriteLog(hwnd,
"VDD2 works only on WIN NT platform!");
//выходим из функции
если платформа != WinNT
return 1;
}
//освобождаем
память
free(temp);
free(path);
Обработка
IDC_BUTTON2: //удаление
девайса
GetDlgItemText(hwnd,IDC_EDIT2,drv,255);
//получаем ->
dl = drv[0];
//-> символ девайса
//выделение
памяти под переменные
temp = (char*)malloc((size_t)255);
memset(temp,0,(size_t)255);
path = (char*)malloc((size_t)255);
memset(path,0,(size_t)255);
path2 = (char*)malloc((size_t)255);
memset(path2,0,(size_t)255);
os.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO);
if (GetVersionEx(&os)==0)
//получаем системную
информацию
{
WriteLog(hwnd,"ERROR
getting windows version!");
return 1;
}
if (os.dwPlatformId
== VER_PLATFORM_WIN32_NT) //если
платформа = WinNT
{
char
buff2[2];
buff2[0]
= dl;
buff2[1]
= ':';
buff2[2]
= '0';
QueryDosDevice(buff2,path,256);
//получаем путь к
девайсу
if (strchr(path,'?')!=NULL)
//удаляем лишние
символы ("??")
{
path +=
4;
strncpy(path2,path,(int)strlen(path));
} else {
strncpy(path2,path,(int)strlen(path));
}
if
(path2[strlen(path2)-1] != '\')
strcat(path2,"\");
if (!DefineDosDevice(DDD_REMOVE_DEFINITION,buff2,path2))
//удаляем девайс
{
WriteLog(hwnd,"ERROR
removing device!");
return 1;
}
sprintf(temp,
"Virtual drive %c was successfully
removed.", dl);
WriteLog(hwnd, temp);
} else
{
WriteLog(hwnd,
"VDD2 works only on WIN NT platform!");
//выходим из функции
если платформа != WinNT
return 1;
}
//освобождаем
память
free(temp);
free(path);
Обработка
IDC_BUTTON2:
//создание
девайса
GetDlgItemText(hwnd,IDC_EDIT1,drv,255);
//получаем ->
dl = drv[0];
//-> символ девайса
//выделение
памяти под переменные
path = (char*)malloc((size_t)255);
memset(path,0,(size_t)255);
temp = (char*)malloc((size_t)255);
memset(temp,0,(size_t)255);
GetDlgItemText(hwnd,IDC_EDIT5,path,255);
if (path[strlen(path)-1]
!= '\')
strcat(path,"\");
os.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO);
if (GetVersionEx(&os)==0)
//получаем системную
информацию
{
WriteLog(hwnd,"ERROR
getting windows version!");
return 1;
}
if (os.dwPlatformId
== VER_PLATFORM_WIN32_NT) //если
платформа = WinNT
{
char buff[2];
buff[0] = dl;
buff[1] =
':';
buff[2] =
'0';
if (!DefineDosDevice(0,buff,path))
//создаем новый девайс
{
WriteLog(hwnd,"ERROR
defining device!");
return 1;
}
//обрадуем
юзера сообщением :)
sprintf(temp,
"Virtual drive %c was successfully
created.", dl);
WriteLog(hwnd, temp);
sprintf(temp,
"Local path to virtual drive %c: %s",
dl, path);
WriteLog(hwnd, temp);
sprintf(temp,
"Enjoy!");
WriteLog(hwnd, temp);
} else
{
WriteLog(hwnd,
"VDD2 works only on WIN NT platform!");
//выходим из функции
если платформа != WinNT
return 1;
}
free(temp);
free(path);
Вот
пожалуй и все.
Осталось только
скомпилировать и
запустить программу.
После
компиляции (естественно
успешной), запустите
программу и проверьте,
создаются
ли новые девайсы. Если
да - все OK, а если же
нет - убедитесь что у вас
стоит WinNT и проверьте
свой код на наличие
ошибок. В
итоге у нас
получилась удобная и
в то же время простая
утилита для
управления виртуальными
девайсами. Но к
сожалению у нее есть
один большой
недостаток: функционирование
ТОЛЬКО на NT
планформах. Так
что счастливым
обладателям Win9x
придется
довольствоваться
только локальными дисками
на компьютере, либо
ждать следующую
статью из этого цикла.
В ней я постараюсь подробно
изложить все аспекты
работы с
альтернативами
рассмотренных нами
функций в Win9x
системах, а так же
убрать с нашей
утилиты таргет WinNT only
;)
Продолжение
следует....
Автор:
NeTxXx Copyright
(C) 2003-2004 e-mail:
develop@list.ru
Размещено:
5.06.2005 |