Adding Region-Change Support to an Application
[The feature associated with this page, DirectShow, is a legacy feature. It has been superseded by MediaPlayer, IMFMediaEngine, and Audio/Video Capture in Media Foundation. Those features have been optimized for Windows 10 and Windows 11. Microsoft strongly recommends that new code use MediaPlayer, IMFMediaEngine and Audio/Video Capture in Media Foundation instead of DirectShow, when possible. Microsoft suggests that existing code that uses the legacy APIs be rewritten to use the new APIs if possible.]
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 the version.
OSVERSIONINFO ver;
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&ver);
if (VER_PLATFORM_WIN32_NT == ver.dwPlatformId)
{
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
{
return FALSE;
}
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;
}
Related topics