DirectShow 보유 DVD 리젼 변경의 지원 (Windows) 애플리케이션에의 리젼 변경 지원의 추가   [목차열람] [주소복사] [슬롯비우기]
애플리케이션에의 리전 변경 지원의 추가
 
Microsoft DirectX 9.0

애플리케이션에의 리전 변경 지원의 추가

이하의 함수는, 디코더 또는 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;
} 
↑TOP