Работа со звуковыми файлами в Windows
Основные принципы мультимедийной файловой подсистемы
Информационная структура файла
Информационная структура файла
Установленные и явные процедуры обмена
Структура звуковых файлов RIFF/WAVE
Типовые схемы применения средств MMIO
Чтение/запись без использования явного буфера
Чтение/запись с явной буферизацией
Использование собственных процедур обмена
Структуры, используемые в MMIO
MMCKINFO — описатель раздела файла
MMIOINFO — информационная структура файла
MAKEFOURCC и mmioFOURCC — формирование кода FOURCC
StringToFOURCC — преобразование строки в код FOURCC
Flush — принудительная запись буфера на диск
Seek — позиционирование в файле
Функции управления буферизацией
GetInfo — запрос копии информационной структуры файла
SetInfo — установка системной информационной структуры файла
SetBuffer — установка буфера файла
Advance — продвижение по файлу в режиме явной буферизации
CreateChunk — создание раздела
Descend — вход в существующий раздел
SendMessage — посылка произвольного сообщения
InstallIOProc — установка локальной процедуры обмена
IOProc — прототип функции для процедуры обмена
Пример программы, использующей MMIO
Введение
Наряду с базовой подсистемой файлового ввода/вывода, представленной функциями CreateFile, ReadFile, WriteFile и т.п., в Windows существует подсистема мультимедийного (звукового, видео и другого подобного) файлового ввода/вывода MMIO (Multimedia Input/Output). Подсистема была введена еще в Windows 3.x; она позволяет удобно и эффективно работать со звуковыми и видеофайлами, а также упрощает работу с файлами, размещенными в оперативной памяти (memory files).Эта статья посвящена работе со звуковыми файлами с использованием программного интерфейса MMIO.
Основные принципы мультимедийной файловой подсистемы
Файлы типа RIFF
Подсистема может оперировать двоичными файлами любого типа, однако она содержит стандартные средства для работы с файлами типа RIFF (Resource Interchange File Format — формат файла обмена ресурсами). Фирмы Microsoft и IBM предложили этот формат в качестве универсального средства организации и хранения данных с иерархическо-последовательной структурой в системах Windows и OS/2.
Структуру RIFF имеют файлы типа WAV (поток оцифрованного звука), IDF (описатель MIDI-инструмента), AVI (поток оцифрованного изображения и звука), ANI (описатель «оживленного», то есть (анимированного) курсора мыши), RMI (один из видов MIDI-партитуры) и многие другие. Creative Labs использует формат RIFF в файлах типа CSP (программы для специализированного звукового процессора ASP звуковых адаптеров Sound Blaster) и SBK/SF2 (загружаемых банков инструментов для звуковых адаптеров классов Sound Blaster AWE и Live!). Универсальный формат загружаемых банков инструментов DLS (DownLoadable Sounds), принятый в качестве стандарта ассоциацией производителей MIDI-систем (MMA — MIDI Manufacturers Association), построен на основе RIFF. Фирма Aureal применяет этот формат для построения загружаемых банков инструментов для своих звуковых чипов.
Структура RIFF-файлов допускает непосредственную запись со звукового или видеоустройства в файл, а также непосредственное воспроизведение материала из файла.
Разделы RIFF-файлов
Файлы типа RIFF состоят из разделов (chunk – «кусок»). Раздел содержит набор данных определенного типа. Большая часть разделов непосредственно представляет наборы данных, однако некоторые разделы содержат внутри себя подразделы (subchunks), которые представляют собственно поток данных, его параметры, формат и т.п. Охватывающий раздел в этом случае называется главным, или родительским (parent chunk).
Существует два типа главных разделов — RIFF (основной раздел файла) и LIST (список из произвольного количества подразделов). Раздел RIFF всегда является первым и единственным в файле; раздел LIST может входить в любой раздел в качестве подраздела.
Поскольку раздел и подраздел в RIFF-файле имеют одинаковый вид, мы будем в основном пользоваться термином «раздел», уточняя его лишь в том случае, когда отношение подчиненности имеет значение.
Каждый раздел состоит из заголовка (chunk header), содержащего код типа раздела и его размер, и из области данных (chunk data), представляющей собственно содержимое раздела. Поле размера в заголовке содержит размер только области данных; заголовок всегда состоит из двух двойных слов (DWORD) и имеет размер 8 байтов.
Каждый раздел располагается на границе слова (имеет четное смещение относительно начала файла). Общий размер раздела также должен быть четным; если содержащийся в нем блок данных имеет нечетный размер, он дополняется нулевым байтом. При этом поле размера блока данных в заголовке раздела содержит реальный размер блока; байт-заполнитель не учитывается.
Для каждого типа данных в файле есть обязательные и факультативные (optional) разделы; последние включаются в файл только при необходимости.
Код FOURCC
Для обозначения типов разделов, а также в некоторых других целях используется специальный четырехсимвольный код FOURCC (Four-Character Code). Этот код представляет собой строку из четырех (или менее) алфавитно-цифровых символов, сформированную из текстового названия объекта и дополненную справа до полной длины пробелами. Регистр букв в строке кода является значимым, все сравнения выполняются буквально, регистрозависимым методом.
Фактически числовое значение четырехсимвольного кода представляет собой четырехбайтовое, 32-разрядное значение типа DWORD, которое образует в памяти заданная строка. Например, код раздела «fmt» в памяти записывается тремя байтами — 0x66, 0x6D, 0x74, 0x20 (четвертый символ — пробел). Числовое значение слова, образованного этими четырьмя байтами, будет равно 0x20746D66, поскольку в процессорах Intel принято расположение в памяти байтов от младшего к старшему. По этой причине четырехсимвольные коды нельзя представлять обычными символьными константами языка C — числовое значение константы 'fmt ' будет равно 0x666D7420. Для формирования четырехсимвольных кодов в Windows имеются функции-макросы MAKEFOURCC и mmioFOURCC.
Для кодов главных разделов определены константы FOURCC_RIFF и FOURCC_LIST.
Типы главных разделов
Главные разделы типа RIFF и LIST бывают различных типов, образуя разного рода формы (RIFF form) и списки (list). Форма или список представляет собой раздел RIFF или LIST, первое двойное слово (DWORD) области данных которого содержит код формы/списка в формате FOURCC. Остальное содержимое области данных представляет собой собственно данные формы или списка и обычно состоит из одного или нескольких подразделов.
Каждый RIFF-файл представляет собой одну RIFF-форму, которая содержит набор данных определенного типа — оцифрованный звук, изображение, видеоролик, MIDI-партитуру и т.п. Таким образом, каждый RIFF-файл имеет структуру:
Смещение в файле |
Содержимое |
0 |
Заголовок раздела RIFF (два двойных слова) |
8 |
Тип формы (одно двойное слово) |
12 |
Область подразделов (переменная длина) |
Поле размера раздела RIFF в его заголовке содержит суммарный размер всех подразделов плюс размер двойного слова, содержащего тип формы (четыре байта). В правильно оформленном RIFF-файле поле размера раздела RIFF равно общему размеру файла минус размер RIFF-заголовка (восемь байтов).
В этой статье описывается только структура файлов типа WAVE, код типа формы для которого также представляется строкой «WAVE».
Ключи мультимедийных файлов
Как и в случае обычных файлов Windows, для доступа к мультимедийному файлу используется его ключ — числовое значение, возвращаемое функцией mmioOpen. Фактически ключ файла представляет собой указатель системного описателя файла, расположенного в памяти подсистемы MMIO.
Ключи обычных и мультимедийных файлов несовместимы между собой, однако уже открытый обычный файл можно повторно открыть в подсистеме MMIO, передав его ключ (типа HANDLE) функции mmioOpen.
Информационная структура файла
Для каждого открытого файла подсистема MMIO поддерживает информационную структуру, описывающую режимы работы с файлом и его параметры. Базовая информационная структура находится внутри самой подсистемы MMIO; приложение может поддерживать собственную локальную копию типа MMIOINFO в своей собственной области памяти. Некоторые функции MMIO требуют от приложения указания локальной структуры MMIOINFO и управляют полями структур таким образом, чтобы отразить операции, выполненные как приложением, так и самой подсистемой MMIO. Приложение также может непосредственно запросить копию системной структуры функцией mmioGetInfo и модифицировать системную структуру функцией mmioSetInfo.
Буферизация файлового обмена
Обмен информацией с файлом может быть непосредственным или буферизованным.
Непосредственный обмен подразумевает прямое чтение информации с диска и запись ее обратно на диск. Он эффективен в том случае, когда обмен с файлом идет большими (несколько килобайт или больше) блоками данных, размеры которых кратны размеру сектора диска (обычно 512 байтов), и сами блоки начинаются также на границе сектора. При обмене мелкими (несколько десятков или сотен байтов) или некратными сектору блоками резко возрастают накладные расходы.
При буферизованном обмене между приложением и файлом находится так называемый буфер файла. При чтении из файла вначале неявно считывается полный буфер, а последующие функции чтения выбирают нужные порции данных из буфера, не обращаясь при этом к диску. При записи все работает наоборот: функции записи вначале заполняют буфер, а затем полностью записанный буфер неявно переносится в файл одной операцией записи.
Строго говоря, в MMIO даже непосредственный обмен с файлом включает простую скрытую буферизацию в самой подсистеме, так как минимальной единицей обмена данными с диском является сектор.
Скрытая и явная буферизация
Буферизация файлов в MMIO может быть скрытой и явной.
Скрытая буферизация работает так же, как и в базовом файловом обмене: файловая подсистема создает буфер, через который проходят все операции чтения/записи, выполняемые приложением. Работа буфера в этом случае приложению не видна, однако возможны накладные расходы при пересылке данных между буферами приложения и файлов.
При явной буферизации приложение имеет непосредственный доступ к буферу для чтения и записи. В этом случае оно самостоятельно заносит данные в буфер при записи и извлекает их при чтении. Для уведомления файловой подсистемы об изменении состояния буфера служит функция продвижения по файлу, которая корректирует рабочие указатели буфера и при необходимости выполняет непосредственный обмен буфера с файлом.
Как при скрытой, так и при явной буферизации приложение может полностью управлять и размером буфера, и местом его размещения в памяти.
Текущая позиция в буфере
При работе с буферизованным файлом используется понятие указателя текущей позиции буфера. В начале работы указатель устанавливается на начало буфера и в процессе считывания или записи данных движется в сторону его конца. При достижении конца буфера или специального ограничителя содержимое буфера записывается в файл либо обновляется из него, и указатель текущей позиции снова возвращается в начало буфера.
Вместе с указателем текущей позицией файловая подсистема использует два специальных ограничителя буфера — ограничитель чтения и ограничитель записи, которые являются «барьерами» для указателя текущей позиции. Фактически оба ограничителя представляют собой указатели, ссылающиеся на байты сразу за концом области буфера, доступной для чтения и записи соответственно. Таким образом, последним доступным для чтения или записи является адрес, на единицу меньший, чем значение соответствующего ограничителя. Размер доступной для чтения или записи области определяется разностью соответствующего ограничителя и указателя текущей позиции.
Текущая позиция буфера не имеет никакого отношения к текущей позиции самого файла. Позиция в файле изменяется только при операциях непосредственного обращения к файлу, позиция буфера — при работе с буфером. Текущие позиции буфера и ограничителей находятся в информационной структуре файла.
Файлы в оперативной памяти
Вместо внешнего устройства файл может находиться в оперативной памяти. Механизм виртуальной памяти Windows позволяет таким файлам иметь практически любой размер, ограниченный лишь объемом доступного на диске пространства для файла подкачки (swapfile).
Размещение файла в памяти позволяет максимально быстро работать с данными, используя обычный файловый интерфейс, что в ряде случаев может быть удобнее, чем использование стандартных средств управления памятью Windows.
Файл, размещаемый в памяти, на самом деле состоит из одного лишь буфера, размер которого увеличивается по мере записи в файл. Стандартная процедура обмена для файлов в памяти управляет указателем текущей позиции, ограничителями чтения/записи и размером буфера, что с точки зрения приложения неотличимо от работы с реальным дисковым файлом.
Процедуры обмена данными
Файловые функции MMIO на самом деле являются промежуточными. Весь фактический обмен с файлом выполняют так называемые процедуры обмена (I/O Procedures). Стандартные процедуры обмена обслуживают файлы на дисковых устройствах и в оперативной памяти; пользовательские процедуры могут обслуживать файлы на любом носителе и даже полностью виртуальные файлы, не имеющие физического представления.
Обращения приложения к файловым функциям MMIO транслируются подсистемой в сообщения к соответствующей процедуре обмена, которая выполняет запрос и возвращает соответствующий код результата.
Можно сказать, что процедура обмена как оконечный интерфейс определяет среду хранения (storage system) файла.
Установленные и явные процедуры обмена
Процедуры обмена могут быть установленными и явными. Установленная процедура вносится во внутренний список подсистемы MMIO и снабжается собственным уникальным символьным кодом, по которому она может быть найдена и подключена к открываемому файлу. Явная процедура задается непосредственно своим указателем при открывании файла и не имеет собственного кода.
В подсистеме MMIO имеются две стандартные процедуры обмена: DOS — интерфейс с дисковыми устройствами, и MEM — интерфейс с оперативной памятью для файлов в памяти. Их коды определяются константами FOURCC_DOS и FOURCC_MEM.
Глобальные и локальные процедуры обмена
Установленные процедуры обмена делятся на глобальные и локальные. Глобальные процедуры доступны всем процессам системы, локальные — только установившему их процессу. Поиск процедуры по коду начинается со списка локальных процедур, которые в этом случае имеют приоритет.
Разделение процедур обмена между процессами возможно только в Win16; в Win32 оно приводит к непредсказуемым результатам.
Структура звуковых файлов RIFF/WAVE
Файлы типа RIFF/WAVE служат для хранения оцифрованных звуковых потоков в различных звуковых форматах — PCM, ADPCM, a-Law, GSM, Audio MPEG и т.п. Стандартное расширение для файлов этого типа — WAV.
Минимальный состав WAVE-формы включает два подраздела: формата и данных. Раздел формата имеет код «fmt» и содержит описатель формата звуковых данных в виде расширенной структуры WAVEFORMATEX. Раздел данных состоит либо из одного подраздела «data», содержащего единый поток звуковых данных в цифровом виде, либо из подраздела-списка «wavl», содержащего последовательность из подразделов «data» и «slnt» (silent — «тихий»). Каждый подраздел «data» задает отдельный фрагмент звучания, подраздел «slnt» — фрагмент тишины (паузу) заданной длительности.
Для форматов, отличных от PCM, и в случае использования списка «wavl» после раздела «fmt» вставляется дополнительный раздел «fact». Первое двойное слово (DWORD) области данных раздела «fact» содержит общее количество звуковых отсчетов (samples) в файле. При помощи этого параметра можно определить время воспроизведения файла, поделив количество отсчетов на значение поля nSamplesPerSec в описателе формата, или вычислить объем, который поток займет после восстановления в PCM, умножив количество отсчетов на значение поля nBlockAlign в описателе выбранного для восстановления формата PCM.
В настоящее время область данных раздела «fact» включает только описанное поле, однако в будущем она может быть расширена добавлением дополнительных полей. Это необходимо иметь в виду, ориентируясь на размер области данных раздела, указанный в его заголовке. По размеру области данных можно узнать о наличии в разделе полей расширения.
В качестве необязательных элементов звукового файла перед разделом данных могут присутствовать разделы «cue» (список «флажков», или «закладок» внутри звукового потока — cue points), «plst» (порядок воспроизведения фрагментов — playlist), «adtl» (раздел типа «LIST», разная дополнительная информация о файле — associated data list) и т.п. Однако полное и подробное описание возможной структуры звукового файла выходит за рамки данной статьи.
Программирование MMIO
Для программирования ACM необходим любой стандартный SDK (Win16 или Win32), содержащий файлы заголовка MMSYSTEM.H и библиотеки WINMM.LIB.
Типовые схемы применения средств MMIO
Открытие/закрытие файла
При открытии файла функцией mmioOpen указываются необходимые виды доступа, режимы совместного использования и буферизации. Функция открывания дискового файла в MMIO в конечном счете раскрывается в базовые функции открывания файла Windows, поэтому подробности о режимах открытия и совместного использования файлов можно получить из описания функции CreateFile.
Возможно использование в подсистеме MMIO уже открытого базового файла Windows; для этого предусмотрен частный случай использования функции mmioOpen.
При открытии файла либо впоследствии для него может быть установлен режим буферизации функцией mmioSetBuffer. В зависимости от набора функций, используемых для чтения/записи, буферизация может быть скрытой или явной.
После завершения работы с файлом он должен быть закрыт функцией mmioClose. Если файл был принят для обработки в MMIO посредством передачи ключа открытого базового файла Windows, – базовый файл также будет закрыт, если в функции mmioClose не указан соответствующий флаг.
Чтение/запись без использования явного буфера
В этом режиме работа с файлом происходит точно так же, как в базовой файловой подсистеме Windows или встроенных средствах поддержки файлов языка C. Сразу после открытия файла для чтения/записи доступны функции mmioRead/mmioWrite, для смены позиции – функции mmioSeek. Для того чтобы гарантированно записать в файл содержимое внутренних буферов, применяется функция mmioFlush.
Чтение/запись с явной буферизацией
Обработка файла с явной буферизацией может начинаться в любое время – сразу после открытия, либо после частичной обработки в обычных режимах. Перед началом обработки с явной буферизацией приложение должно любым из способов, предусмотренных в MMIO, задать буфер для файла. Затем приложение запрашивает копию информационной структуры файла функцией mmioGetInfo, после чего приступает к работе с буфером, используя указатели позиций буфера в полях pchNext, pchEndRead, pchEndWrite.
Если данные в буфере изменяются при записи или модификации буфера, – приложение должно установить флаг DIRTY в слове флагов информационной структуры. При достижении конца буфера вызывается функция mmioAdvance, продвигающая буфер по файлу и соответствующим образом изменяющая указатели позиций.
Сеанс обработки файла в буферизованном режиме завершается вызовом функции mmioSetInfo, окончательно фиксирующей текущее состояние буфера в файле. После этого обработка файла может быть продолжена в обычном режиме.
Функция mmioSetInfo вызывается также в том случае, когда необходима фактическая запись на диск еще не заполненного буфера; при этом должен быть установлен флаг DIRTY.
Перед использованием функций работы с разделами RIFF-файл должен находиться в обычном режиме. Например, существующий файл открывается в обычном режиме, затем функциями mmioDescend в нем находятся нужные разделы, после чего файл переводится в режим явной буферизации и считывается в этом режиме.
Формирование RIFF-файла
В созданном или открытом для перезаписи файле при помощи функции mmioCreateChunk создаются необходимые разделы и подразделы, заполняются данными в любом из режимов буферизации, после чего разделы закрываются функцией mmioAscend.
Чтение RIFF-файла
Для открытого файла вызывается функция mmioDescend, выполняющая поиск нужного раздела или подраздела, затем данные найденных разделов считываются и обрабатываются в любом из режимов буферизации.
Использование собственных процедур обмена
Если приложение поддерживает собственные устройства и методы хранения данных и хочет использовать для них функции MMIO, оно может установить собственные процедуры обмена для этих файлов функцией mmioInstallIOProc, после чего работать с файлами посредством любых функций MMIO. Например, таким образом удобно работать с RIFF-файлами на нестандартных носителях информации.
Структуры, используемые в MMIO
MMCKINFO — описатель раздела файла
Описывает раздел файла типа RIFF. Первые три поля структуры представляют собой заголовок раздела в том же виде, в котором он присутствует в файле; поле fccType присутствует только в заголовках главных разделов.
FOURCC ckid; DWORD cksize; FOURCC fccType; DWORD dwDataOffset; DWORD dwFlags;
- ckid — код (идентификатор) раздела.
- cksize — размер области данных раздела в байтах. Поле отражает точный размер области данных; в него не входит размер заголовка и возможный дополнительный байт, автоматически дописываемый к области данных нечетного размера.
- fccType — тип главного раздела, если в поле ckid указан код «RIFF» и «LIST».
- dwDataOffset — смещение области данных раздела относительно начала файла. Значение этого поля удобно использовать в функции mmioSeek для позиционирования на начало области данных.
- dwFlags — флаги состояния раздела. На данный момент определен единственный флаг MMIO_DIRTY, означающий, что заголовок раздела в файле (поле cksize) должно быть обновлено, например, после изменения размера области данных раздела. Этот флаг устанавливается функцией mmioCreateChunk и анализируется функцией mmioAscend, которая корректирует поле длины в заголовке в соответствии с реальным размером области данных.
MMIOINFO — информационная структура файла
Описывает состояние открытого файла, его буфера и процедуры обмена данными.
DWORD dwFlags; FOURCC fccIOProc; LPMMIOPROC pIOProc; UINT wErrorRet; HTASK hTask; LONG cchBuffer; HPSTR pchBuffer; HPSTR pchNext; HPSTR pchEndRead; HPSTR pchEndWrite; LONG lBufOffset; LONG lDiskOffset; DWORD adwInfo [4]; DWORD dwReserved1; DWORD dwReserved2; HMMIO hmmio;
- dwFlags — режимы открытия/опроса и флаги состояния файла, копируемые из параметра Mode функции mmioOpen. Дополнительно определены следующие константы, имеющие префикс MMIO_:
DIRTY |
Флаг, показывающий, что содержимое буфера было изменено и требует записи на диск. Устанавливается либо MMIO — при скрытой буферизации, либо приложением — при явной буферизации. Сбрасывается MMIO после фактической записи буфера на диск. |
RWMODE |
Битовая маска, включающая все флаги вида доступа к файлу. |
SHAREMODE |
Битовая маска, включающая все флаги режимов совместного доступа к файлу. |
- fccIOProc — код установленной процедуры обмена. Если функция не является установленной, поле имеет нулевое значение. Для файлов универсальной структуры стандартная функция обмена имеет код «DOS».
- pIOProc — указатель процедуры обмена. Если приложение не использует процедуру обмена, в этом поле находится указатель стандартной процедуры обмена файловой подсистемы.
- wErrorRet — код ошибки, возвращаемый при неудачном завершении функции mmioOpen.
- hTask — ключ задачи (task), созданной для процедуры обмена.
- cchBuffer — размер буфера файла. Для файлов без буфера поле имеет нулевое значение.
- pchBuffer — указатель буфера файла. Для файлов без буфера поле имеет нулевое значение.
- pchNext — указатель текущей позиции в буфере.
- pchEndRead — ограничитель чтения в буфере.
- pchEndWrite — ограничитель записи в буфере.
- lBufOffset — зарезервированное поле для служебного использования.
- lDiskOffset — текущее смещение внутри файла. Поле управляется процедурами обмена.
- adwInfo — дополнительная информация, используемая процедурами обмена. Используется также для передачи дополнительных данных при открывании файла.
- dwReserved1, dwReserved2 — зарезервированные поля.
- hmmio — ключ открытого файла.
Функции MMIO
Классы функций
Средства мультимедийной файловой подсистемы включают три основных класса функций:
- базовые - открытие, закрытие, чтение и запись файлов. Этот класс практически аналогичен стандартным средствам работы с файлами языка C.
- управления буферизацией — создание или установка промежуточного буфера и манипуляции с ним, а также — с текущей позицией буфера.
- работы с форматом RIFF — операции с файлами универсального формата RIFF.
Все функции интерфейса имеют имена с префиксом mmio. В заголовке описания каждой функции этот префикс опущен; полное имя каждой функции приведено в ее прототипе.
Большая часть функций получает параметром ключ открытого файла. Такие функции имеют в прототипе параметр File типа HMMIO. В целях экономии места этот параметр не описывается в каждом из описаний функций.
Перечень базовых функций
mmioStringToFOURCC |
Преобразование строки ASCIZ в код FOURCC |
mmioOpen |
Открытие или опрос файла |
mmioClose |
Закрытие файла |
mmioRename |
Переименование файла |
mmioRead |
Чтение из файла |
mmioWrite |
Запись в файл |
mmioSeek |
Позиционирование по файлу |
Перечень функций управления буферизацией
mmioGetInfo |
Запрос информационной структуры файла |
mmioSetInfo |
Модификация информационной структуры файла |
mmioSetBuffer |
Установка буфера для файла |
mmioAdvance |
Продвижение по файлу |
mmioFlush |
Принудительная запись буфера в файл |
Перечень функций работы с форматом RIFF
mmioCreateChunk |
Создание раздела |
mmioAscend |
Выход из раздела |
mmioDescend |
Вход в раздел |
Перечень остальных функций интерфейса
mmioSendMessage |
Посылка произвольного сообщения процедуре обмена |
mmioInstallIOProc |
Установка процедуры обмена |
IOProc |
Прототип процедуры обмена |
Возвращаемые значения
Для функций, возвращающих значения типа MMRESULT, а также для ряда других, определены константы кодов завершения с префиксами MMSYSERR_ и MMIOERR_. Константы первой группы были описаны в статье «Низкоуровневое программирование звука в Windows»), константы второй группы перечислены в таблице:
FILENOTFOUND |
Файл не найден |
OUTOFMEMORY |
Недостаточно памяти |
CANNOTOPEN |
Невозможно открыть файл |
CANNOTCLOSE |
Невозможно закрыть файл |
CANNOTREAD |
Невозможно прочитать из файла |
CANNOTWRITE |
Невозможно записать в файл |
CANNOTSEEK |
Невозможно позиционировать файл |
CANNOTEXPAND |
Невозможно расширить файл |
CHUNKNOTFOUND |
Раздел не найден |
UNBUFFERED |
Файл открыт для непосредственного доступа |
PATHNOTFOUND |
Недопустимый путь (устройство и/или каталог) |
ACCESSDENIED |
Доступ к файлу запрещен |
SHARINGVIOLATION |
Нарушение условий совместного доступа |
NETWORKERROR |
Ошибка сетевой подсистемы |
TOOMANYOPENFILES |
Нет свободных описателей ключей для нового файла |
INVALIDFILE |
Общая ошибка, неудача по неизвестной причине |