Microsoft DirectX 8.0 |
ここでは、DVD リージョン選択プロセスが Microsoft® Windows® 9x および Windows 2000 上でどのように動作するかについて述べる。最初に、DVD リージョン情報の 3 つのソースについて説明する。次に、PC システム メーカーがシステムの初期 DVD リージョンをどのように設定するかを説明する。最後に、DVD ナビゲータがドライブ、デコーダ、およびディスク間でどのようにリージョンの一致を決定するかについて説明する。ここでは、アプリケーションおよびデコーダの開発者がコード内に適切な DVD リージョン選択サポートをどのように実装するかを示す。
PC の DVD ドライブに対する初期 DVD リージョンを選択するのは、システム メーカーの役割である。
システム メーカーがレジストリにデフォルト リージョンを設定し、デフォルト リージョンを含むマルチ リージョン ディスクを再生した場合、リージョンはデフォルトに設定されディスクが再生される。ディスクのリージョンがデフォルト リージョンに一致しない場合、ユーザーは必要なリ-ジョンへの変更を求められる。(RPC-1 ドライブに対して行うことができる変更はこの一度だけである。)このデフォルト リージョンがシステム メーカーによって設定されていない場合、Windows はオペレーティング システムのロケール、タイム ゾーンなどに基づいてリージョンを選択する。最初に再生されるディスクがマルチ リージョン ディスクである場合、Windows はロケール、タイムゾーンなどに基づいてリージョンを選択し、最も小さいリージョン番号との一致を探す。マルチ リージョン ディスク上のリージョンと Windows によって選択されたリージョンが 1 つも一致しなかった場合は、ディスク上の最も小さい番号を持つリージョンが選択される。
メーカーがリージョンを設定しなかった場合、Windows 98 オペレーティング システムのベース コンポーンネントはオペレーティング システム言語およびタイム ゾーンに基づいて最初のブート時にリージョンを選択し、ドライブをそのリージョンに設定する。システム メーカーはドライブ上でリージョンを自由に設定できるが、製造プロセスの間に設定が行われなかった場合は、Windows が推測に基づいてドライブのリージョンを選択する。
RPC1 ドライブの場合、ブート アップの間にドライブにディスクがないときはマシンのロケールだけに基づいてデフォルト リージョンが設定される。ブート アップの間にドライブに DVD ディスクがある場合は、デフォルト リージョンがディスクのリージョンと一致すれば選択されてドライブのリージョンになる。一致しない場合は、ディスク上の最も小さい番号のリージョンがドライブの初期リージョンとして選択される。デフォルトが適切ではない場合に、ユーザー (またはシステム メーカー) が行える変更は一度だけである。
RPC2 ドライブの場合、セットアップ プロセスの間に Windows 2000 がドライブにリージョン セット がないこと (フレッシュ ドライブ) を見つけると、上記のようなリージョンを選択するが、これはドライブにディスクがある場合のみである。(ドライブにディスクがない場合、RPC1 ドライブはリージョンを選択しない)。 RPC2 ドライブに対してリージョンがいったん設定されると、オペレーティング システムの再インストールまたはクリーン インストールによって自動的に変更されることはない。
Microsoft DVD ナビゲータは以下の方法を使用して、PC 上で DVD ディスクを再生中にリージョンの一致を確認する。
DVD ナビゲータはディスクのリージョン、ドライバのリージョン、およびデコーダのリージョンを取得する。ディスクのリージョンが "すべてのリージョン" である場合、DVD ナビゲータはディスクを再生する。ディスクにすべてのリージョンに対するマークが付いていない場合、DVD ナビゲータはデコーダにあらかじめ設定されたリージョンがあるかどうかを確認する。デコーダにあらかじめリージョンが設定されており、それがディスクのリージョンと一致しない場合は、DVD ナビゲータはエラーを返し、現在の DVD の設定ではディスクを再生できないということを示す。デコーダのリージョンがディスクのリージョンと同じ場合、DVD ナビゲータはドライブのリージョンがディスクのリージョンと同じかどうかを確認する。同じであれば、DVD ナビゲータはタイトルを再生する。同じでない場合は、DVD ナビゲータはドライブのリージョンを変更するためのコードを呼び出す。使用できるリージョン番号が残っていない場合、リージョン変更の試みは失敗し、そのシステム上でタイトルを再生できない。
Windows 9x の場合、DVD ナビゲータは DVD ドライブ上でのリージョンの変更が必要であることがわかると、DVDRgn.exe を使用してドライブ上のリージョンの変更を要求する。このアプリケーションは、オペレーティング システムの他のコンポーネントと合わせてリージョナライズされる。このアプリケーションは、Windows 98 にデフォルトではインストールされていない。対象となるシステムへのインストールの方法を以下に示す。
Windows 2000 の場合、DVD ナビゲータは DVD マネージャで DVD-ROM ドライブ デバイス上のプロパティ ページを呼び出す。リージョンを変更する必要がある場合は、DVDPlay.exe アプリケーションによってもプロパティ ページが呼び出される。プロパティ ページの UI は DVDRgn.exe の UI によく似ており、オペレーティング システムによってリージョナライズされる。
RPC1 ドライブの場合、Windows オペレーティング システムのコンポーネントがリージョンの変更を管理する。RPC2 ドライブでは、リージョン設定はハードウェア自体に保持される。使用できる変更番号が RPC2 ドライブ上に残っていない場合、ドライブはリージョン変更の呼び出しに失敗し、そのことはオペレーティング システム内のリージョン変更コンポ-ネントによってユーザーに示される。
[Version] Signature=$CHICAGO$ LayoutFile=layout.inf [DestinationDirs] DvdRgnCopy=25 ; Windows DefaultDestDir=25 ; Windows [DefaultInstall] CopyFiles=DvdRgnCopy [DvdRgnCopy] dvdrgn.exe
///////////////////////////////////////////////////////////////////// // ChangeDVDRegion : DVD ドライブのリージョンを変更する関数 // // パラメータ : // In : hWnd - この関数を呼び出すアプリケーション // のウィンドウ ハンドル // Out : なし。 // // 以下の値を返す : // TRUE : ドライブのリージョン変更が成功した場合 // FALSE : リージョン変更が失敗した場合 (おそらく、 // 有効な DVD-V ディスクのあるドライブが見つからないため)。 ///////////////////////////////////////////////////////////////////// BOOL ChangeDVDRegion(HWND hWnd) { typedef BOOL (APIENTRY *DVDPPLAUNCHER) (HWND hWnd, CHAR DriveLetter); BOOL bRegionChanged = FALSE; TCHAR szCmdLine[MAX_PATH]; // まず、有効な DVD-V ディスクのある DVD ドライブはどれかを見つける。 TCHAR szDVDDrive[4]; if (! GetDriveLetter (szDVDDrive) ) { MessageBox(hWnd, TEXT("No DVD drive was found with DVD-V disc.") TEXT("\nCannot change DVD region of the drive."), TEXT("Error"), MB_OK | MB_INFORMATION) ; return FALSE ; } // 実行中の OS を検出する。Windows NT の場合、storprop.dll を使用し、 // Windows 9x の場合は DVDRgn.exe アプリケーションを使用してリージョンを変更する。 OSVERSIONINFO ver; ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&ver); if (VER_PLATFORM_WIN32_NT == ver.dwPlatformId) { // Windows NT プラットフォーム HINSTANCE hInstDLL; DVDPPLAUNCHER dvdPPLauncher; CHAR szDVDDriveA[4]; #ifdef UNICODE WideCharToMultiByte(0, 0, szDVDDrive, -1, szDVDDriveA, sizeof(szDVDDriveA), NULL, NULL ); #else strcpy(szDVDDriveA, szDVDDrive); #endif // UNICODE GetSystemDirectory(szCmdLine, MAX_PATH); lstrcat(szCmdLine, TEXT("\\storprop.dll")); hInstDLL = LoadLibrary (szCmdLine); if (hInstDLL) { dvdPPLauncher = (DVDPPLAUNCHER) GetProcAddress(hInstDLL, "DvdLauncher"); if (dvdPPLauncher) { bRegionChanged = dvdPPLauncher(hWnd, szDVDDriveA[0]); } FreeLibrary(hInstDLL); } } // Windows NT プラットフォーム用のリージョン変更コードの終わり else // Windows 9x プラットフォーム { // コマンド ライン文字列用の \windows\dvdrgn.exe のパスを取得する GetWindowsDirectory(szCmdLine, MAX_PATH); lstrcat(szCmdLine, TEXT("\\DVDRgn.exe ")); // コマンド ライン パラメータとしてドライブ レターのみ追加する lstrncat(szCmdLine, szDVDDrive, 1); // DVDRgn.exe 実行の準備をする STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInfo; StartupInfo.cb = sizeof(StartupInfo); StartupInfo.dwFlags = STARTF_USESHOWWINDOW; StartupInfo.wShowWindow = SW_SHOWNORMAL; StartupInfo.lpReserved = NULL; StartupInfo.lpDesktop = NULL; StartupInfo.lpTitle = NULL; StartupInfo.cbReserved2 = 0; StartupInfo.lpReserved2 = NULL; if (CreateProcess(csModuleName, szCmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &StartupInfo, &ProcessInfo) ) { // DVDRgn.exe が終了するまで待つ WaitForSingleObject(ProcessInfo.hProcess, INFINITE); DWORD dwRet = 1; BOOL bRet = GetExitCodeProcess(ProcessInfo.hProcess, &dwRet); // ユーザーがドライブのリージョン変更に成功した場合、 // DVDRgn.exe の終了コードは 0。 if (bRet && 0 == dwRet) { bRegionChanged = TRUE; } } } // Windows 9x プラットフォーム用のリージョン変更コードの終わり if (bRegionChanged) // リージョンの変更が成功した場合 { // 古いフィルタ グラフを削除して新しいフィルタ グラフを作成するために、 // IDvdGraphBuilder::RenderDvdVideoVolume() を使用する。 } else // DVD リージョンがなかった { MessageBox(hWnd, TEXT("DVD drive region could not be changed.") TEXT("Error"), MB_OK | MB_INFORMATION) ; } } //関数 ChangeDVDRegion の終わり ///////////////////////////////////////////////////////////////////// // GetDriveLetter : 現在アクティブなドライブのドライブ レターを // 取得する関数 // パラメータ : // In : pDvdC - DVDNavigator フィルタの IDvdControl // インターフェイスへのポインタ.. // Out : pszDrive - 有効な DVD-V ディスクがあることがわかった、 // 最初の DVD ドライブ。 // // 以下の値を返す : // TRUE : DVD ドライブが検出された場合 (有効なディスクと共に) // FALSE : 有効な DVD-V ディスクのある DVD ドライブが検出されなかった場合。 ///////////////////////////////////////////////////////////////////// BOOL GetDriveLetter(IDvdControl *pDvdC, TCHAR *pszDrive) { CHAR szPathA[MAX_PATH]; TCHAR szPath[MAX_PATH]; ULONG ulActualSize; pszDrive[0] = pszDrive[3] = 0; // 現在のルート ディレクトリを取得する if (pDvdC ->GetRoot(szPathA, MAX_PATH, &ulActualSize)) { #ifdef UNICODE MultiByteToWideChar(CP_ACP, 0, szPathA, 0, szPath, MAX_PATH); #else lstrcpy(szPath, szPathA); #endif // UNICODE lstrcpyn(pszDrive, szPath, 3); if (DRIVE_CDROM == GetDriveType(pszDrive)) // DVD ドライブ の場合 return TRUE; } // 有効なドライブ全体をループして、有効な DVD-V ディスクが入っている // DVD ドライブはどれかを見つける。 // 有効なドライブをすべて取得する DWORD dwLeng = GetLogicalDriveStrings(MAX_PATH, szPath); TCHAR *pszTemp = szPath; // すべてのドライブを 1 つずつ試す for (DWORD dw = 0; dw < dwLeng; dw += 4) { // 必要な (.ifo) ファイルを持つ CD-ROM ドライブのみ調べる if (DRIVE_CDROM == GetDriveType(pszTemp)) { TCHAR szDVDPath1[MAX_PATH] TCHAR szDVDPath2[MAX_PATH]; lstrcpyn(szDVDPath1, pszTemp, 4); lstrcpyn(szDVDPath 2, pszTemp, 4); lstrcat(szDVDPath1, TEXT("Video_ts\\Video_ts.ifo")); lstrcat(szDVDPath2, TEXT("Video_ts\\Vts_01_0.ifo")); // .ifo ファイルがドライブ上にある場合、それは有効な DVD-V ディスクを持っている if (DoesFileExist(achDVDPath1) && DoesFileExist(achDVDPath2)) { lstrcpyn(pszDrive, pszTemp, 3); return TRUE; // 有効な DVD-V ディスクを持っている最初のドライブを返す } } pszTemp += 4; } return FALSE ; // DVD ドライブ (DVD-V コンテンツを含む) が見つからなかった。 } //関数 GetDriveLetter の終わり ///////////////////////////////////////////////////////////////////// // DoesFileExist : 特定のファイル名が既存のファイルであるかどうかを確認する関数。 // // パラメータ : // In : pszFile - 存在を確認するファイル名の文字列 // Out : なし。 // // 以下の値を返す : // TRUE : 指定されたファイルが見つかった場合。 // FALSE : 指定されたファイルが見つからなかった場合。 ///////////////////////////////////////////////////////////////////// BOOL DoesFileExist(LPTSTR pszFile) { HANDLE hFile = NULL ; // 必要なファイルを開いて読むことができるかどうかテストを試みる場合に、 // エラー メッセージ ボックスが表示されないようにしたい。 UINT uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); SetErrorMode(uErrorMode); // エラー モードを回復する。 If (INVALID_HANDLE_VALUE == hFile) return FALSE ; CloseHandle(hFile); return TRUE; } //関数 DoesFileExist の終わり