Системное программирование в среде Win32

Автор работы: Пользователь скрыл имя, 25 Марта 2014 в 14:49, лекция

Краткое описание

Конспект лекций содержит описание технологии системного программирования под Windows с использованием функций Win32 API. В первой части конспекта лекций рассмотрены особенности архитектуры ОС Windows, специфика интерфейса прикладного программирования Win32, структура приложений для Windows. Подробно рассмотрены API функции и основные структуры данных для работы с дисками, каталогами, файлами. Отдельная глава посвящена структурной обработке исключений SEH.

Прикрепленные файлы: 1 файл

Win32_лек_часть1.doc

— 811.00 Кб (Скачать документ)

 

Win32 не поддерживает ссылок на  файлы (file linking), благодаря которым два имени файла могут указывать на один и тот же файл.

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

При перемещениии файл реально перемещается только тогда, когда он перемещается с одного диска на другой. Иначе просто изменяется ссылка на файл в таблице размещения файлов

 

4.2. Управление каталогами

Создание и удаление каталогов

Создание или удаление каталога выполняется двумя простыми функциями.

BOOL CreateDirectory (LPCTSTR lpszPath,   

LPSECURITY_ATTRIBUTES  lpsa)

и

BOOL RemoveDirectory (LPCTSTR lpszPath)

lpszPath указывает на строку  с завершающим нулем, содержащую  имя каталога, который должен  быть создан или удален. Второй  параметр - атрибуты безопасности – позволяет назначить особые привилегии для каталога. Если в этом нет необходимости, то этот параметр должен быть равен NULL. При успешном завершении функция CreateDirectory создает каталог и возвращает значение TRUE. В случае возникновения какой-либо ошибки функция возвращает FALSE.

Удалить можно только пустой каталог.

Определение и изменение текущего каталога

Каждый процесс имеет текущий, или рабочий, каталог. Программист может и узнать текущий каталог, и установить его. Устанавливает каталог функция:

BOOL SetCurrentDirectory (LPCTSTR lpszCurDir)

lpszCurDir – путь к новому  текущему каталогу. Это может  быть относительный путь или полностью уточненный путь, начинающийся либо с буквы диска и двоеточия, например D:, либо с имени UNC (например, \\ACCNG_SERVER\PUBLIC).

Если путь к каталогу – просто обозначение привода (например, А: или С:), текущим становится рабочий каталог указанного диска. Например, если рабочие каталоги установлены в последовательности

C:\MSDEV

INCLUDE

A:\MEMOS\TODO

C:

то в  результате текущий каталог будет C:\MSDEV\INCLUDE.

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

DWORD GetCurrentDirectory (DWORD cchCurDir,

LPTSTR  lpszCurDir)

Возвращаемое значение: длина строки возвращенного пути или требуемый размер буфера, если он недостаточно велик; нуль при неудаче.

Параметры этой функции:

  • cchCurDir  -  длина в символах (не в байтах) буфера для имени каталога,  длина должна учитывать завершающий нулевой символ;
  • lpszCurDir указывает на буфер, в который записывается строка пути.

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

Этот метод возвращения строки и ее длины обычен в Win32; работать с ним следует осторожно.

Пример 4.1. Демонстрационная программа «Каталоги и файлы»

В этой программе мы сделаем следующее:

1. Создадим на диске С две  директории с именами

«Demo_Directory_For_Book_1» и «Demo_Directory_For_Book_2».

2. В каждой  из этих директорий создадим  файлы с именами 

«File_1.dem»

3. Постараемся  скопировать файл из первой  директории во вторую и убедимся, что произошла ошибка, так как  файл уже существует.

4. Переименуем  файл в первой директории в «File_2.dem».

5. Скопируем  файл из первой директории  во вторую.

6. Удалим  файлы и директории.

 

#include "stdafx.h"

 

#include <windows.h>

 

int APIENTRY WinMain(HINSTANCE hInstance,

                     HINSTANCE hPrevInstance,

                     LPSTR     lpCmdLine,

                     int       nCmdShow)

{

const int szBuffer=200;

char cBuffer[256];

char cBufferForCurrentDirectory[szBuffer];

HANDLE hFile;

// Сохраняем имя текущего  каталога

int LenCurDir=GetCurrentDirectory(szBuffer, cBufferForCurrentDirectory);

    if (LenCurDir==0)

{MessageBox(NULL, "Не  удается определить текущий каталог",

"Ошибка", MB_OK);

return 0;}

  if (LenCurDir>szBuffer)

{MessageBox(NULL, "Имя  текущего каталога слишком длинное!", "Info", MB_OK);

return 0;}

 

strcpy(cBuffer, "c:\\Demo_Directory_For_Book_1");

// Создаём первый каталог

if(CreateDirectory(cBuffer, NULL))   MessageBox(NULL,

"Директория c:\\Demo_Directory_For_Book_1 создана!",

"Info", MB_OK);

else { MessageBox(NULL,

"He могу создать директорию c:\\Demo_Directory_For_Book_1",

"Error", MB_OK);

 return 0; }

 

//Делаем только что созданный  каталог текущим.

SetCurrentDirectory(cBuffer);

 

// Создаём в текущем  каталоге файл с именем "File_1.dem"

if(INVALID_HANDLE_VALUE == (hFile =

CreateFile("File_1.dem", GENERIC_READ | GENERIC_WRITE,

   FILE_SHARE_READ |  FILE_SHARE_WRITE,

   NULL,CREATE_NEW,

   FILE_ATTRIBUTE_NORMAL, 0)) )

{MessageBox(NULL,

  "He могу создать файл в директории c:\\Demo_Directory_For_Book_1",

"Error", MB_OK);

  return 0;}

else

//закрываем файл, иначе  будем получать сообщения об  ошибке доступа к файлу.

CloseHandle(hFile);

 

strcpy(cBuffer, "c:\\Demo_Directory_For_Book_2");

//создаем второй каталог

if (CreateDirectory(cBuffer, NULL))

MessageBox(NULL,

"Директория c:\\Demo_Directory_For_Book_2 создана!", "Info", MB_OK);

else

{ MessageBox(NULL,

"He могу создать директорию c:\\Demo_Directory_For_Book_2",

  "Error", MB_OK);

return 0;}

 

//делаем только что созданный  каталог текущим

SetCurrentDirectory(cBuffer);

 

// Создаём в текущем  каталоге файл с именем "File_1.dem"

if(INVALID_HANDLE_VALUE == (hFile =

CreateFile("File_1.dem", GENERIC_READ | GENERIC_WRITE,

   FILE_SHARE_READ |  FILE_SHARE_WRITE,

   NULL,CREATE_NEW,

   FILE_ATTRIBUTE_NORMAL, 0)) )

   {MessageBox(NULL,

  "He могу создать файл в директории c:\\Demo_Directory_For_Book_2",

"Error", MB_OK);

  return 0;}

else

//закрываем файл, иначе  будем получать сообщения 

//об ошибке доступа к  файлу.

CloseHandle(hFile);

 

//Делаем попытку скопировать файл. Файл с таким именем

//уже существует,  поэтому  получаем сообщение об ошибке.

if(!CopyFile("c:\\Demo_Directory_For_Book_1\\File_1.dem",

"c:\\Demo_Directory_For_Book_1\\File_1.dem", TRUE))

MessageBox(NULL, "He могу скопировать файл File_1.dem!", "Error", MB_OK);

 

// Переименовываем файл.

if(!MoveFile("c:\\Demo_Directory_For_Book_1\\File_1.dem",

   "c:\\Demo_Directory_For_Book_1\\File_2.dem"))

{ MessageBox(NULL, "He могу переименовать файл", "Error", MB_OK);

return 0;}

 

//Делаем вторую попытку скопировать файл.

// Файла с таким именем  уже не существует,

// поэтому копирование  происходит успешно.

if(!CopyFile("c:\\Demo_Directory_For_Book_1\\File_2.dem",

"c:\\Demo_Directory_For_Book_2\\File_2.dem", TRUE))

{ MessageBox(NULL, "He могу скопировать файл из1 в 2!", "Error", MB_OK);

return 0;

} else

MessageBox(NULL, "Файл скопирован успешно", "Info", MB_OK);

 

// Делаем попытку удалить  каталог, в котором ещё есть  файлы,

// поэтому получаем сообщение  об ошибке

 

if(!RemoveDirectory("с\\Demo_Directory_For Book_1"))

     MessageBox(NULL,

"He могу  удалить каталог\nВозможно, в нем  ещё есть файлы",

"Error", MB_OK);

 

// Удаляем файлы из второго  каталога.

DeleteFile("c:\\Demo_Directory_For_Book_2\\File_1.dem");

DeleteFile("c:\\Demo_Directory_For_Book_2\\File_2.dem");

 

// Удаляем файл из первого  каталога.

DeleteFile("c:\\Demo_Directory_For_Book_1 \\File_2.dem");

 

// Удаляем первый каталог.

RemoveDirectory("c:\\Demo_pirectory_For_Book_1");

 

// Делаем попытку удалить  текущий каталог

if(!RemoveDirectory("с \\Demo_Directory_For_Book_2"))

MessageBox(NULL,

"He могу удалить каталог\nВозможно, он является текущим",

"Error", MB_OK);

 

// Делаем текущим тот  каталог, который был текущим 

// перед началом работы  программы.

SetCurrentDirectory(cBufferForCurrentDirectory);

 

// Удаляем второй каталог

RemoveDirectory("c:\\Demo_Directory_For_Book_2");

return 1;

}

 

Определение системной и основной директории Windows

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

        UINT GetSystemDirectory(

           LPTSTR lpBuffer,  // указатель на буфер, хранящий имя сист. каталога

           UINT uSize            // размер этого буфера );

В случае успешного завершения функция заполняет буфер и возвращает число байтов, записанных в буфер. В случае ошибки система возвращает 0.

Аналогичным образом можно узнать и имя основной директории Windows :

UINT GetWindowsDirectory(

    LPTSTR lpBuffer,

    UINT uSize );

4.3. Получение информации о дисках  компьютера

Простейшей функцией, определяющей, какие логические диски присутствуют в системе, является функция

DWORD GetLogicalDrives(VOID);

Эта функция без параметров. Значение, которое она возвращает , фактически является логической шкалой. Нулевой (самый младший) бит этой шкалы соответствует диску А, первый бит – диску В, второй – диску –С и так далее.

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

DWORD GetLogicalDriveStrings (DWORD nBufferLenght,

LPSTR lpBuffer);

Первый аргумент  этой функции – длина буфера, который будет заполнен списком корневых каталогов дисков, установленных на компьютере. Второй аргумент – указатель на этот буфер. При успешном завершении функция возвращает количество символов, скопированных в этот буфер. Если возвращаемое значение больше длины буфера, следует увеличить его размер. Если при выполнении функции произошла ошибка, функция возвращает 0.

Данные записываются в буфер в виде строк с завершающими нулями. В конце списка стоит еще один нуль.

Для определения типа дисков используется функция:

UINT GetDriveType (LPCSTR lpRootPathName);

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

Таблица 4.1

Идентификатор

Значение

Назначение

DRIVE_UNKNOWN

0

Тип определить не удалось

DRIVE_NO_ROOT_DIR

1

Корневой директории не существует

DRIVE_REMOVABLE

2

Дисковод со сменным носителем (гибкий диск FDD)

DRIVE_FIXED

3

Дисковод с несменным носителем (жесткий диск НDD)

DRIVE_REMOTE

4

Удаленный дисковод – сетевой диск

DRIVE_CDROM

5

Дисковод для компакт-дисков

DRIVE_RAMDISK

6

Эмулируемый в оперативной памяти диск – RAM-диск


 

Для получения более полной информации о дисках предусмотрена функция :

BOOL GetVolumeInformation (

LPCTSTR lpRootPathName,

LPTSTR lpVolumeNameBuffer,

DWORD nVolumeNameSize,

LPDWORD lpVolumeSerialNumber,

LPDWORD lpMaximumComponentLength,

LPDWORD lpFileSystemFlags,

LPTSTR lpFileSystemNameBuffer,

DWORD nFileSystemNameSize  );

 

Первый аргумент этой функции, lpRootPathName, указывает на наименование корневой директории того диска, информацию о котором мы хотим получить. Если этот параметр равен NULL, используется корневая директория текущего диска.

Второй и третий аргументы функции работают в связке. Второй аргумент, lpVolumeNameBuffer, должен указывать на буфер, в который будет записано имя диска, а третий, nVolumeNameSize, определяет размер этого буфера в байтах.

В переменную, на которую указывает четвёртый аргумент, lpVolumeSerialNumber, функция записывает серийный номер диска. Если, однако, при вызове функции эта переменная будет равна NULL, то система определит, что информация о серийном номере вам не нужна и не станет возвращать её.

Пятый аргумент, lpMaximumComponentLength, указывает на двойное слово, в которое будет записана информация о том, какая максимальная длина имени файла вместе с путём, естественно, допускается в этой системе. Например, в FAT и NTFS это значение будет равно 255.

Шестой параметр, lpFileSystemFlags, указывает на двойное слово, в которое будут записаны флаги, дающие дополнительную информацию о файловой системе. Их перечень  приведен в табл. 4.2 .

Таблица 4.2

Значение

Назначение

FS_CASE_IS_PRESERVED

Если  этот  флаг установлен, то при записи  на диск сохраняется регистр букв в имени файла

FS_CASE_SENSITIVE

Если этот флаг установлен, то файловая система поддерживает поиск файлов с учётом регистра букв в именах

FS_UNICODE_STORED_ON_DISK

Если этот флаг установлен, то файловая система поддерживает  хранение на диске имён файлов в Unicode

FS_PERSISTENT_ACLS

Если этот флаг установлен, то файловая система способна оперировать со списками контроля доступа (ACL) (доступно только в NTFS)

FS_VOL_IS_COMPRESSED

Если этот флаг установлен, то том, информация о котором запрашивается, был подвергнут сжатию (например, DoubleSpace)

FS_FILE_COMPRESSION

Если этот флаг установлен, то файловая система поддерживает сжатие файлов


 

Седьмой параметр, lpFileSystemNameBuffer, указывает на буфер, в который будет записано название файловой системы, такое как FAT, HPFS или NTFS. Если этот параметр при вызове функции равен NULL, то операционная система не будет возвращать имя файловой системы.

Последний, восьмой параметр, nFileSystemNameSize, определяет размер буфера, предназначенного для имени файловой системы. Если предыдущий аргумент равен NULL, то этот аргумент игнорируется.

Информация о работе Системное программирование в среде Win32