Adding Region-Change Support to an Application
Microsoft DirectShow 9.0 |
Adding Region-Change Support to an Application
The following functions are provided for developers who wish to integrate region-change support into their decoders or DVD applications.
// Forward declares, constants, typedefs. const short MAX_DRIVE_NAME = 4; struct DriveName { TCHAR name[MAX_DRIVE_NAME]; }; BOOL DoesFileExist(LPTSTR pszFile); BOOL GetDriveLetter(IDvdInfo2 *pDvd, DriveName& szDrive); #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) ///////////////////////////////////////////////////////////////////// // ChangeDVDRegion : Function to change the DVD drive region. // Parameters: // hWnd - Handle to the application window. // Returns TRUE if the change is successful, or FALSE otherwise. // (Failure usually means there was no drive with a valid DVD-V disc.) ///////////////////////////////////////////////////////////////////// BOOL ChangeDVDRegion(HWND hWnd, IDvdInfo2 *pDvd) { typedef BOOL (APIENTRY *DVDPPLAUNCHER) (HWND hWnd, CHAR DriveLetter); // First find out which drive is a DVD drive with a valid DVD-V disc. DriveName szDVDDrive; if (! GetDriveLetter(pDvd, szDVDDrive) ) { MessageBox(hWnd, TEXT("No DVD drive was found with DVD-V disc."), TEXT("Error"), MB_OK | MB_ICONERROR) ; return FALSE; } // Detect which OS we are running on. OSVERSIONINFO ver; ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&ver); if (VER_PLATFORM_WIN32_NT == ver.dwPlatformId) { // For Windows NT, use the storprop.dll, HINSTANCE hInstDLL; DVDPPLAUNCHER dvdPPLauncher; CHAR szDVDDriveA[MAX_DRIVE_NAME]; const TCHAR szDllName[] = TEXT("\\storprop.dll"); // Allocate a large enough string to hold the path + the name. TCHAR szCmdLine[MAX_PATH + (sizeof(szDllName)/sizeof(TCHAR)) + 1]; #ifdef UNICODE WideCharToMultiByte(CP_ACP, 0, szDVDDrive.name, -1, szDVDDriveA, sizeof(szDVDDriveA), NULL, NULL ); #else StringCchCopy(szDVDDriveA, MAX_DRIVE_NAME, szDVDDrive.name); #endif UINT cb = GetSystemDirectory(szCmdLine, MAX_PATH + 1); if (cb == 0 || cb > MAX_PATH + 1) { return FALSE; } StringCchCat(szCmdLine, ARRAY_SIZE(szCmdLine), szDllName); hInstDLL = LoadLibrary (szCmdLine); if (hInstDLL) { BOOL bResult = FALSE; dvdPPLauncher = (DVDPPLAUNCHER) GetProcAddress(hInstDLL, "DvdLauncher"); if (dvdPPLauncher) { bResult = dvdPPLauncher(hWnd, szDVDDriveA[0]); } FreeLibrary(hInstDLL); return bResult; } } else { // For Windows 9x use the DVDRgn.exe application. const TCHAR szUtilName[] = TEXT("\\DVDRgn.exe "); // Allocate a large enough string, including a one-character command-line argument. TCHAR szCmdLine[MAX_PATH + (sizeof(szUtilName)/sizeof(TCHAR)) + 2]; // Get path of \windows\dvdrgn.exe for command line string UINT cb = GetWindowsDirectory(szCmdLine, MAX_PATH + 1); if (cb == 0 || cb > MAX_PATH + 1) { return FALSE; } StringCchCat(szCmdLine, ARRAY_SIZE(szCmdLine), szUtilName); // Add only the drive letter as command line parameter StringCchCatN(szCmdLine, sizeof(szCmdLine), szDVDDrive.name, 1); // Prepare to execute 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(0, szCmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &StartupInfo, &ProcessInfo) ) { // Wait until DVDRgn.exe finishes WaitForSingleObject(ProcessInfo.hProcess, INFINITE); DWORD dwRet = 1; BOOL bRet = GetExitCodeProcess(ProcessInfo.hProcess, &dwRet); // If the user changed the drive region // successfully, the exit code of DVDRgn.exe is 0. if (bRet && 0 == dwRet) { return TRUE; } } } return FALSE; } ///////////////////////////////////////////////////////////////////// // GetDriveLetter: Returns the drive letter of the active DVD drive. // Parameters: // pDvdC - IDvdControl2 interface of the DVD Navigator filter. // pszDrive - Receives the first DVD drive with a valid DVD-V disc. // Returns TRUE if there is a DVD drive with a valid disc. ///////////////////////////////////////////////////////////////////// BOOL GetDriveLetter(IDvdInfo2 *pDvd, DriveName& pszDrive) { WCHAR szPathW[MAX_PATH]; TCHAR szPath[MAX_PATH]; ULONG ulActualSize = 0; pszDrive.name[0] = pszDrive.name[MAX_DRIVE_NAME - 1] = 0; // Get the current root directory HRESULT hr = pDvd->GetDVDDirectory(szPathW, MAX_PATH, &ulActualSize); if (SUCCEEDED(hr)) { #ifdef UNICODE StringCchCopy(pszDrive.name, MAX_DRIVE_NAME, szPathW); #else WideCharToMultiByte(CP_ACP, 0, szPathW, ulActualSize, szPath, MAX_PATH, 0, 0); StringCchCopy(pszDrive.name, MAX_DRIVE_NAME, szPath); #endif if (DRIVE_CDROM == GetDriveType(pszDrive.name)) // could be a DVD drive return TRUE; } // Now loop through all the valid drives to detect which one // is a DVD drive with a valid DVD-V disc in it. // Get all valid drives DWORD dwLen = GetLogicalDriveStrings(MAX_PATH, szPath); if (dwLen > MAX_PATH) { // The function returns a larger value if the buffer is too small. return FALSE; } // Try all drives one by one for (size_t dw = 0; dw < dwLen; ) { TCHAR *szTmp = szPath + dw; // Look only for CD-ROM drives that has a disc with required (.ifo) files if (DRIVE_CDROM == GetDriveType(szTmp)) { TCHAR szDVDPath1[MAX_PATH + 1]; TCHAR szDVDPath2[MAX_PATH + 1]; StringCchCopy(szDVDPath1, MAX_DRIVE_NAME, szTmp); StringCchCopy(szDVDPath2, MAX_DRIVE_NAME, szTmp); StringCchCat(szDVDPath1, ARRAY_SIZE(szDVDPath1), TEXT("Video_ts\\Video_ts.ifo")); StringCchCat(szDVDPath2, ARRAY_SIZE(szDVDPath2), TEXT("Video_ts\\Vts_01_0.ifo")); // If the .ifo files exist on this drive then it has a valid DVD-V disc if (DoesFileExist(szDVDPath1) && DoesFileExist(szDVDPath2)) { StringCchCopy(pszDrive.name, MAX_DRIVE_NAME, szTmp); return TRUE; // return the first drive that has a valid DVD-V disc } } size_t len = 0; StringCchLength(szTmp, STRSAFE_MAX_CCH, &len); dw += len + 1; } return FALSE ; // didn't find any DVD drive with DVD-V content } ///////////////////////////////////////////////////////////////////// // DoesFileExist : Determines whether a specified file exists // Parameters: // pszFile - File name to check. // Returns TRUE if the specified file is found, or FALSE otherwise. ///////////////////////////////////////////////////////////////////// BOOL DoesFileExist(LPTSTR pszFile) { if (pszFile == NULL) { return FALSE; } size_t len = 0; if (FAILED(StringCchLength(pszFile, STRSAFE_MAX_CCH, &len))) { return FALSE; } if (len > MAX_PATH) { return FALSE; } // We don't want any error message box to pop up when we try to test // if the required file is available to open for read --apcb. UINT uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); HANDLE hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); SetErrorMode(uErrorMode); // restore error mode if (INVALID_HANDLE_VALUE == hFile) { return FALSE; } CloseHandle(hFile); return TRUE; }