第166章 高レベルMCIの基礎


今回から高レベルMCIについて解説します。 MCIとはMedia Control Interface の略で各種マルチメディアとの 間のインターフェイスを提供します。その中でも高レベルのものは 扱いが簡単で、多数のマクロが用意されています。今回は いろいろなマルチメディアを再生できるプログラムを作って みます。



今回作るプログラムの外観です。マルチメディアのファイルは たいていのものを開くことができます。メニューの「MCI」「開く」 でファイルを開きます。あとはメニューの「MCI」「PLAY」または、 三角形の再生ボタンを押せば再生が始まります。 左の図はVC++についてきたfilevome.aviを再生しているところです。



MCIWndウィンドウクラスはマルチメディア関連の再生・記録関連の ウィンドウを作ります。 準備としては

1.vfw.hをインクルードします。 2.vfw32.libをリンクします。

を行って下さい。MCIWndクラスのウィンドウを作るには

HWND MCIWndCreate( HWND hwndParent, HINSTANCE hInstance, DWORD dwStyle, LPSTR szFile );

を使います。

hwndParentは、親ウィンドウを指定します。

hInstanceには、インスタンスハンドルを指定します。

dwStyleにはウィンドウスタイルを指定します。CreateWindowEx関数で 使うウィンドウスタイルのほかに、いろいろなスタイルが用意されています。 MCIWNDF_というプレフィックスが付きます。MCIWNDF_NOOPENはツールバーの 「開く」コマンドを隠します。

szFileはオープンするMCIデバイスまたはファイルを指定します。

一番簡単な例は

MCIWndCreate(hWnd, hInst, 0, "a:\\test.wav");

です。これでtest.wavを開くことができます。

LONG MCIWndChangeStyles( hwnd, mask, value );

MCIWndウィンドウのスタイルを変更するマクロです。

maskには、スタイルを指定するマスクを指定します。

valueには、ウィンドウの新しいスタイルを指定します。

maskとvalueにはMCIWNDF_で始まる値を設定します。vfw.h を調べてみてください。

LONG MCIWndPlay( hwnd );

これは、マクロです。hwndにMCIWndCreateで作成したウィンドウの ハンドルを指定します。現在位置からの再生を開始します。

BOOL MCIWndCanPlay( hwnd );

再生できるかどうかを調べるマクロです。可能な場合はTRUEを返します。 だめな場合はFALSEを返します。

LONG MCIWndOpen( hwnd, szFile, wFlags );

MCIデバイスをオープンしてMCIWndウィンドウと関連付けるマクロです。

szFileにはMCIデバイスのタイプ名、またはファイル名を指定します。

wFlagsにはオープンに関連するフラグを指定します。MCIWNDOPENF_NEW以外は 0を指定しておいて下さい。

VOID MCIWndDestroy( hwnd );

MCIWndウィンドウを破棄します。

では、プログラムを見てみることにします。

// mciwnd01.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "MCI(&M)" BEGIN MENUITEM "開く(&O)", IDM_OPEN MENUITEM "プレイ(&P)", IDM_PLAY END END

これは、ごく普通のメニューのリソース・スクリプトです。

// mciwnd01.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <vfw.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void OpenMyMci(HWND, char *); char szClassName[] = "mciwnd01"; //ウィンドウクラス HINSTANCE hInst; int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }

vfw.hをインクルードするのを忘れないでください。また、vfw32.libを リンクするのも忘れないでください。 現在のインスタンスハンドルをグローバル変数にコピーしています。

//ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); }

メニュー名を忘れないでください。

//ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるMCIWnd", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

いつもと同じです。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HWND hMCIWnd; static char FileName[MAX_PATH]; RECT rc; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_OPEN: OpenMyMci(hWnd, FileName); MCIWndOpen(hMCIWnd, FileName, NULL); GetWindowRect(hMCIWnd, &rc); AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, TRUE); MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); break; case IDM_PLAY: if (!MCIWndCanPlay(hMCIWnd)) { MessageBox(hWnd, "再生できません", "Error", MB_OK); break; } MCIWndPlay(hMCIWnd); break; } break; case WM_CREATE: hMCIWnd = MCIWndCreate(hWnd, hInst, 0, NULL); if (hMCIWnd == NULL) { MessageBox(hWnd, "MCIウィンドウ作成失敗", "Error", MB_OK); break; } MCIWndChangeStyles(hMCIWnd, MCIWNDF_NOOPEN, MCIWNDF_NOOPEN); GetWindowRect(hMCIWnd, &rc); AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, TRUE); MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { MCIWndDestroy(hMCIWnd); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

メニューの「開く」(IDM_OPEN)が選択されたら自作関数のOpenMyMci(後述)を呼びます。 これで、FileNameにファイル名(フルパス付き)をコピーします。次にMCIWndOpenで このファイルを開きます。そして、その時のMCIWndウィンドウの大きさを調べます。 親ウィンドウのクライアント領域の大きさをこれに合わせます。 クライアント領域の大きさを合わせるにはAdjustWindowRect関数を使うのが便利です。 (第93章参照)ただし、この関数で求めたウィンドウの 大きさはメニューが2列以上になった時は正しくありません。つまり、小さいaviファイルを オープンした時は親ウィンドウのメニューが2列になり正しく表示されません。

メニューの「再生」(IDM_PLAY)が選択された時はまず、MCIWndCanPlayマクロで 再生できるかどうかを調べて、可能ならMCIWndPlayで再生を始めます。再生できない時は その旨メッセージボックスで知らせます。

WM_CREATEがきたら、MCIWndCreateでMCIWndウィンドウを作り、 親ウィンドウの大きさを調整します。

プログラム終了時にMCIWndDestroyでウィンドウを破棄します。

void OpenMyMci(HWND hWnd, char *FileName) { OPENFILENAME ofn; static int nIndex = 0; static char szInitialDir[MAX_PATH] = ""; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.lpstrFilter = "waveaudio(*.wav)\0*.wav\0digitalvideo(*.avi)\0*.avi\0All Files(*.*)\0*.*\0\0"; ofn.lpstrFile = FileName; ofn.nMaxFile = 256; ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrTitle = "マルチメディア"; ofn.nFilterIndex = nIndex; ofn.lpstrInitialDir = szInitialDir; GetOpenFileName(&ofn); nIndex = ofn.nFilterIndex; strcpy(szInitialDir, ofn.lpstrInitialDir); return; }

コモンダイアログを利用しています。一度ファイルを開いたらこの時の ディレクトリとファイルフィルタを記憶しておいて、次回そのディレクトリと ファイルフィルタでダイアログボックスをオープンするようにしてみました。

MCIWndに関してはVC++6.0のヘルプにはなぜか載っていません。 VC++4.xには記載があります。VC++6.0の人はヘッダファイルをよく調べてみてください。


[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 30/Dec/1998 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。