MCI ウィンドウ


高水準 API

動画や音声ファイルの再生など、ユーザーにより直接的な刺激を与えるプログラム
すなわちマルチメディアという世界は、多くのプログラマの憧れでしょう
マルチメディアは、ユーザーの視覚や聴覚に直接刺激を与える華やかな世界です

Microsoft の Windows の戦略の一つに、マルチメディアのサポートがありました
パーソナルコンピュータの世界では、マルチメディアの歴史はまだ浅く
動画や音声を標準でサポートできるようになったのは、つい最近といえます

Windows 98 以降であれば、強力にマルチメディアがサポートされているでしょう
大抵の動画は見れますし、その時代のコンピュータは、ほとんどが CD ドライブを持っています
今となっては DVD や CD-RW が当たり前ですが、98 の時代は FD と CD が標準的でした
とりあえず、このマルチメディア編を読むには、CD とスピーカが付いているマシンで
ある程度、動画や音声ファイルは苦無く再生できるものと仮定します

Win32 マルチメディア API は、大別して3種類に分けることができます
それらは、高レベル中レベル低レベル API の3つです
高レベルとは、すなわち高水準な API で、高い生産性を持った完成された API です
逆に、低レベル API は低水準な、ビットレベルで音声を扱ったりする難解な API を指します

この場では、高レベル API から紹介し、中レベル、低レベルという順で解説を進めます
ただし、一つだけ注意してほしいことがあります
多くの場合、高レベル API を使うだけで、十分マルチメディアファイルを扱えます
少し複雑なことをやる時に中レベル API を使う程度でしょう

しかし、高レベル API を使って動画や音声ファイルを再生したとしても
それはあなたのプログラムではなく、Windows の DLL が作業をしているということであり
動画や音声を扱っているのは、あなたの技術力ではなく Windows の技術力です

高レベル API のような、華やかで簡素で生産性の高い手法を知ってしまうと
難解で緻密な低レベル API を学習する意欲を失ってしまうかもしれません
低レベル API を学習するには、数学、及び物理学の知識も必要となります
しかし、低レベル API を扱えることにより、より高度で繊細なアプリケーションを作れますし
何より、マルチメディアの本質を知ることができます
簡単な高レベル、中レベル API に満足することなく、低レベル API の学習をしてください
動けば良いのではなく、本質を知ることに意義があることを忘れないでください

さて、高レベル API とはすなわち MCI ウィンドウのことを言います
これは Windows 95 から導入された API で、簡単にメディアファイルを再生できます
MCI ウィンドウとは MCIWnd ウィンドウクラスで作られたウィンドウを示します

高レベル API を用いる場合、vfw.h ヘッダをインクルードしなければなりません
そして、コンパイルする時は vfw32.lib インポートライブラリを用いてください
そうしなければ、DLL の関数を呼び出すことができません

まず、MCI ウィンドウを作成するために MCIWndCreate() 関数を使います
この関数を使って、ウィンドウを生成し、ファイルと関連付けるだけで再生できます
HWND MCIWndCreate(
	HWND hwndParent , HINSTANCE hInstance ,
	DWORD dwStyle , LPSTR szFile
);
hwndParent には、MCI ウィンドウの親ウィンドウのハンドルを
hInstance には、ウィンドウに関連付けるインスタンスのハンドルを指定します

dwStyle は、ウィンドウのスタイルをあらわすフラグを指定します
従来のウィンドウスタイルを指定することができ、通常 WS_CHILD を必ず指定します
これに加え、次の値を組み合わせて指定することもできます

定数解説
MCIWNDF_NOAUTOSIZEMOVIE MCIWnd ウィンドウのサイズが変化しても
ディスティネーション矩形の寸法を変更しない
MCIWNDF_NOAUTOSIZEWINDOW イメージのサイズが変化しても
MCI のウィンドウサイズは変更しない
MCIWNDF_NOERRORDLG MCIエラーのユーザーへの表示を禁止する
MCIWNDF_NOMENU ツールバーの「メニュー」ボタンを隠す
MCIWNDF_NOOPEN MCIWnd メニューの「開く」及び「閉じる」コマンドを隠す
MCIWNDF_NOPLAYBAR ツールバーを隠す
MCIWNDF_NOTIFYALL 全ての MCIWNDF ウィンドウ通知スタイルを使用する
MCIWNDF_NOTIFYERROR MCI エラーの発生を親ウィンドウに通知する
MCIWNDF_NOTIFYMEDIA 新規デバイスの仕様とデータファイルのオープン、クローズを
MCIWNDM_NOTIFYMEDIA メッセージで親ウィンドウに通知する
MCIWNDF_NOTIFYMODE デバイス動作モードの変更を
MCIWNDM_NOTIFYMODE メッセージで親ウィンドウに通知する
MCIWNDF_NOTIFYPOS コンテンツ内の再生位置、記録位置の変更を
MCIWNDM_NOTIFYPOS メッセージで親ウィンドウに通知する
MCIWNDF_NOTIFYSIZE MCI ウィンドウのサイズの変更を親ウィンドウに通知する
MCIWNDF_RECORD MCI デバイスに記録機能がある場合、ツールバーに「記録」ボタンを追加し
メニューに新しいファイルコマンドを追加する
MCIWNDF_SHOWALL 全ての MCIWINDF_SHOW スタイルを使う
MCIWNDF_SHOWMODE MCI デバイスの現在のモードを、ウィンドウのタイトルバーに表示する
MCIWNDF_SHOWNAME 開いている MCI デバイス、またはデータファイルの名前を
MCI ウィンドウのタイトルバーに表示する
MCIWNDF_SHOWPOS MCI デバイスのコンテンツ内の現在位置を
ウィンドウのタイトルバーに表示する

szFile には、再生するファイル名、または MCI デバイス名を指定します
MCI デバイスとは、例えば CD ドライブなどが考えられます
ファイル名以外でも、CD ドライブに好きな CD を挿入し
szFile に "cdaudio" と指定すれば、CD の音楽を再生することができます

関数が成功すれば MCI ウィンドウのハンドルが、失敗すれば 0 が返ります
さて、これだけで szFile で指定したマルチメディアファイルを開くことができます
そのファイルの形式を Windows がサポートしているならば、です

MCI ウィンドウが不用になれば MCIWndDestroy() マクロを呼び出します
このマクロは、MCI デバイス、またはファイルを閉じて MCI ウィンドウを破棄します

VOID MCIWndDestroy(HWND hwnd);

hwnd には、破棄する MCI ウィンドウのハンドルを指定します
たったこれだけの関数とマクロで、AVI、MPEG、WAVE など
代表的なマルチメディアファイルのほとんどを再生することができるようになります
#include <windows.h>
#include <vfw.h>
#define TITLE TEXT("Kitty on your lap")

PSTR strAvi;

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	static HWND hMCI;

	switch (msg) {
	case WM_DESTROY:
		MCIWndDestroy(hMCI);
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		hMCI = MCIWndCreate(hWnd , ((LPCREATESTRUCT)lp)->hInstance ,
			WS_CHILD | WS_VISIBLE | WS_BORDER  , strAvi);
		return 0;
	case WM_SIZE:
		MoveWindow(hMCI , 0 , 0 , LOWORD(lp) , HIWORD(lp) , FALSE);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hWnd;
	MSG msg;
	WNDCLASS winc;

	strAvi = lpCmdLine;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hWnd = CreateWindow(
			TEXT("KITTY") , TITLE ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL , hInstance , NULL
	);
	if (hWnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
©KANEKO , アストロビジョン , CULTURE PUBLISHERS
PSゲーム「ひざの上の同居人〜Kitty on your lap〜」より
©KANEKO, アストロビジョン, CULTURE PUBLISHERS
あぁ…趣味が見え隠れ……。っえ!?もうバレてる?

このプログラムは、コマンドライン引数で指定したファイルを MCI ウィンドウで開きます
上の図は、コマンドラインから *.AVI 形式の動画ファイルを再生したものです
再生ボタン、スライダーなど、基本的なインターフェイスも初期からサポートされています

MCI で開いている MCI デバイスやファイルを変更する場合
まず、MCIWndClose() マクロでいま開いているファイルなどを閉じます

LONG MCIWndClose(HWND hwnd);

hwnd には、MCI ウィンドウのハンドルを指定します
戻り値は常に 0 です

このマクロによって、現在開いているファイル、または MCI デバイスが閉じられます
その後も MCI ウィンドウは有効なので MCIWndOpen() マクロを使って
新しい MCI デバイス、またはファイルを関連付けることができます

LONG MCIWndOpen(HWND hwnd , LPVOID szFile , UINT wFlags);

hwnd には MCI ウィンドウのハンドルを
szFile には MCI デバイス、またはファイル名を示す文字列を指定します
この引数に -1 を指定すると「開く」ダイアログボックスが表示されます

wFlags には、開く MCI デバイス、またはファイルに関連するフラグを指定します
この引数に指定できるフラグは、現在 MCIWNDOPENF_NEW だけです
このフラグは、szFile で指定した名前で新しいファイルを作成します
正常終了すれば 0、そうでなければエラーコードが返されます

これで、現在のメディアを閉じて、新しいメディアを関連付けられます
プログラムから明示的にメディアを再生したい場合 MCIWndPlay() を使います

LONG MCIWndPlay(HWND hwnd);

hwnd には、MCI ウィンドウのハンドルを指定します
正常終了すれば 0、そうでなければエラーコードを返します
/*resource.h*/
#define IDM_OPEN 100
/*リソーススクリプト*/
#include "resource.h"
KITTY MENU {
	POPUP "File(&F)" {
		MENUITEM "Open(&O)" , IDM_OPEN
	}
}
#include <windows.h>
#include <vfw.h>
#include "resource.h"
#define TITLE TEXT("Kitty on your lap")

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	static HWND hMCI;
	static OPENFILENAME ofn;
	static TCHAR strFile[MAX_PATH];

	switch (msg) {
	case WM_DESTROY:
		MCIWndDestroy(hMCI);
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		ofn.lStructSize = sizeof (OPENFILENAME);
		ofn.hwndOwner = hWnd;
		ofn.lpstrFilter = TEXT("Mdia File \0*.avi;*.mpg;*.wav\0");
		ofn.nMaxCustFilter = 256;
		ofn.nFilterIndex = 0;
		ofn.lpstrFile = strFile;
		ofn.nMaxFile = MAX_PATH;
		ofn.Flags = OFN_FILEMUSTEXIST;
		
		hMCI = MCIWndCreate(hWnd , ((LPCREATESTRUCT)lp)->hInstance ,
			WS_CHILD | WS_VISIBLE | MCIWNDF_NOPLAYBAR , NULL);
		return 0;
	case WM_COMMAND:
		switch (LOWORD(wp)) {
		case IDM_OPEN:
			if (GetOpenFileName(&ofn)) {
				MCIWndClose(hMCI);
				MCIWndOpen(hMCI , strFile , 0);
				MCIWndPlay(hMCI);
			}
		}
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hWnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= TEXT("KITTY");
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hWnd = CreateWindow(
			TEXT("KITTY") , TITLE ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL , hInstance , NULL
	);
	if (hWnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
©KANEKO , アストロビジョン , CULTURE PUBLISHERS
PSゲーム「ひざの上の同居人〜Kitty on your lap〜」より
©KANEKO, アストロビジョン, CULTURE PUBLISHERS

このプログラムは、上の図でわかるようにメニューバーが付属しています
メニューの Open 項目を選択すると、ファイル選択ダイアログボックスが出現します
ファイルを選択すれば、指定したメディアファイルが自動的に再生されます

機能は貧弱ですが、これだけのソースでマルチメディアプレーヤーが作れました
いかに高レベル API が優れた機能を提供しているかわかります


MCIWndCreate()

HWND MCIWndCreate(
	HWND hwndParent , HINSTANCE hInstance ,
	DWORD dwStyle , LPSTR szFile
);
MCIWnd ウィンドウクラスのウィンドウを作成します

hwndParent - MCI ウィンドウの親ウィンドウのハンドルを指定します
hInstance - ウィンドウに関連付けるインスタンスのハンドルを指定します
dwStyle - ウィンドウのスタイルをあらわすフラグを指定します
szFile - 再生するファイル名、または MCI デバイス名を指定します

戻り値 - 成功すれば MCI ウィンドウのハンドル、失敗すれば 0

dwStyle には、ウィンドウスタイルに加え、以下のスタイルを組み合わせて指定できます

定数解説
MCIWNDF_NOAUTOSIZEMOVIE MCIWnd ウィンドウのサイズが変化しても
ディスティネーション矩形の寸法を変更しない
MCIWNDF_NOAUTOSIZEWINDOW イメージのサイズが変化しても
MCI のウィンドウサイズは変更しない
MCIWNDF_NOERRORDLG MCIエラーのユーザーへの表示を禁止する
MCIWNDF_NOMENU ツールバーの「メニュー」ボタンを隠す
MCIWNDF_NOOPEN MCIWnd メニューの「開く」及び「閉じる」コマンドを隠す
MCIWNDF_NOPLAYBAR ツールバーを隠す
MCIWNDF_NOTIFYALL 全ての MCIWNDF ウィンドウ通知スタイルを使用する
MCIWNDF_NOTIFYERROR MCI エラーの発生を親ウィンドウに通知する
MCIWNDF_NOTIFYMEDIA 新規デバイスの仕様とデータファイルのオープン、クローズを
MCIWNDM_NOTIFYMEDIA メッセージで親ウィンドウに通知する
MCIWNDF_NOTIFYMODE デバイス動作モードの変更を
MCIWNDM_NOTIFYMODE メッセージで親ウィンドウに通知する
MCIWNDF_NOTIFYPOS コンテンツ内の再生位置、記録位置の変更を
MCIWNDM_NOTIFYPOS メッセージで親ウィンドウに通知する
MCIWNDF_NOTIFYSIZE MCI ウィンドウのサイズの変更を親ウィンドウに通知する
MCIWNDF_RECORD MCI デバイスに記録機能がある場合、ツールバーに「記録」ボタンを追加し
メニューに新しいファイルコマンドを追加する
MCIWNDF_SHOWALL 全ての MCIWINDF_SHOW スタイルを使う
MCIWNDF_SHOWMODE MCI デバイスの現在のモードを、ウィンドウのタイトルバーに表示する
MCIWNDF_SHOWNAME 開いている MCI デバイス、またはデータファイルの名前を
MCI ウィンドウのタイトルバーに表示する
MCIWNDF_SHOWPOS MCI デバイスのコンテンツ内の現在位置を
ウィンドウのタイトルバーに表示する

MCIWndDestroy()

VOID MCIWndDestroy(HWND hwnd);

MCI ウィンドウを破棄します

hwnd - 破棄する MCI ウィンドウのハンドルを指定します

MCIWndClose()

LONG MCIWndClose(HWND hwnd);

MCI ウィンドウに関連付けられているメディアを破棄します

hwnd - MCI ウィンドウのハンドルを指定します

戻り値 - 常に 0

MCIWndOpen()

LONG MCIWndOpen(HWND hwnd , LPVOID szFile , UINT wFlags);

MCI ウィンドに、新しい MCI デバイス、またはファイルを関連付けます

hwnd - MCI ウィンドウのハンドルを指定します
szFile - MCI デバイス、またはファイル名を示す文字列を指定します
wFlags - 開く MCI デバイス、またはファイルに関連するフラグを指定します
戻り値 - 正常終了すれば 0、そうでなければエラーコード

wFlags には、以下のフラグを指定することができます

定数解説
MCIWNDOPEN_NEW szFile で指定した名前で新しいファイルを作成します

MCIWndPlay()

LONG MCIWndPlay(HWND hwnd);

MCI ウィンドウのコンテンツを再生します

hwnd - MCI ウィンドウのハンドルを指定します

戻り値 - 正常終了すれば 0、そうでなければエラーコード



戻る次のページへ