レガシー Windows API(概要)について

ここで紹介しているAPIは、Windows95、Windows NT3.5時代のAPI群であり、最新のAPIは含まれていないことに注しして欲しい。なお、当時の解説書は現在よりもより詳細に解説しているため、参考になるはずである。

  • レイアウトを変換する際、崩れているページがあります。
  • 概要およびSampleコードはありますが、APIの解説はありません。

ご要望があれば旧版のWin32 API(HELP形式)をお譲りします。問い合わせフォームより申し込みください。

Windows API マルチメディア ファイル

I/Oの概要

通常、 マルチメディア アプリケーションには、 ディスク ファイルを作成したり読み書きするためのファイル入出力 (I/O) 機能が必要です。Microsoft(R) Win32(R) アプリケーション プログラミング インターフェイス (API) が用意しているマルチメディア ファイル入出力サービスによって、 バッファ付きとバッファなしのファイル入出力や、 リソース交換ファイル形式 (RIFF; Resource Interchange File Format) ファイルを利用できます。このサービスは、 複数のアプリケーションで共有可能なカスタム入出力プロシージャで拡張できます。

次に示すトピックでは、 マルチメディア ファイル入出力サービスについて説明しています。

C言語ランタイムやWindowsのファイル入出力との比較

関数のプリフィックス

データ型

基本的なファイル入出力の実行

ファイルのオープン

ファイルの作成と削除

ファイルの読み書き

ファイルの別の位置へのシーク

バッファ付きファイル入出力の実行

バッファ付きファイル入出力が適切な場合

バッファ付きファイル入出力によるファイルのオープン

入出力バッファ制御関数

RIFFファイルの使用

RIFFファイルについて

4文字コードの生成

RIFFチャンクの作成

RIFFファイルの操作

RIFFファイル入出力の例

ファイル入出力バッファへの直接アクセス

ファイル入出力バッファに関する情報の取得

ファイル入出力バッファの読み書き

ファイル入出力バッファの更新

ファイル入出力バッファのアクセスの例

ファイル入出力バッファの直接アクセスの終了

メモリ ファイルに対するファイル入出力の実行

メモリ ファイルのオープン

カスタム入出力プロシージャの使用

カスタム入出力プロシージャによるファイルのオープン

入出力プロシージャの作成

入出力プロシージャのインストール

マルチメディア ファイルI/O関数

マルチメディア ファイル入出力サービスは、 次のファイル入出力操作をサポートします。

基本的な、 バッファなしまたはバッファ付きのファイル入出力。

RIFFファイル入出力。

ファイル入出力バッファへの直接アクセス。

メモリ ファイル。

アプリケーション固有の入出力プロシージャを使用した、 カスタム記憶システム入出力。

ほとんどのアプリケーションは、 基本ファイル入出力サービスと、 RIFFファイル入出力サービスしか必要としません。リアル タイムでCD-ROMからデータをストリーム転送するアプリケーションなどのファイル入出力の性能に依存するアプリケーションでは、 ファイル入出力バッファに直接アクセスするサービスを使って、 性能を最適化できます。カスタム記憶システムにアクセスするアプリケーションは、 記憶システムの要素の読み書きを行う固有の入出力プロシージャを設定できます。記憶システムとは、 ファイル アーカイブ システムやデータベース記憶システムのような、 ファイルにデータを物理的に保存する方法です。

C言語のランタイムやWindowsのファイル入出力との比較

CランタイムやWin32 APIのライブラリのサービスがすでにあるのに、 なぜ別のファイル入出力サービスのセットが必要なのか、 疑問に思われるかも知れませんが、 マルチメディア ファイル入出力サービスは、 ほかのファイル入出力サービスと比較して、 次の点が優れています。

システム ソフトウェアの一部なので、 Cランタイム ライブラリのリンクのように、 アプリケーションのサイズを大きくしません。

バッファ付き入出力、 RIFFファイル、 メモリ ファイル、 カスタム記憶システムのサポートのように、 Win32サービスより優れた機能を提供します。

さらに、 マルチメディア ファイル入出力サービスは、 性能を重視するアプリケーションのために最適化されています。

関数のプリフィックス

すべてのマルチメディア ファイル入出力関数の名前は、 mmioというプリフィックスで始まります。同様に、 すべてのマルチメディア ファイル入出力メッセージの名前は、 MMIOM_というプリフィックスで始まります。

データ型

MMSYSTEM.Hヘッダー ファイルでは、 データ型とすべてのマルチメディア ファイル入出力関数の関数プロトタイプを定義しています。マルチメディア入出力関数を使用するソース モジュールは、 このヘッダー ファイルを必ずインクルードしなければなりません。MMSYSTEM.HはWINDOWS.Hの宣言に依存しているため、 必ず最初にWINDOWS.Hヘッダーファイルをインクルードしてください。MMSYSTEM.Hでは、 次に示すマルチメディア ファイル入出力関数のデータ型を定義しています。

データ型 説明

FOURCC RIFFファイルの要素を識別する4文字コード

HMMIO オープンされているファイルのハンドル

MMCKINFO RIFFファイル内のチャンクに関する情報を格納する構造体

MMIOINFO マルチメディア ファイル入出力サービスを使用してアクセスするファイルの現在の状態を維持するために使われる構造体

MMIOPROC カスタム マルチメディア ファイル入出力プロシージャ

基本ファイル入出力の実行

基本入出力サービスの使い方は、 Cランタイム ファイル入出力サービスの使い方に似ています。ファイルは、 読み書きを行う前にオープンしなければなりません。読み書きの後は、 ファイルをクローズしなければなりません。現在の読み書き位置は、 オープンされているファイル内の特定の位置にシークして変更できます。次の表は、 基本ファイル入出力関数のリストです。

関数 説明

mmioClose オープンされているファイルをクローズします。

mmioOpen 読み書きできるようにファイルをオープンし、 オープンしたファイルのハンドルを返します。

mmioRead オープンされているファイルから、 指定されたバイト数を読み取ります。

mmioSeek オープンされているファイルの、 現在の読み書き位置を変更します。

mmioWrite オープンされているファイルに、 指定されたバイト数を書き込みます。

上記のファイル入出力関数が、 マルチメディア ファイル入出力サービスの中心になります。バッファ付きやバッファなしの入出力のほかに、 RIFFファイル、 メモリ ファイル、 カスタム記憶システムなどの入出力にも、 これらの関数を使えます。

ファイルのオープン

ファイルの入出力操作の前に、 mmioOpen関数を使ってファイルをオープンしなければなりません。mmioOpen関数が返すファイル ハンドルは、 ほかのファイル入出力関数を呼び出すとき、 オープンされているファイルの識別に使います。

: HMMIOファイル ハンドルを、 WindowsやCランタイムのファイル入出力関数で使わないでください。

mmioOpen関数には、 基本ファイル入出力の範囲を超える操作のためのオプションがあります。lpmmioinfoパラメータにMMIOINFO構造体を指定することにより、 メモリ ファイルのオープン、 カスタム入出力プロシージャの指定、 バッファ付き入出力のためのバッファの供給などができます。これらに関しては、 このトピックの後半で解説します。まず初めに、 このトピックでは、 mmioOpenの最も基本的な使用法として、 基本的なバッファなしファイル入出力におけるファイルのオープンを説明します。

基本入出力操作用にファイルをオープンするには、 mmioOpenlpmmioinfoパラメータにNULLを指定してください。たとえば、 次のコードは、 ファイルC:\SAMPLES\SAMPLE1.TX36を読み取り用にオープンし、 戻り値をチェックします。

HMMIO hFile;

.ifdef REF

.

.

.

.endif

hFile = mmioOpen("NEWFILE.TXT",

NULL, MMIO_CREATE | MMIO_READWRITE);

if (hFile != NULL)

/* File created successfully. */

return TRUE;

else

/* File could not be created. */

return FALSE;

ファイルのオープンに関するオプション

ファイルをオープンするときは、 ファイルの使用目的 (読み取りや書き込みなど) を必ず指定してください。また、 新しいファイルの作成や削除のなどのオプションも指定できます。ファイルのオープンに関するオプションを指定するには、 mmioOpendwFlagsパラメータを使ってください。

次の表は、 mmioOpenを使ってファイルをオープンするときの、 基本的なオプションのリストです。

フラグ 意味

MMIO_READ ファイルを読み取り専用にオープンします。

MMIO_WRITE ファイルを書き込み専用にオープンします。

MMIO_READWRITE ファイルを読み書き用にオープンします。

MMIO_CREATE 新しいファイルを作成します (ファイルがすでに存在する場合は、 長さ0に切り捨てます)。

MMIO_DELETE ファイルを削除します。

MMIO_ALLOCBUF ファイルをバッファ付き入出力用にオープンします。

MMIO_READフラグ、 MMIO_WRITEフラグ、 MMIO_READWRITEフラグは、 読み取りと書き込みの特権フラグです。これらのフラグは、 相互に排他的です。ファイルをオープンするときに、 1つだけを指定してください。これらのフラグをどれも指定しないと、 mmioOpenは読み取り専用にファイルをオープンします。

MMIO_CREATEフラグとMMIO_DELETEフラグも、 相互に排他的です。MMIO_CREATEフラグには、 読み取りや書き込みの特権フラグのいずれかを同時に指定できます。MMIO_DELETEフラグと同時にほかのフラグを指定することはできません。

MMIO_ALLOCBUFフラグの使い型について詳しくは、 バッファ付きファイル入出力の実行を参照してください。

ファイルのオープンにおける基本的なオプションに加えて、 複数のプロセスでのオープンとアクセスを可能にするための共有オプションがあります。次の表は、 mmioOpenによるファイルのオープンでの共有オプションのリストです。

フラグ 意味

MMIO_COMPAT 互換モードでファイルをオープンします。

MMIO_EXCLUSIVE 排他モードでファイルをオープンします。

MMIO_DENYWRITE ファイルをオープンし、 ほかのプロセスからの書き込み用ファイル アクセスを拒否します。

MMIO_DENYREAD ファイルをオープンし、 ほかのプロセスからの読み取り用ファイル アクセスを拒否します。

MMIO_DENYNONE ほかのプロセスからのファイル アクセスを拒否せずにファイルをオープンします。

ファイルの作成と削除

新しいファイルを作成するには、 mmioOpen関数でMMIO_CREATEオプションを指定してください。たとえば、 次のコードは、 新しいファイルを作成し、 それを読み書き用にオープンします。

HMMIO hFile;

.ifdef REF

.

.

.

.endif

hFile = mmioOpen("NEWFILE.TXT",

NULL, MMIO_CREATE | MMIO_READWRITE);

if (hFile != NULL)

/* File created successfully. */

return TRUE;

else

/* File could not be created. */

return FALSE;

: 作成しようとするファイルがすでに存在している場合、 そのファイルは長さが0に切り捨てられます。

ファイルを削除するには、 mmioOpen関数でMMIO_DELETEフラグを指定してください。いったんファイルを削除すると、 修復することはできません。ファイルの削除がユーザーの要求によるものであれば、 実際に削除する前に、 そのファイルを本当に削除したいのかを確かめるために必ずユーザーに問い合わせるように、 アプリケーションを設計してください。

ファイルの読み書き

オープンしたファイルの読み取りと書き込みには、 mmioRead関数とmmioWrite関数を使ってください。各関数には、 HMMIOファイル ハンドル、 バッファを指すポインタ、 読み書きするバイト数を示すパラメータを指定します。

mmioReadによるファイルからの読み取りの例に関しては、 このトピックのRIFFファイル入出力の例を参照してください。

ファイルの別の位置へのシーク

ファイル内の現在位置 (ファイル ポインタ) は、 次の読み込み処理が発生する場所を指しています。オープンされているファイル内の現在位置を変更するには、 mmioSeek関数を使ってください。

戻り値は、 新しい位置を、 ファイルの先頭からのバイト数で示します。エラーが発生すると、 戻り値は-1になります。ファイルの終端を超えた位置など、 ファイル内の無効な位置へのシークの場合、 mmioSeekはエラーを返しませんが、 それ以降の入出力処理は失敗します。

バッファ付きファイル入出力の実行

ファイル入出力のオーバーヘッドのほとんどは、 メディア (物理デバイス) へのアクセスです。小さな情報ブロックの読み書きを何度も行うと、 メディア デバイスは、 それぞれの読み書きの処理において、 メディア上の物理位置を見つけるためのシークに多くの時間を費やします。このとき、 バッファ付きファイル入出力を使うと、 性能が向上します。バッファ付きファイル入出力では、 ファイル入出力マネージャは、 読み書きを行う情報ブロックより大きな中間バッファを管理します。ファイル入出力マネージャは、 バッファにディスクからのデータを設定しなければならないときや、 ディスクへ書き込まなければならないときにしか、 メディアにアクセスしません。

バッファ付きファイル入出力が適切な場合

バッファ付き入出力の使用が必要な場合の正確な基準を示すのは困難です。この基準は、 ファイルに対して実行する読み書きの頻度と、 読み書きのサイズに依存します。一般的なガイドラインとして、 2Kバイト以下の単位で多くの入出力操作を行う場合には、 バッファ付き入出力を使います。しかし、 この規則は絶対ではありません。プログラムがどのようにファイル入出力を使用するかを正確に理解し、 プログラムの要求に応じてファイル入出力の最適化を試行するのが最善の方法です。

バッファ付きファイル入出力によるファイルのオープン

マルチメディア ファイル入出力マネージャは、 バッファ付きファイル入出力の設定と使用に関して、 数種類の方法を提供しています。これらの方法の主な相違点は、 ファイル入出力マネージャとアプリケーションのどちらがバッファを割り当てるかにあります。入出力バッファは、 ファイル入出力マネージャとアプリケーションのどちらでも割り当てることができます。入出力バッファの直接アクセスやメモリ ファイルのオープンが必要でない限り、 ファイル入出力マネージャがバッファを割り当てるようにしてください。入出力バッファの直接アクセスと、 メモリ ファイルの使用について詳しくは、 ファイル入出力バッファへの直接アクセスメモリ ファイルに対するファイル入出力の実行を参照してください。

ファイル入出力マネージャが割り当てるバッファを、 内部バッファと呼びます。内部バッファを使うバッファ付き入出力用にファイルをオープンするには、 ファイルをオープンするときに、 mmioOpen関数でMMIO_ALLOCBUFフラグを指定してください。いったんファイルがバッファ付き入出力用にオープンされると、 アプリケーションからバッファを考慮する必要はなくなります。バッファなし入出力を使うのと同じ方法で、 読み込みとシークを行えます。

入出力バッファ制御関数

マルチメディア ファイル入出力サービスには、 ファイル入出力バッファをより詳細に制御するための関数がいくつか用意されています。次の関数によって、 入出力バッファ内容のディスクへの強制的な書き込み、 バッファなし入出力用にオープンされたファイルでのバッファ付き入出力、 入出力バッファのサイズ変更、 独自の入出力バッファの供給などができます。

関数 説明

mmioFlush 入出力バッファの内容をディスクに書き込みます。

mmioSetBuffer 入出力バッファのサイズの変更したり、 アプリケーション固有のバッファを供給します。

入出力バッファのフラッシュ

入出力バッファのフラッシュとは、 バッファの内容をディスクに書き込むことです。入出力バッファをフラッシュするのに、 必ずしもmmioFlushを呼び出す必要はありません。mmioCloseを使ってファイルをクローズすると、 バッファは自動的にフラッシュされます。書き込み後すぐにファイルをクローズしない場合は、 情報がディスクに確実に書き込まれるようにするため、 バッファをフラッシュしてください。

: ディスク領域を使い果たした場合、 先のmmioWriteの呼び出しが成功していても、 mmioFlushで失敗することがあります。同様に、 mmioCloseで入出力バッファをフラッシュするときに失敗する可能性もあります。

内部入出力バッファのサイズ変更

内部入出力バッファのデフォルト サイズは8Kバイトです。このサイズが適切でなければ、 mmioSetBufferを使って、 バッファ サイズを変更できます。また、 mmioSetBufferを使って、 バッファなし入出力用にオープンされたファイルでバッファを利用することもできます。

たとえば、 次のコードは、 バッファなし入出力用にSAMPLE.TXTという名前のファイルをオープンし、 その後、 16Kバイトの内部バッファでのバッファ付き入出力ができるようにします。

HMMIO hFile;

.ifdef REF

.

.

.

.endif

if ((hFile = mmioOpen("SAMPLE.TXT", NULL, MMIO_READ)) != NULL) {

/* File opened successfully; request an I/O buffer */

if (mmioSetBuffer(hFile, NULL, 16384L, 0))

/* Buffer cannot be allocated. */

return FALSE;

else

/* Buffer allocated successfully. */

return TRUE;

}

else

/* File cannot be opened. */

return FALSE;

独自の入出力バッファの供給

mmioSetBufferを使って、 メモリ ファイルとして使うための独自のバッファを供給することもできます。メモリ ファイルの使用について詳しくは、 メモリ ファイルに対するファイル入出力の実行を参照してください。

RIFFファイルの使用

マルチメディア ファイルに適した形式として、 リソース交換ファイル形式 (RIFF) があります。RIFF形式はタグ付きファイル構造です。

マルチメディア ファイル入出力サービスは、 RIFFファイルに対するファイル入出力をサポートするための次の関数を提供しています。

関数 説明

mmioAscend RIFFファイルのチャンクから出て、 ファイル内の次のチャンクに進みます。

mmioCreateChunk RIFFファイル内に新しいチャンクを作成します。

mmioDescend 現在のファイル位置から始まるRIFFファイル チャンクに入るか、 指定されたチャンクを検索します。

mmioFOURCC 4つの別々の文字を、 4文字コードに変換します。

mmioStringToFOURCC NULLで終わる文字列を、 4文字コードに変換します。

上記の関数は、 バッファ付きまたはバッファなしの基本ファイル入出力サービスで使います。ほかのファイルと同様に、 基本ファイル入出力サービスで、 RIFFファイルのオープンと読み書きができます。

RIFFファイルについて

RIFFファイルの基本的なブロックをチャンクと呼びます。それぞれのチャンクは、 次のメンバで構成されます。

チャンクIDを示す4文字コード

チャンク内のデータ フィールドのサイズを示すDWORD

データ フィールド

ほかのチャンク (サブチャンク) を含むことができるチャンクは、 チャンクIDがRIFFまたはLISTのチャンクだけです。RIFFファイルの最初のチャンクは、 RIFFチャンクでなければなりません。ファイル内のほかのすべてのチャンクは、 RIFFチャンクのサブチャンクです。

RIFFチャンク

RIFFチャンクは、 データ フィールドの最初の4バイトに、 付加的なフィールドを持ちます。このフィールドは、 フィールドのフォーム タイプを示します。フォーム タイプとは、 ファイル内に格納されているデータの形式を識別する4文字コードです。たとえば、 ウェーブフォーム オーディオ ファイル (WAVEファイル) のフォーム タイプは、 WAVEです。

LISTチャンク

LISTチャンクも、 データ フィールドの最初の4バイトに、 付加的なフィールドを含んでいます。このフィールドは、 フィールドのリストの種類を示します。リストの種類とは、 リストの内容を識別する4文字コードです。たとえば、 リストの種類がINFOLISTチャンクは、 著作権と作成日付の情報を示すICOPチャンクとICRDチャンクを含むことができます。

4文字コードの生成

4文字コードとは、 1文字から4文字のASCII英数文字列に、 必要に応じて右側に空白文字を付加した、 32ビット データです。4文字コードのデータ型はFOURCCです。4つの文字を4文字コードに変換するには、 次のコードに示すように、 mmioFOURCC関数を使ってください。ここでは、 WAVEという4文字コードを生成しています。

FOURCC fourccID;

.ifdef REF

.

.

.

.endif

fourccID = mmioFOURCC('W', 'A', 'V', 'E');

NULLで終わる文字列を4文字コードに変換するには、 次のコードに示すように、 mmioStringToFOURCC関数を使ってください。ここでも、 WAVEという4文字コードを生成しています。

FOURCC fourccID;

.ifdef REF

.

.

.

.endif

fourccID = mmioStringToFOURCC("WAVE", 0);

mmioStringToFOURCCの第2パラメータには、 文字列を4文字コードに変換するときのオプションを指定します。MMIO_TOUPPERフラグを指定すると、 mmioStringToFOURCCは、 文字列の英字をすべて大文字に変換します。これは、 カスタム入出力プロシージャの識別に4文字コードの指定が必要なとき便利です (ファイル拡張子を識別する4文字コードは、 すべて大文字でなければなりません)。

RIFFチャンクの作成

新しいチャンクを作成するには、 mmioCreateChunkを使って、 オープンされているファイルの現在位置にチャンク ヘッダーを書き込みます。

次の例は、 チャンクIDRIFFとフォーム タイプRDIBを持つ、 新しいチャンクを作成します。

HMMIOhmmio;

MMCKINFO mmckinfo;

.ifdef REF

.

.

.

.endif

mmckinfo.fccType = mmioFOURCC('R', 'D', 'I', 'B');

mmioCreateChunk(hmmio, &mmckinfo, MMIO_CREATERIFF);

RIFFチャンクやLISTチャンクを作成するときは、 MMCKINFO構造体のfccTypeメンバにフォーム タイプを指定してください。前の例では、 フォーム タイプはRDIBです。

新しいチャンクのデータ フィールドのサイズがわかっていれば、 チャンクを作成するときに、 MMCKINFO構造体のcksizeメンバにサイズを設定してください。この値は、 新しいチャンクのデータ サイズ メンバに書き込まれます。mmioAscendを呼び出してチャンクの終わりをマークしたとき、 この値が間違っていると、 データ フィールドの正しいサイズを反映するように、 自動的に再書き込みが行われます。

mmioCreateChunkを使って新しいチャンクを作成すると、 ファイル位置は、 チャンクのデータ フィールド (チャンクの先頭から8バイト目) に設定されます。チャンクがRIFFLISTならば、 ファイル位置は、 フォーム タイプやリストの種類の後 (チャンクの先頭から12バイト目) に設定されます。

RIFFファイルの操作

RIFFファイルでは、 データ チャンクがネストしています。マルチメディア ファイル入出力サービスには、 RIFFファイル内でのチャンク間の移動に使うmmioAscendmmioDescendの2つの関数があります。これらの関数は、 高レベルなシーク関数とみなすことができます。チャンク内に入ると、 ファイル位置は、 チャンクのデータ フィールド (チャンクの先頭から8バイト目) に設定されます。RIFFチャンクとLISTチャンクでは、 フォーム タイプやリストの種類に続く位置 (チャンクの先頭から12バイト目) にファイル位置が設定されます。チャンクから出るとき、 ファイル位置は、 チャンクの終端の直後に設定されます。

チャンクへの進入

mmioDescend関数は、 現在のファイル位置から始まるチャンクに進入したり、 チャンクを検索します。

mmioDescend関数は、 MMCKINFO構造体にチャンクに関する情報を設定します。この情報は、 チャンクIDとデータ フィールドのサイズ、 フォーム タイプを示します。また、 チャンクがRIFFLISTの場合には、 フォーム タイプではなくリストの種類を示します。

チャンクの検索

オープンされているRIFFファイル内でチャンクを検索するには、 mmioDescendwFlagsパラメータにMMIO_FINDCHUNKフラグを指定してください。lpckが指すMMCKINFO構造体のckidメンバには、 検索したいチャンクの4文字コードを設定してください。

RIFFチャンクやLISTチャンクを検索するときは、 MMCKINFO構造体のckidメンバに値を設定する必要はありません。mmioDescendが、 このメンバを設定してくれます。fccTypeメンバに、 チャンクのフォーム タイプかリストの種類の4文字コードを設定してください。

次のコードは、 オープンしたファイルがWAVEウェーブフォーム オーディオ ファイルであることを確認するために、 フォーム タイプにWAVEを使ってRIFFチャンクを検索します。

HMMIOhmmio;

MMCKINFO mmckinfoParent;

MMCKINFO mmckinfoSubchunk;

.ifdef REF

.

.

.

.endif

/*

* Locate a "RIFF" chunk with a "WAVE" form type

* to make sure the file is a WAVE file.

*/

mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');

if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent,

NULL, MMIO_FINDRIFF))

/* The file is not a WAVE file. */

return FALSE;

else

/* The file is a WAVE file. */

return TRUE;

検索するチャンクが親チャンク内にあるサブチャンクならば (RIFFチャンク以外のすべてのチャンクの場合)、 lpckParentパラメータに親チャンクを指定してください。この場合、 mmioDescendは、 指定された親チャンクの中だけを検索します。

次に示すコードは、 前の例で進入したRIFFチャンク内でfmtチャンクを検索します。

/*

* Find the format chunk (form type "fmt "); it should be

* a subchunk of the "RIFF" parent chunk.

*/

mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');

if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,

MMIO_FINDCHUNK)) {

/* Error, cannot find the "fmt " chunk. */

return FALSE;

}

else {

/* "fmt " chunk found. */

return TRUE;

}

親チャンクを指定しない場合、 チャンクの検索のためにmmioDescendを呼び出す前に、 現在のファイル位置がチャンクの先頭になければなりません。親チャンクを指定する場合には、 現在のファイル位置は、 親チャンク内のどの位置でもかまいません。

サブチャンクの検索に失敗すると、 現在のファイル位置は未定義になります。親チャンクのMMCKINFO構造体のdwDataOffsetのメンバの値をmmioSeekに指定することによって、 親チャンクの先頭に戻ることができます。例を次に示します。

mmioSeek(hmmio, mmckinfoParent.dwDataOffset + 4, SEEK_SET);

dwDataOffsetメンバはチャンクのデータ部分の先頭のオフセットを示しているため、 ファイル位置をフォーム タイプの後に設定するには、 dwDataOffset4バイト後にシークしなければなりません。

チャンクからの退出

チャンクに進入してチャンクのデータを読み取ったら、 mmioAscend関数を使ってチャンクから退出し、 ファイル位置を次のチャンクの先頭に移動できます。

たとえば、 次の文は、 サブチャンクの検索を示した上記の例で進入したfmtサブチャンクから退出します。

/* Ascend out of the "fmt " subchunk.
*/
mmioAscend(hmmio, &mmckinfoSubchunk, 0);

RIFFファイル入出力の例

次に示すコード例は、 バッファ付き入出力でRIFFファイルをオープンする方法と、 RIFFチャンクの進入、 退出、 読み取りの方法を示しています。

/* ReversePlay--Plays a WAVE waveform audio file backwards. */

void ReversePlay(void)

{

charszFileName[128];/* filename of file to open */

HMMIOhmmio;/* file handle for open file */

MMCKINFOmmckinfoParent;/* parent chunk information structure */

MMCKINFOmmckinfoSubchunk; /* subchunk information structure*/

DWORDdwFmtSize;/* size of "fmt" chunk*/

DWORDdwDataSize;/* size of "data" chunk*/

WAVEFORMAT*pFormat;/* pointer to memory for "fmt" chunk */

.ifdef REF

...

.endif

/* Get the filename from the edit control. */

.ifdef REF

...

.endif

/*

* Open the given file for reading with buffered I/O

* using the default internal buffer.

*/

hmmio = mmioOpen(szFileName, NULL, MMIO_READ | MMIO_ALLOCBUF);

if(hmmio == NULL){

Error("Failed to open file.");

return;

}

/*

* Locate a "RIFF" chunk with a "WAVE" form type

* to make sure the file is a WAVE file.

*/

mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');

if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL,

MMIO_FINDRIFF)) {

Error("This is not a WAVE file.");

mmioClose(hmmio, 0);

return;

}

/*

* Find the "fmt " chunk (form type "fmt "); it must be

* a subchunk of the "RIFF" parent chunk.

*/

mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');

if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,

MMIO_FINDCHUNK)) {

Error("WAVE file has no \"fmt\" chunk");

mmioClose(hmmio, 0);

return;

}

/*

* Get the size of the "fmt " chunk--allocate and lock memory for it.

*/

dwFmtSize = mmckinfoSubchunk.cksize;

.ifdef REF

...

.endif

/* Read the "fmt " chunk. */

if (mmioRead(hmmio, (HPSTR) pFormat, dwFmtSize) != (LRESULT)dwFmtSize){

Error("Failed to read format chunk.");

.ifdef REF

...

.endif

mmioClose(hmmio, 0);

return;

}

/* Ascend out of the "fmt " subchunk. */

mmioAscend(hmmio, &mmckinfoSubchunk, 0);

/*

* Find the data subchunk. The current file position

* should be at the beginning of the data chunk.

*/

mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');

if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,

MMIO_FINDCHUNK)) {

Error("WAVE file has no data chunk.");

.ifdef REF

...

.endif

mmioClose(hmmio, 0);

return;

}

/* Get the size of the data subchunk. */

dwDataSize = mmckinfoSubchunk.cksize;

if (dwDataSize == 0L) {

Error("The data chunk contains no data.");

.ifdef REF

...

.endif

mmioClose(hmmio, 0);

return;

}

/* Open a waveform output device. */

.ifdef REF

...

.endif

/* Allocate and lock memory for the waveform data. */

.ifdef REF

...

.endif

/* Read the waveform data subchunk. */

if(mmioRead(hmmio, (HPSTR) lpData,

dwDataSize) != (LRESULT)dwDataSize) {

Error("Failed to read data chunk.");

.ifdef REF

...

.endif

mmioClose(hmmio, 0);

return;

}

/* Close the file. */

mmioClose(hmmio, 0);

/* Reverse the sound and play it. */

.ifdef REF

...

.endif

}

ファイル入出力バッファへの直接アクセス

CD-ROMからのデータをリアル タイムでストリーム転送しなければならないアプリケーションなどの、 処理速度に左右されるアプリケーションでは、 ファイル入出力バッファを直接アクセスすることによって、 ファイル入出力性能を最適化することができます。ファイル入出力バッファに直接アクセスする方法では、 ファイル入出力マネージャによる保安機能とエラー チェックをバイパスすることになるため、 注意してください。

マルチメディア ファイル入出力サービスは、 入出力バッファへの直接アクセスをサポートするために、 次の関数を用意しています。

関数 説明

mmioAdvance 直接入出力バッファ アクセスが設定されたファイルの、 入出力バッファの設定やフラッシュを行います。

mmioGetInfo バッファ付き入出力用にオープンされたファイルの、 ファイル入出力バッファに関する情報を取得します。

mmioSetInfo バッファ付き入出力用にオープンされたファイルの、 ファイル入出力バッファに関する情報を変更します。

ファイル入出力バッファに直接アクセスするには、 バッファ付きファイル入出力の実行で述べた方法で、 バッファ付き入出力用にファイルをオープンしてください。内部ファイル入出力バッファを使用するか、 mmioSetBufferで独自のバッファを供給することができます。

ファイル入出力バッファに関する情報の取得

バッファのサイズやアドレスなどの、 ファイル入出力バッファに関する情報を取得するには、 mmioGetInfo関数を使ってください。

ファイル入出力バッファの読み書き

ファイル入出力バッファの読み書きに使われるMMIOINFO構造体には、 pchNext pchEndRead pchEndWrite3つのメンバがあります。pchNextメンバは、 バッファ内の次に読み書きが行われる位置を示します。バッファの読み書きに応じて、 pchNextを増加しなければなりません。pchEndReadメンバは、 バッファから読み取ることができる有効な文字の終端を識別します。同じように、 pchEndWriteは、 バッファに書き込める最後の位置を識別します。正確には、 pchEndReadpchEndWriteは、 ともにバッファ内の最後の有効なデータの次のメモリ位置を指しています。

ファイル入出力バッファの更新

ファイル入出力バッファの終端に達したときには、 バッファを更新して (読み取りの場合) ディスクからのデータを設定するか、 ディスクへフラッシュ (書き込みの場合) しなければなりません。ファイル入出力バッファの更新には、 mmioAdvance関数を使います。

mmioAdvance関数は、 (pchNext - cchBuffer) バイトだけバッファにデータを読み取って更新します。バッファのpchNextより前にはすべてデータが存在し、 pchNextからpchEndReadまでのデータはまったく読み取られていないと仮定されます。このため、 mmioAdvanceが呼び出されると、 pchNextより前のデータはすべて上書きされます。バッファを配列として扱うことはできず、 pchNextpchEndReadに等しくなるまでpchNextを増やさなければなりません。

mmioAdvance関数の使用

ファイル入出力バッファにディスクのデータを設定するには、 MMIO_READフラグを指定してmmioAdvanceを呼び出してください。ファイルのデータでバッファがいっぱいにならなかったときは、 MMIOINFO構造体のpchEndReadメンバは、 バッファ内の最後の有効なバイトの次の位置を示します。

バッファをディスクにフラッシュするには、 まずMMIOINFO構造体のdwFlagsメンバにMMIO_DIRTYフラグを設定します。その後、 MMIO_WRITEフラグを指定して、 mmioAdvanceを呼び出してください。

ファイル入出力バッファへのアクセスの例

次のコード例は、 このトピックで以前に説明したReversePlay関数を元にしています。この例では、 ファイルからウェーブフォーム データを読み取るために、 バッファへの直接アクセスが使われています。

HMMIOhmmio;

MMIOINFO mmioinfo;

DWORDdwDataSize;

DWORDdwCount;

HPSTRhptr;

.ifdef REF

.

.

.

.endif

/* Get information on the file I/O buffer. */

if (mmioGetInfo(hmmio, &mmioinfo, 0)) {

Error("Failed to get I/O buffer info");

mmioClose(hmmio, 0);

return FALSE;

}

/*

* Read the entire file by directly reading the file I/O buffer.

* When the end of the I/O buffer is reached, advance the buffer.

*/

for (dwCount = dwDataSize, hptr = lpData; dwCount > 0; dwCount--) {

/* Check to see if the I/O buffer must be advanced. */

if (mmioinfo.pchNext == mmioinfo.pchEndRead) {

if(mmioAdvance(hmmio, &mmioinfo, MMIO_READ)) {

Error("Failed to advance buffer.");

mmioClose(hmmio, 0);

return FALSE;

}

}

/* Get a character from the buffer. */

*hptr++ = *mmioinfo.pchNext++;

}

/* End direct buffer access and close the file. */

mmioSetInfo(hmmio, &mmioinfo, 0);

mmioClose(hmmio, 0);

ファイル入出力バッファの直接アクセスの終了

ファイル入出力バッファへのアクセスを終了したら、 mmioGetInfoを使って値を設定したMMIOINFO構造体をmmioSetInfoに渡して、 バッファへの直接アクセスを終了してください。バッファに書き込みを行った場合は、 mmioSetInfoを呼び出す前に、 MMIOINFO構造体のdwFlagsメンバにMMIO_DIRTYフラグを設定してください。これを行わないと、 バッファがディスクへフラッシュされません。

メモリ ファイルに対するファイル入出力の実行

マルチメディア ファイル入出力サービスでは、 メモリ ブロックをファイルとして扱うことができます。すでにメモリ内にファイル イメージを持っている場合に便利です。メモリ ファイルを使えば、 入出力の際に、 ファイルのメモリ イメージをディスク ベースのファイルであるかのように扱えるため、 コードの例外条件の数を減らすことができます。また、 クリップボードでメモリ ファイルを使うこともできます。

メモリ ファイルのオープン

メモリ ファイルには、 入出力バッファと同様に、 アプリケーションまたはファイル入出力マネージャが割り当てたメモリを使うことができます。また、 メモリ ファイルには、 拡張可能と拡張不可能のどちらかを指定できます。ファイル入出力マネージャは、 拡張可能メモリ ファイルの終端に達すると、 あらかじめ定義された増分だけメモリ ファイルを拡張します。

メモリ ファイルをオープンするには、 mmioOpenを使います。szFilenameパラメータにはNULLを指定し、 dwOpenFlagsパラメータにはMMIO_READWRITEフラグを指定します。また、 lpmmioinfoパラメータには、 次のように設定したMMIOINFO構造体を指すポインタを指定してください。

pIOProcメンバに、 NULLを設定します。

fccIOProcメンバに、 FOURCC_MEMを設定します。

pchBufferメンバに、 メモリ ブロックを指すポインタを設定します。ファイル入出力マネージャにメモリ ブロックの割り当てを要求する場合は、 pchBufferをNULLにしてください。

cchBufferメンバに、 メモリ ブロックの初期サイズを設定します。

adwInfo[0]メンバに、 メモリ ブロックの最小拡張サイズを設定します。拡張不可能メモリ ファイルでは、 adwInfo[0]はNULLにしてください。

ほかのメンバは、 すべて0にしてください。

メモリ ファイル用のメモリの割り当て

拡張不可能なメモリ ファイルで使用するメモリの割り当てに関しては、 何の制限もありません。スタティック メモリ、 スタック メモリ、 ローカルまたはグローバルに割り当てたメモリのいずれも使用できます。拡張可能なメモリ ファイルには、 GlobalAllocで割り当ててGlobalLockでロックしたメモリを使わなければなりません。

カスタム入出力プロシージャの使用

マルチメディア ファイル入出力サービスは、 入出力プロシージャを使って、 ファイル アーカイブ システムやデータベース記憶システムなどの多様な記憶システムの読み書きに対応した、 物理的な入力と出力を扱います。標準Microsoft(R) Windows(TM) ファイルとメモリ ファイルには、 定義済みの入出力プロシージャがあります。将来は、 複合ファイルの要素をアクセスするための定義済み入出力プロシージャが提供される予定です。複合ファイルとは、 ファイル要素と呼ばれる多くの個別のファイルを組み合わせて1つの物理的なファイルを構成したものです。

データベースやファイル アーカイブのような固有の記憶システムにアクセスするために、 カスタム入出力プロシージャを供給することができます。このような入出力プロシージャは、 1つのアプリケーションにプライベートにするか、 ほかのアプリケーションと共有することができます。

マルチメディア ファイル入出力サービスは、 カスタム入出力プロシージャをサポートするために、 次の関数を提供しています。

関数 説明

mmioInstallIOProc 入出力プロシージャのインストール、 削除、 検索を行います。

mmioSendMessage カスタム メッセージを、 ファイルに関連付けられている入出力プロシージャに送ります。

カスタム入出力プロシージャによるファイルのオープン

入出力プロシージャの作成方法について学ぶ前に、 その使用方法を理解した方がよいでしょう。カスタム入出力プロシージャを使ってファイルをオープンするには、 ほかのファイルのオープンと同様に、 mmioOpenを使います。ファイル名の物理ファイル名とオープンしたいファイル エレメント名を区切るには、 プラス (+) 記号を使ってください。たとえば、 次の例では、 filename.arcというファイルのelementというファイル要素をオープンしています。

mmioOpen("filename.arc+element", NULL, MMIO_READ);

ファイル入出力マネージャは、 ファイル名にプラス記号を見つけると、 そのファイルに関連付けられている入出力プロシージャをファイル名拡張子から決定します。上記の例では、 ファイル入出力マネージャは、 .ARCファイル名拡張子に関連付けられた入出力プロシージャを使おうとします。入出力プロシージャがまったくインストールされていない場合、 mmioOpen関数はエラーを返します。

入出力プロシージャの作成

入出力プロシージャは、 アプリケーションが供給するメッセージ処理関数です。入出力プロシージャ関数の構文は次のとおりです。

LRESULT IOProc(lpmmioinfo, wMsg, lParam1, lParam2)

lpmmioinfoパラメータは、 アクセス中のファイルに関連付けられているMMIOINFO構造体を指すポインタを示します。

wMsgパラメータはUINT型で、 ファイル入出力マネージャから入出力プロシージャに送られたメッセージを示します。

lParam1パラメータはLPARAM型で、 メッセージによって異なる32ビット情報を示します。

lParam2パラメータはLPARAM型で、 メッセージによって異なる32ビット情報を示します。

戻り値はメッセージによって異なります。入出力プロシージャは、 メッセージを認識できなければ0を返してください。

入出力プロシージャ メッセージ

入出力プロシージャは、 MMIOM_CLOSE MMIOM_OPEN MMIOM_READ MMIOM_WRITE MMIOM_SEEK MMIOM_WRITEFLUSHの各メッセージに応答しなければなりません。これらのメッセージには、 パラメータが2つあります。

また、 カスタム メッセージを作成し、 mmioSendMessage関数を使ってそのメッセージを入出力プロシージャに送ることもできます。独自のメッセージを定義する場合は、 MMIOM_USERメッセージ以上の範囲で定義してください。たとえば、 次のコード例は、 MMIOM_MYMESSAGEという名前のメッセージを定義します。

#defineMMIOM_MYMESSAGE MMIOM_USER + 0

MMIOINFO構造体の使用

入出力プロシージャは、 メッセージを処理するほかに、 lpmmioinfoパラメータが指すMMIOINFO構造体のlDiskOffsetメンバを管理しなければなりません。lDiskOffsetメンバには、 次のMMIOM_READメッセージやMMIOM_WRITEメッセージがアクセスする位置のファイル オフセットを常に設定しておかなければなりません。オフセットはバイト単位で、 ファイルの先頭からの相対値です。入出力プロシージャは、 adwInfo[]メンバを使って必要な状態情報を管理できます。これ以外のMMIOINFO構造体のメンバは、 入出力プロシージャで更新しないでください。

入出力プロシージャのインストール

入出力プロシージャのインストール、 削除、 検索には、 mmioInstallIOProcを使ってください。

たとえば、 ファイル名拡張子ARCに関連付けられている入出力プロシージャは次のようにインストールします。

mmioInstallIOProc (mmioFOURCC('A', 'R', 'C', ' '),
(LPMMIOPROC)lpmmioproc, MMIO_INSTALLPROC);

: アプリケーションを終了する前に、 インストールした入出力プロシージャを必ずすべて削除してください。

mmioOpenのよる入出力プロシージャのインストール

mmioInstallIOProcを使って入出力プロシージャをインストールすると、 そのプロシージャは、 削除するまでインストールされたままになります。入出力プロシージャは、 適切なファイル名拡張子を持つファイルのオープンすべてに使用されます。mmioOpenを使って、 一時的に入出力プロシージャをインストールすることもできます。この場合、 入出力プロシージャはmmioOpenでオープンしたファイルでしか使われず、 ファイルをmmioCloseでクローズすると入出力プロシージャは削除されます。

mmioOpenでファイルをオープンするときに入出力プロシージャを指定するには、 lpmmioinfoパラメータに、 次のようなMMIOINFO構造体を指定してください。

fccIOProcメンバには、 NULLを設定します。

pIOProcメンバに、 入出力プロシージャのプロシージャ インスタンス アドレスを設定します。

ほかのメンバは、 (メモリ ファイルのオープンや、 ファイル入出力バッファへの直接読み書きを行わないかぎり) すべて0にしてください。

マルチメディア ファイルI/O関数

マルチメディア ファイル入出力で使用する関数を次に示します。

mmioAdvance

mmioAscend

mmioClose

mmioCreateChunk

mmioDescend

mmioFlush

mmioFOURCC

mmioGetInfo

mmioInstallIOProc

mmioOpen

MMIOProc

mmioRead

mmioRename

mmioSeek

mmioSendMessage

mmioSetBuffer

mmioSetInfo

mmioStringToFOURCC

mmioWrite

mmsystemGetVersion

▲ページトップに戻る

【本を読んでもよくらからない】 … 個別指導でわかりやすくお教えします
inserted by FC2 system