Работа со звуковыми файлами в Windows

Базовые функции

MAKEFOURCC и mmioFOURCC — формирование кода FOURCC

Эти два макроса формируют 32-разрядное значение типа FOURCC (DWORD) из четырех заданных символов (значений типа char):

MAKEFOURCC (ch0, ch1, ch2, ch3)
mmioFOURCC (ch0, ch1, ch2, ch3)

Оба макроса полностью идентичны – mmioFOURCC определяется через MAKEFOURCC. Результатом вызова любого из макросов является «склейка» четырех символьных значений в одно 32-разрядное:

mmioFOURCC ('c', 'u', 'e', ' ') преобразуется в 0x20657563

В начало

В начало

StringToFOURCC — преобразование строки в код FOURCC

Преобразует заданную строку ASCIZ в код FOURCC.

FOURCC mmioStringToFOURCC (
  LPCSTR Str,
  UINT Flags
);
  • Str — исходная строка ASCIZ, содержащая сочетание символов кода.
  • Flags — флаги режимов преобразования. Определен единственный флаг MMIO_TOUPPER, при наличии которого преобразуемые символы приводятся к верхнему регистру.

Функция формирует из заданной строки соответствующий четырехсимвольный код, при необходимости дополняя строку пробелами либо отбрасывая лишние символы. Например, результатом преобразования строки «fmt» будет числовое значение 0x20746D66.

В начало

В начало

Open — открывание файла

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

HMMIO mmioOpen (
  LPSTR FileName,
  MMIOINFO *Info,
  DWORD Mode
);
  • FileName — строка имени файла. Вопреки тому, что стандартное описание ограничивает эту строку 128 символами, фактически воспринимается 238 символов пути. Возможно три варианта установки этого поля:
    • Обыкновенное имя, не содержащее знака «+». В этом случае открывается обычный двоичный файл со стандартной процедурой обмена, формат которого будет определяться приложением.
    • Структурное имя в формате «имя.тип+элем». В этом случае открываемому файлу автоматически назначается процедура обмена, выбираемая по указанному типу, а внутри файла открывается указанный элемент данных.
    • Нулевое значение — в случае открытия файла в памяти либо стандартного файла Windows по его ключу типа HANDLE.
  • Info — указатель локальной информационной структуры файла типа MMIOINFO. Задается в тех случаях, когда открывается файл в памяти, файл с не установленной процедурой обмена, либо приложение самостоятельно задает параметры буферизации файла. В этих случаях все поля структуры, кроме явно заданных, должны быть нулевыми. В остальных случаях параметр должен иметь нулевое значение.
  • Mode — флаги режимов открытия/опроса и флаги, уточняющие способ открытия файла. Имена констант для значений имеют префикс MMIO_.

Флаги режимов открывания

CREATE

Запрашивает создание нового файла либо усечение существующего файла до нулевого размера.

DELETE

Запрашивает удаление существующего файла. При успешном завершении возвращается TRUE, в противном случае — FALSE. Этот режим перекрывает все остальные режимы открытия файла.

ALLOCBUF

Запрашивает автоматическое выделение буфера для файла. Если указатель информационной структуры не задан либо ее поле cchBuffer имеет нулевое значение, выделяется буфер размером MMIO_DEFAULTBUFFER (8 Кбит), в противном случае поле cchBuffer задает размер выделяемого буфера.

Коды режимов опроса, без фактического открывания файла

PARSE

Запрашивает возврат полного имени (пути) для заданного имени файла. Существование самого файла не проверяется. При успешном завершении функция возвращает значение TRUE; в противном случае возвращается значение FALSE.

EXIST

Аналогично PARSE, но проверяется существование заданного файла.

GETTEMP

Запрашивает формирование уникального имени для временного файла. Временное имя дописывается к исходной строке имени. Функция возвращает нулевое значение при успешном завершении и значение MMIOERR_FILENOTFOUND — при неудаче. Этот флаг перекрывает все остальные флаги режима опроса.

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

Флаги вида доступа (access mode)

READ

Файл открывается только для чтения.

WRITE

Файл открывается только для записи.

READWRITE

Файл открывается для чтения и записи одновременно.

Флаги режимов разделяемого доступа (sharing mode)

COMPAT

Совместимый режим (compatibility mode), не накладывающий ограничений на одновременное открытие файла другими процессами в таком же совместимом режиме.

DENYNONE

Другим процессам разрешаются все операции с этим файлом.

DENYREAD

Другим процессам запрещаются операции чтения с этим файлом.

DENYWRITE

Другим процессам запрещаются операции записи с этим файлом.

EXCLUSIVE

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

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

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

  • Для подключения нужной процедуры обмена необходимо установить либо код установленной процедуры в поле fccIOProc, либо указатель явной процедуры в поле pIOProc.
  • Для подключения установленной процедуры обмена, определяемой символьным кодом, необходимо установить оба вышеописанных поля в нулевые значения. При этом строка имени файла должна иметь вид «имя.тип+элем», где тип — расширение файла (1..4 символа), определяющее одну из установленных процедур, а элем — элемент внутри структуры файла, который необходимо открыть.
  • Для открытия файлов в памяти в поле fccIOProc должен быть задан код стандартной процедуры обмена для оперативной памяти — FOURCC_MEM. Поле cchBuffer в этом случае задает начальный размер буфера файла, а поле adwInfo [0] — величину приращения размера буфера при его расширении. По умолчанию содержимое буфера файла доступно для операций чтения (ограничитель pchEndRead в информационной структуре находится за концом буфера); чтобы файл открывался «пустым» (ограничитель pchEndRead установлен на начало буфера) — необходимо указать флаг CREATE в параметре Mode.
  • Чтобы буфер для файла в памяти создавался автоматически, поле pchBuffer должно иметь нулевое значение. Если значение поля отлично от нуля, — оно трактуется как адрес буфера, предоставленного приложением. В этом случае, если задана величина приращения в поле adwInfo [0], MMIO использует для расширения функцию GlobalReAlloc. Эта функция может работать только с областями памяти, адреса которых получены посредством функций GlobalAlloc / GlobalLock. В Win32 нет различий между глобальными и локальными функциями динамической памяти, поэтому память для буфера может выделяться функциями LocalAlloc / LocalLock. Если буфер получен другим способом, величина приращения должна быть нулевой, и расширение буфера должно выполняться самим приложением.
  • Для открывания посредством MMIO уже открытого стандартного файла Windows, ключ которого имеет тип HANDLE, значение ключа заносится в поле adwInfo [0]. В этом случае поле fccIOProc должно иметь значение FOURCC_DOS, а поле pchBuffer — нуль. MMIO будет работать со стандартным файлом посредством функций ReadFile, WriteFile и т.п.

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

Если был запрошен один из других режимов, — возвращается соответствующее значение, приведенное к типу HMMIO.

Локальная информационная структура файла, передаваемая параметром Info, служит только для передачи параметров в функцию, которая устанавливает значения внутренней информационной структуры MMIO. Никакие поля локальной структуры, включая указатель текущей позиции и ограничители чтения/записи, не заполняются функцией. Для получения копии текущего значения структуры необходимо использовать функцию mmioGetInfo.

В начало

В начало

Close — закрытие файла

Закрывает файл, открытый функцией mmioOpen, либо завершает работу со стандартным файлом Windows, повторно открытым функцией mmioOpen.

MMRESULT mmioClose (
  HMMIO File,
  UINT Flags
);
  • Flags — флаги режимов закрывания файла. Определен единственный флаг MMIO_FHOPEN, который должен быть указан при завершении работы с повторно открытым стандартным файлом Windows. В этом случае стандартный файл остается доступен по своему «родному» ключу типа HANDLE, в противном случае стандартный файл закрывается.

Если буфер файла помечен как требующий дозаписи на диск, функция неявно вызывает mmioFlush. Если в процессе работы mmioFlush возникает ошибка (например, переполнение диска), — код ошибки будет возвращен функцией mmioClose.

После успешного завершения mmioClose ключ File становится недоступным, и обращение к нему приведет к ошибке.

В начало

В начало

Rename — переименование файла

Переименует заданный файл.

MMRESULT mmioRename (
  LPCSTR Name,
  LPCSTR NewName,
  const MMIOINFO *Info,
  DWORD Reserved
);
  • Name — строка имени исходного файла.
  • NewName — строка нового имени файла.
  • Info — указатель локальной информационной структуры файла. Роль этой структуры в операции переименования неясна, документация требует либо нулевого значения этого параметра, либо нулевых значений «неиспользуемых полей». Какие именно поля используются и каким образом — в документации не сказано, поэтому лучше всего оставлять этот параметр нулевым.
  • Reserved — зарезервированный параметр; должен иметь нулевое значение.

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

В начало

В начало

Read — чтение из файла

Считывает из файла указанное количество байтов.

LONG mmioRead (
   HMMIO File,
   char *Buffer,
   LONG Size
 );
  • Buffer — указатель области памяти, в которую считываются данные из файла.
  • Size — размер считываемой порции данных в байтах.

Функция возвращает размер реально считанной и занесенной в буфер порции данных. Если данных в файле больше нет (достигнут конец файла) — возвращается нулевое значение. При ошибке чтения возвращается —1.

В начало

В начало

Write — запись в файл

Записывает в файл указанное количество байтов.

LONG mmioWrite (
   HMMIO File,
   const char *Data,
   LONG Size
 );
  • Data — указатель области памяти, содержащей записываемую порцию данных.
  • Size — размер порции данных в байтах.

Возвращается количество реально записанных в файл байтов, либо —1 в случае ошибки.

Успешное завершение функции означает, что данные успешно перенесены в скрытый внутренний буфер файла, поддерживаемый MMIO. Непосредственно в файл записываются только полные буферы, остаток данных остается в буфере до вызова функций mmioFlush или mmioClose.

В начало

В начало

Flush — принудительная запись буфера на диск

Служит для принудительной записи скрытого системного буфера файла на диск.

MMRESULT mmioFlush (
   HMMIO File,
   UINT Flags
 );
  • Flags — управляющие флаги операции. Флаг MMIO_EMPTYBUF требует аннулирования содержимого буфера (пометки буфера как пустого) после записи. Это означает, что последующая операция чтения того же участка файла, данные которого содержались в буфере на момент вызова mmioFlush, вызовет повторное считывание данных из файла в буфер.

Функция используется, когда приложение хочет быть уверенным, что все данные, записанные ранее функцией mmioWrite, на самом деле записаны в файл, а не остались в скрытом промежуточном буфере. При успешном завершении mmioFlush содержимое буфера записывается в файл.

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

В начало

В начало

Seek — позиционирование в файле

Перемещает текущую позицию файла в заданное место.

LONG mmioSeek (
   HMMIO File,
   LONG Offset,
   int Origin
 );
  • Offset — смещение в байтах относительно заданной точки. Может быть положительным, нулевым, либо отрицательным.
  • Origin — точка, относительно которой выполняется позиционирование. Возможно три варианта задания исходной точки:
    • SEEK_SET — начало файла
    • SEEK_CUR — текущая позиция в файле
    • SEEK_END — конец файла (точка за последним записанным байтом в файле).

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

Функция часто используется для получения длины файла — путем позиционирования на 0 байтов относительно конца файла; возвращаемое значение при этом представляет длину файла в байтах.

В начало

В начало

Функции управления буферизацией

GetInfo — запрос копии информационной структуры файла

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

MMRESULT mmioGetInfo (
   HMMIO File,
   MMIOINFO *Info,
   UINT Reserved
 );
  • Info — указатель области памяти для локальной копии информационной структуры, типа MMIOINFO.
  • Reserved — зарезервированный параметр; должен иметь нулевое значение.

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

В начало

В начало

SetInfo — установка системной информационной структуры файла

Передает данные из локальной копии информационной структуры файла, поддерживаемой приложением, в системную структуру MMIO.

MMRESULT mmioSetInfo (
   HMMIO File,
   const MMIOINFO *Info,
   UINT Reserved
 );
  • Info — указатель локальной копии информационной структуры, типа MMIOINFO.
  • Reserved — зарезервированный параметр; должен иметь нулевое значение.

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

Если содержимое буфера было изменено приложением, перед вызовом функции необходимо установить флаг DIRTY. Фактическая запись буфера на диск выполняется только при наличии этого флага.

В начало

В начало

SetBuffer — установка буфера файла

Устанавливает или отменяет буферизацию файла.

MMRESULT mmioSetBuffer (
   HMMIO File,
   LPSTR Buffer,
   LONG Size,
   UINT Reserved
 );
  • Buffer — указатель буфера файла, если буфер предоставляется приложением, либо нуль, если буфер должен быть выделен подсистемой MMIO.
  • Size — размер буфера приложения или MMIO в байтах, либо нуль, если буферизация отменяется. В последнем случае указатель буфера также должен быть нулевым.
  • Reserved — зарезервированный параметр; должен иметь нулевое значение.

Функция выполняет затребованную смену режима буферизации для указанного файла. Если в данный момент для файла используется внутренний буфер, а функция вызывается в режиме задания размера внутреннего буфера, — MMIO изменяет размер буфера функцией GlobalRealloc.

В начало

В начало

Advance — продвижение по файлу в режиме явной буферизации

Считывает в явный буфер очередную порцию данных из файла либо записывает содержимое буфера в файл.

MMRESULT mmioAdvance (
   HMMIO File,
   MMIOINFO *Info,
   UINT Mode
 );
  • Info — указатель локальной копии информационной структуры файла, типа MMIOINFO.
  • Mode — режим продвижения: MMIO_READ — чтение в буфер из файла, MMIO_WRITE — запись буфера в файл.

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

После успешного выполнения чтения или записи функция обновляет значения полей pchNext, pchEndRead, pchEndWrite, lDiskOffset локальной информационной структуры в соответствии с новым состоянием буфера и файла.

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

В начало

В начало

Функции работы с файлами RIFF

CreateChunk — создание раздела

Создает новый раздел в файле.

MMRESULT mmioCreateChunk (
   HMMIO File,
   MMCKINFO *Chunk,
   UINT Type
 );
  • Chunk — указатель описателя создаваемого раздела, типа MMCKINFO:
    • в поле ckid должен быть указан код создаваемого раздела, кроме случая явного создания главного раздела типа RIFF или LIST путем задания значения в поле Type. При создании главных разделов в поле fccType должен быть указан тип формы или списка, а поле ckid автоматически заполняется MMIO.
    • в поле cksize задается размер области данных раздела, если он известен на данный момент; в противном случае поле оставляется произвольным. Для занесения в заголовок фактического размера раздела после завершения его формирования вызывается функция mmioAscend.
  • Type — тип создаваемого раздела:
    • MMIO_CREATERIFF — создание главного раздела RIFF
    • MMIO_CREATELIST — создание главного раздела LIST
    • нуль — создание раздела другого типа.

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

При успешном завершении функции текущая позиция файла устанавливается на начало его области данных, а для режимов CREATERIFF / CREATELIST — сразу за двойным словом типа раздела (12 байтов от начала заголовка). Функция также устанавливает флаг DIRTY в описателе раздела, чтобы вызванная впоследствии функция mmioAscend могла проверить и скорректировать фактический размер области данных раздела.

В начало

В начало

Ascend — выход из раздела

Выполняет выход из раздела, который был создан функцией mmioCreateChunk либо вход в который был выполнен функцией mmioDescend.

MMRESULT mmioAscend (
   HMMIO File,
   MMCKINFO *Chunk,
   UINT Reserved
 );
  • Chunk — указатель описателя создаваемого раздела, типа MMCKINFO.
  • Reserved — зарезервированный параметр; должен иметь нулевое значение.

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

Если флаг не установлен — функция сразу выполняет позиционирование за конец раздела в соответствии со значениями полей dwDataOffset и cksize описателя, полагая, что размер раздела не был изменен после входа в него функцией mmioDescend.

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

Функция вызывается сразу после завершения формирования нового раздела, длина области данных которого заранее неизвестна, либо после изменения длины существующего раздела.

В начало

В начало

Descend — вход в существующий раздел

Выполняет поиск указанного раздела и вход в него.

MMRESULT mmioDescend (
   HMMIO File,
   MMCKINFO *Chunk,
   const MMCKINFO *Parent,
   UINT Mode
 );
  • Chunk — указатель описателя искомого раздела, типа MMCKINFO. В поле ckid должен быть указан код искомого раздела, кроме случаев явного поиска разделов RIFF/LIST, путем задания значения параметра Mode.
  • Parent — указатель описателя главного раздела, типа MMCKINFO. Если он задан, то требуемый раздел ищется внутри указанного главного раздела, вход в который был ранее выполнен функцией mmioDescend.
  • Mode — вид выполняемой операции:
    • нуль — вход в раздел, расположенный с текущей позиции файла.
    • MMIO_FINDRIFF — поиск главного раздела RIFF заданного типа.
    • MMIO_FINDLIST — поиск главного раздела LIST заданного типа.
    • MMIO_FINDCHUNK — поиск произвольного раздела.

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

Если требуется найти любой из главных разделов, независимо от типа, — в поле ckid описателя искомого раздела необходимо занести соответствующий код, а в параметре Mode указать значение MMIO_FINDCHUNK.

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

При обнаружении нужного раздела функция считывает его заголовок в заданный описатель, заносит в поле dwDataOffset позицию начала области данных в файле и устанавливает текущую позицию на начало области данных раздела. Для режимов FINDRIFF / FINDLIST позиция устанавливается сразу за двойным словом типа раздела (12 байтов от начала заголовка).

Флаг DIRTY в описателе раздела сбрасывается. Если требуется расширить, усечь или перезаписать область данных раздела, то после этого необходимо установить флаг DIRTY и выполнить выход из раздела функцией mmioAscend для коррекции поля длины в заголовке. Для разделов, длина которых не изменяется, выход выполнять не требуется.

Если искомый раздел не найден — текущая позиция файла не определена.

В начало

В начало

Прочие функции

SendMessage – посылка произвольного сообщения

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

LRESULT mmioSendMessage (
   HMMIO File,
   UINT Msg,
   LPARAM Param1,
   LPARAM Param2
 );
  • Msg – код передаваемого сообщения. Коды пользовательских сообщений начинаются со значения MMIOM_USER.
  • Param1, Param2 – параметры сообщения. Смысл параметров определяется видом конкретного сообщения.

Фактически почти все вызываемые приложением функции MMIO преобразуются в сообщения с кодами MMIOM_xxx, передаваемые процедуре обмена. Если процедура обмена поддерживает какие-либо дополнительные сообщения (например, средства расширенного управления), функция mmioSendMessage позволяет передать такое сообщение с нужными параметрами. Функция возвращает значение, возвращенное процедурой обмена в ответ на переданное ей сообщение.

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

В начало

В начало

InstallIOProc – установка локальной процедуры обмена

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

LPMMIOPROC mmioInstallIOProc (
   FOURCC ProcCode,
   LPMMIOPROC ProcAddr,
   DWORD Flags
 );
  • ProcCodeкод процедуры обмена, над которой выполняется требуемая операция. Код должен быть составлен только из символов верхнего регистра (заглавные буквы).
  • ProcAddr – адрес внутренней функции для устанавливаемой процедуры обмена. Функция должна быть оформлена в соответствии с заданным прототипом. Для случаев поиска или удаления процедуры этот параметр должен быть нулевым.
  • Flags – код выполняемой операции и дополнительные флаги:
    • MMIO_INSTALLPROC – установка процедуры с заданными адресом и кодом. Вместе с этим кодом операции может быть задан флаг MMIO_GLOBALPROC, указывающий, что процедура устанавливается глобально;
    • MMIO_REMOVEPROC – удаление установленной процедуры с заданным кодом;
    • MMIO_FINDPROC – поиск установленной процедуры с заданным кодом.

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

Новые процедуры обмена заносятся в начало внутреннего списка MMIO, и при установке процедуры для уже имеющегося кода новая процедура будет использоваться вместо старой. При поиске/удалении список просматривается от начала к концу, и найдена/удалена будет последняя из установленных процедур с подходящим кодом. Таким образом, удаление процедур должно происходить в порядке, обратном порядку их установки.

В Win32 глобально установленные процедуры становятся «видимыми» из других процессов: другой процесс может получить адрес установленной процедуры, удалить ее, а также попытаться подключить ее к открываемому файлу посредством указания структурного имени в функции mmioOpen. Однако из-за использования различными процессами разных адресных пространств обращение к «чужой» процедуре обмена в общем случае приведет к ошибке.

В начало

В начало

IOProc — прототип функции для процедуры обмена

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

LRESULT CALLBACK IOProc (
   LPSTR Info,
   UINT Msg,
   LONG Param1,
   LONG Param2
 );
  • Info – указатель структуры MMIOINFO, описывающей текущее состояние открытого файла. По непонятной причине этот параметр имеет тип LPSTR (char *), поэтому требуется его явное приведение к типу (MMIOINFO *).
  • Msg – код сообщения, определяющего выполняемое процедурой действие.
  • Param1, Param2 – параметры сообщения, уточняющие смысл выполняемой операции.

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

Процедура обмена вызывается обычным обращением к подпрограмме из той же задачи (thread), которая запросила файловую операцию посредством одной из функций MMIO. Отдельная задача для процедуры обмена не создается.

Для хранения своих служебных данных процедура обмена может пользоваться массивом adwInfo в информационной структуре. Прочие поля структуры управляются только MMIO; процедура обмена не должна изменять их значений.

В ответ на стандартное сообщение функция должна возвратить значение, определяемое типом обрабатываемого сообщения. В том случае, если возвращаемое значение имеет тип MMRESULT, при успешном выполнении операции должно возвращаться значение MMSYSERR_NOERROR (нуль), а при неудаче — код ошибки. При возникновении типовых ошибок (файл не найден, недостаточно памяти и т.п.) должны возвращаться стандартные коды ошибок. Введение дополнительных кодов ошибок для стандартных сообщений допускается лишь в тех случаях, когда среди стандартных кодов нет подходящего.

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

Константы для кодов стандартных сообщений, передаваемых подсистемой MMIO, имеют префиксы MMIOM_:

OPEN

Открывание файла. В параметре Param1 передается указатель строки имени открываемого файла. Поле dwFlags информационной структуры содержит коды режимов открывания файла и дополнительные флаги. Поле lDiskOffset в этот момент имеет нулевое значение. Возвращается значение типа MMRESULT.

CLOSE

Закрывание файла. В параметре Param1 передается значение параметра Flags функции mmioClose. Возвращается значение типа MMRESULT.

RENAME

Переименование файла. В параметре Param1 передается указатель строки имени исходного файла, в параметре Param2 – указатель строки нового имени. Возвращается значение типа MMRESULT.

READ

Чтение из файла. В параметре Param1 передается указатель буфера, в который считываются данные, в параметре Param2 – размер считываемого фрагмента. Возвращается реальное количество считанных байтов, либо — 1 в случае ошибки.

WRITE

Запись в файл. В параметре Param1 передается указатель буфера, содержащего записываемые данные, в параметре Param2 – размер записываемого фрагмента. Возвращается реальное количество записанных байтов, либо — 1 в случае ошибки.

WRITEFLUSH

Аналогично WRITE, требует фактической записи на диск внутренних буферов файла после выполнения операции.

SEEK

Смена текущей позиции файла. В параметре Param1 передается величина смещения в байтах, в параметре Param2 – код исходной точки для позиционирования, как в функции mmioSeek. Возвращается новая позиция относительно начала файла, либо — 1 в случае ошибки.

В начало

В начало

Недостатки интерфейса MMIO

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

Разделение процедур обмена в Windows 95/98 принципиально возможно путем помещения процедуры обмена в область общих адресов (начиная с 0x80000000), где она будет «видна» остальным процессам. Однако ее вызов в любом случае будет выполняться локально, и вызываемая процедура будет работать от имени вызывающего процесса и пользоваться его ресурсами.

В начало

В начало

Пример программы, использующей MMIO

В качестве иллюстрации схемы обработки звуковых файлов приведена программа ACMPlay, файлы проекта которой находятся в каталоге ACMPlay. Программа переделана из опубликованной в прошлом номере программы RTComp, предназначенной для сжатия и записи звука в файл в реальном времени. Фактически ACMPlay является «обратной» к RTComp: она открывает существующий WAV-файл, находит в нем требуемые разделы, после чего восстанавливает данные в формат PCM и воспроизводит на заданном Wave-устройстве.

Для воспроизведения файла необходимо выбрать звуковое устройство, после чего выбрать звуковой файл кнопкой «Файл». Фильтр типов файлов в диалоге выбора пропускает только файлы с расширением WAV. После успешного выбора воспроизведение запускается автоматически. В процессе воспроизведения кнопка переименовывается в «Стоп» для досрочной остановки воспроизведения.

Для поиска разделов RIFF/WAVE, fmt, data используются функции mmioDescend. Файл обрабатывается в режиме явной буферизации, причем буфер файла используется как исходный буфер при преобразовании порций данных в потоке ACM. Размер буфера округляется до 4096 байтов, чтобы он мог вместить полный блок в форматах MS ADPCM и IMA ADPCM.

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

Предыдуюшая страница

КомпьютерПресс 8'2000


Наш канал на Youtube

1999 1 2 3 4 5 6 7 8 9 10 11 12
2000 1 2 3 4 5 6 7 8 9 10 11 12
2001 1 2 3 4 5 6 7 8 9 10 11 12
2002 1 2 3 4 5 6 7 8 9 10 11 12
2003 1 2 3 4 5 6 7 8 9 10 11 12
2004 1 2 3 4 5 6 7 8 9 10 11 12
2005 1 2 3 4 5 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
Популярные статьи
КомпьютерПресс использует