Microsoft DirectX 9.0 |
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);
/////////////////////////////////////////////////////////////////////
// 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
strncpy(szDVDDriveA, szDVDDrive.name, MAX_DRIVE_NAME);
#endif
UINT cb = GetSystemDirectory(szCmdLine, MAX_PATH + 1);
if (cb == 0 || cb > MAX_PATH + 1)
{
return FALSE;
}
lstrcat(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;
}
lstrcat(szCmdLine, szUtilName);
// Add only the drive letter as command line parameter
_tcsnccat(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
lstrcpyn(pszDrive.name, szPathW, MAX_DRIVE_NAME);
#else
WideCharToMultiByte(CP_ACP, 0, szPathW, ulActualSize, szPath, MAX_PATH, 0, 0);
lstrcpyn(pszDrive.name, szPath, MAX_DRIVE_NAME);
#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 (DWORD 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];
lstrcpyn(szDVDPath1, szTmp, MAX_DRIVE_NAME);
lstrcpyn(szDVDPath2, szTmp, MAX_DRIVE_NAME);
lstrcat(szDVDPath1, TEXT("Video_ts\\Video_ts.ifo"));
lstrcat(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))
{
lstrcpyn(pszDrive.name, szTmp, MAX_DRIVE_NAME);
return TRUE; // return the first drive that has a valid DVD-V disc
}
}
dw += lstrlen(szTmp) + 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;
}
if (lstrlen(pszFile) > 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.
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;
}