애플리케이션에의 리전 변경 지원의 추가
애플리케이션에의 리전 변경 지원의 추가
이하의 함수는, 디코더 또는 DVD 애플리케이션으로 리전 변경 지원을 통합하고 싶은 개발자에게 제공된다.
// 선언, 정수, typedef 를 전송 한다.
const short MAX_DRIVE_NAME = 4;
struct DriveName
{
TCHAR name[MAX_DRIVE_NAME];
};
BOOL DoesFileExist(LPTSTR pszFile);
BOOL GetDriveLetter(IDvdInfo2 *pDvd, DriveName& szDrive);
/////////////////////////////////////////////////////////////////////
// ChangeDVDRegion : DVD 드라이브의 리전을 변경하기 위한 함수.
// 파라미터 :
// hWnd - 애플리케이션 윈도우의 핸들.
// 변경에 성공했을 경우는 TRUE 를 돌려주어, 그 이외의 경우는 FALSE 를 돌려준다.
// 실패는, 보통, 유효한 DVD-V 디스크가 삽입된 드라이브가 없었던 것을 의미한다.
/////////////////////////////////////////////////////////////////////
BOOL ChangeDVDRegion(HWND hWnd, IDvdInfo2 *pDvd)
{
typedef BOOL (APIENTRY *DVDPPLAUNCHER) (HWND hWnd, CHAR DriveLetter);
// 최초로, 유효한 DVD-V 디스크가 삽입된 DVD 드라이브인 드라이브를 검색한다.
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;
}
// 실행하고 있는 OS 를 검출한다.
OSVERSIONINFO ver;
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&ver);
if (VER_PLATFORM_WIN32_NT == ver.dwPlatformId)
{
// Windows NT 의 경우는, storprop.dll 를 사용한다.
HINSTANCE hInstDLL;
DVDPPLAUNCHER dvdPPLauncher;
CHAR szDVDDriveA[MAX_DRIVE_NAME];
const TCHAR szDllName[] = TEXT("\\storprop.dll");
// 패스와 이름을 보관 유지하기 위해서 충분한 길이의 캐릭터 라인을 할당한다.
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
{
// Windows 9x 의 경우는, DVDRgn.exe 애플리케이션을 사용한다.
const TCHAR szUtilName[] = TEXT("\\DVDRgn.exe ");
// 1 문자의 커멘드 라인 인수를 포함한, 충분한 길이의 캐릭터 라인을 할당한다.
TCHAR szCmdLine[MAX_PATH + (sizeof(szUtilName) /sizeof(TCHAR)) + 2];
// 커멘드 라인의 캐릭터 라인으로서 \windows\dvdrgn.exe 의 패스를 얻어온다.
UINT cb = GetWindowsDirectory(szCmdLine, MAX_PATH + 1);
if (cb == 0 || cb > MAX_PATH + 1)
{
return FALSE;
}
lstrcat(szCmdLine, szUtilName);
// 커멘드 라인 인수로서 드라이브 문자만을 추가한다
_tcsnccat(szCmdLine, szDVDDrive.name, 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(0, 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)
{
return TRUE;
}
}
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////
// GetDriveLetter : 액티브한 DVD 드라이브의 드라이브 문자를 돌려준다.
// 파라미터 :
// pDvdC - DVD 네비게이터 필터의 IDvdControl2 인터페이스.
// pszDrive - 유효한 DVD-V 디스크가 삽입된 최초의 DVD 드라이브를 받는다.
// 유효한 디스크가 삽입된 DVD 드라이브가 있는 경우는 TRUE 를 돌려준다.
/////////////////////////////////////////////////////////////////////
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;
// 현재의 루트 디렉토리를 얻어온다
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)) // DVD 드라이브일 가능성이 있다
return TRUE;
}
// 유효한 드라이브를 모두 루프 처리해, 유효한 DVD-V 디스크가 삽입되었다
// DVD 드라이브를 검출한다.
// 유효한 드라이브를 모두 얻어온다
DWORD dwLen = GetLogicalDriveStrings(MAX_PATH, szPath);
if (dwLen > MAX_PATH)
{
// 이 함수는, 버퍼가 너무 작은 경우는 보다 큰 값을 돌려준다.
return FALSE;
}
// 모든 드라이브를 1 개씩 시행한다
for (DWORD dw = 0; dw < dwLen; )
{
TCHAR *szTmp = szPath + dw;
// 필요한 . ifo 파일이 들어간 디스크가 삽입된 CD-ROM 드라이브만을 검색한다
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"));
// 이 드라이브에 . ifo 파일이 존재하는 경우, 이 드라이브에는 유효한 DVD-V 디스크가 삽입되고 있다
if (DoesFileExist(szDVDPath1) && DoesFileExist(szDVDPath2))
{
lstrcpyn(pszDrive.name, szTmp, MAX_DRIVE_NAME);
return TRUE; // 유효한 DVD-V 디스크가 삽입된 최초의 드라이브를 돌려준다
}
}
dw += lstrlen(szTmp) + 1;
}
return FALSE ; // DVD-V 컨텐츠를 포함한 DVD 드라이브가 발견되지 않았다
}
/////////////////////////////////////////////////////////////////////
// DoesFileExist : 지정한 파일이 존재할지 어떨지를 조사한다
// 파라미터 :
// pszFile - 체크하는 파일명.
// 지정한 파일이 발견되었을 경우는 TRUE 를 돌려주어, 그 이외의 경우는 FALSE 를 돌려준다.
/////////////////////////////////////////////////////////////////////
BOOL DoesFileExist(LPTSTR pszFile)
{
if (pszFile == NULL)
{
return FALSE;
}
if (lstrlen(pszFile) > MAX_PATH)
{
return FALSE;
}
// 요구된 파일을 열어 읽어낼 수가 있을지 어떨지를 테스트할 경우에
// 에러 메시지가 pop-up 표시되지 않게 한다.
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); // 에러 모드를 바탕으로 되돌린다
if (INVALID_HANDLE_VALUE == hFile)
{
return FALSE;
}
CloseHandle(hFile);
return TRUE;
}