home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / DVD / DVDSample / dvdsample.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  30.7 KB  |  941 lines

  1. //------------------------------------------------------------------------------
  2. // File: DvdSample.cpp
  3. //
  4. // Desc: DVD Playback sample app using IDvdGraphBuilder,
  5. //       IDvdInfo2, and IDvdControl2 interfaces.
  6. //
  7. //       This contains all Windows-related "plumbing" for the application
  8. //
  9. // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
  10. //------------------------------------------------------------------------------
  11.  
  12. #include <windows.h>
  13. #include <commdlg.h>
  14. #include <commctrl.h>
  15.  
  16. #include <dshow.h>
  17. #include "resource.h"
  18.  
  19. #include "DvdCore.h"
  20. #include "Dialogs.h"
  21. #include "DvdSample.h"
  22.  
  23.  
  24.  
  25.  
  26. //------------------------------------------------------------------------------
  27. // Global data
  28. //------------------------------------------------------------------------------
  29.  
  30. const PTSTR APPNAME = TEXT("DVDSample");
  31. CApp g_App;
  32.  
  33.  
  34.  
  35.  
  36. //------------------------------------------------------------------------------
  37. // Type Definitions
  38. //------------------------------------------------------------------------------
  39.  
  40. typedef UINT (CALLBACK* PFNDLL_STES)(UINT);
  41.  
  42.  
  43.  
  44.  
  45. //------------------------------------------------------------------------------
  46. // Name: WinMain()
  47. // Desc: This method is the standard Windows program entry point.
  48. //------------------------------------------------------------------------------
  49.  
  50. int APIENTRY WinMain(HINSTANCE hInstance,
  51.                      HINSTANCE hPrevInstance,
  52.                      PSTR      pCmdLine,
  53.                      int       nCmdShow)
  54. {    
  55.     DbgInitialise(hInstance);
  56.     g_App.SetAppValues(hInstance, APPNAME, IDS_APP_TITLE) ;
  57.     
  58.     // Perform application initialization:
  59.     if (! g_App.InitInstance(nCmdShow) ) 
  60.     {
  61.         DbgTerminate();
  62.         return (FALSE) ;
  63.     }
  64.     
  65.     HACCEL hAccelTable ;
  66.     hAccelTable = LoadAccelerators(hInstance, g_App.GetAppName()) ;
  67.     
  68.     // Main message loop:
  69.     MSG msg ;
  70.     while (GetMessage(&msg, NULL, 0, 0))
  71.     {
  72.         if (! TranslateAccelerator(msg.hwnd, hAccelTable, &msg) )
  73.         {
  74.             TranslateMessage(&msg) ;
  75.             DispatchMessage(&msg) ;
  76.         }
  77.     }
  78.     
  79.     DbgTerminate();
  80.     return (msg.wParam) ;
  81. }
  82.  
  83.  
  84. //------------------------------------------------------------------------------
  85. // Name: CApp::CApp()
  86. // Desc: This is the constructor for CApp.  It sets default values and disables 
  87. //       power saving.
  88. //------------------------------------------------------------------------------
  89.  
  90. CApp::CApp() : m_hInstance(NULL), 
  91.                m_hWnd(NULL), 
  92.                m_bCaptionsOn(false), 
  93.                m_pDvdCore(NULL),
  94.                m_bFullScreenOn(false),
  95.                m_pParentLevels(NULL),
  96.                m_pLangLookup(NULL),
  97.                m_hwndToolBar(0),
  98.                m_dwProhibitedTime(0)
  99. {
  100.     DbgLog((LOG_TRACE, 5, TEXT("CApp::CApp()"))) ;
  101.     ZeroMemory(m_szAppTitle, sizeof(m_szAppTitle)) ;
  102.  
  103.     ZeroMemory(m_szAppName, sizeof(m_szAppName)) ;
  104.  
  105.     m_pParentLevels = new CParentLevels();
  106.     m_pLangLookup = new CDVDLanguages();
  107.  
  108.     // notify the power manager that the display is in use so it won't go to sleep
  109.     // SetThreadExecutionState() is a Win98/Win2k API.
  110.     // The following code lets it fail gracefully on Win95
  111.  
  112.     PFNDLL_STES pfn;
  113.     pfn = (PFNDLL_STES) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
  114.         "SetThreadExecutionState");
  115.     if (pfn)
  116.     {
  117.         pfn(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
  118.     }
  119. }
  120.  
  121.  
  122. //------------------------------------------------------------------------------
  123. // Name: CApp::~CApp()
  124. // Desc: This is the destructor for CApp.
  125. //------------------------------------------------------------------------------
  126.  
  127. CApp::~CApp()
  128. {
  129.     DbgLog((LOG_TRACE, 5, TEXT("CApp::~CApp()"))) ;
  130.  
  131.     delete m_pParentLevels;
  132.     delete m_pLangLookup;
  133.     if (m_pDvdCore)
  134.     {
  135.         delete m_pDvdCore;
  136.         m_pDvdCore = NULL;
  137.     }
  138.  
  139.     // notify the power manager that the display is no longer in use and it can go to sleep
  140.     // SetThreadExecutionState() is a Win98/Win2k API.
  141.     // The following code lets it fail gracefully on Win95
  142.  
  143.     PFNDLL_STES pfn;
  144.     pfn = (PFNDLL_STES) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
  145.         "SetThreadExecutionState");
  146.     if (pfn)
  147.     {
  148.         pfn(ES_CONTINUOUS);
  149.     }
  150. }
  151.  
  152.  
  153. //------------------------------------------------------------------------------
  154. // Name: CApp::SetAppValues()
  155. // Desc: This method sets the basic application values like szAppName and hInstance
  156. //------------------------------------------------------------------------------
  157.  
  158. void CApp::SetAppValues(HINSTANCE hInst, PTSTR szAppName, int iAppTitleResId)
  159. {
  160.     DbgLog((LOG_TRACE, 5, TEXT("CApp::SetAppValues()"))) ;
  161.     
  162.     // The Windows stuff
  163.     m_hInstance = hInst ;
  164.     lstrcpy(m_szAppName, APPNAME) ;
  165.     LoadString(m_hInstance, IDS_APP_TITLE, m_szAppTitle, 100) ;
  166. }
  167.  
  168.  
  169. //------------------------------------------------------------------------------
  170. // Name: CApp::InitInstance()
  171. // Desc: This method registers and creates our window and toolbar.
  172. //------------------------------------------------------------------------------
  173.  
  174. bool CApp::InitInstance(int nCmdShow)
  175. {
  176.     DbgLog((LOG_TRACE, 5, TEXT("CApp::InitInstance()"))) ;
  177.         
  178.     // Win32 will always set hPrevInstance to NULL, So lets check
  179.     // things a little closer. This is because we only want a single
  180.     // version of this app to run at a time
  181.     m_hWnd = FindWindow (m_szAppName, m_szAppTitle) ;
  182.     if (m_hWnd) 
  183.     {
  184.         // We found another instance of ourself. Lets use that one:
  185.         if (IsIconic(m_hWnd)) 
  186.         {
  187.             ShowWindow(m_hWnd, SW_RESTORE);
  188.         }
  189.         SetForegroundWindow(m_hWnd);
  190.         
  191.         // If this app actually had any methodality, we would
  192.         // also want to communicate any action that our 'twin'
  193.         // should now perform based on how the user tried to
  194.         // execute us.
  195.         return false;
  196.     }
  197.     
  198.     // Register the app main window class
  199.     WNDCLASSEX  wc ;
  200.     wc.cbSize        = sizeof(wc) ;
  201.     wc.style         = CS_HREDRAW | CS_VREDRAW ;
  202.     wc.lpfnWndProc   = (WNDPROC) WndProc ;
  203.     wc.cbClsExtra    = 0 ;
  204.     wc.cbWndExtra    = 0 ;
  205.     wc.hInstance     = m_hInstance ;
  206.     wc.hIcon         = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_APPICON));
  207.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW) ;
  208.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1) ;
  209.     wc.lpszMenuName  = TEXT("DvdSample_Menu");
  210.     wc.lpszClassName = m_szAppName ;
  211.     wc.hIconSm       = NULL ;
  212.  
  213.     if (0 == RegisterClassEx(&wc))
  214.     {
  215.         DbgLog((LOG_ERROR, 0, 
  216.             TEXT("ERROR: RegisterClassEx() for app class failed (Error %ld)"), 
  217.             GetLastError())) ;
  218.         return false ;
  219.     }
  220.  
  221.     // Determine where to put the Application Window
  222.     RECT rDesktop;
  223.     SystemParametersInfo(SPI_GETWORKAREA, NULL, &rDesktop, NULL);
  224.  
  225.     // Create an instance of the window we just registered
  226.     // locate it at the bottom of the screen (bottom of screen - height of player)
  227.     m_hWnd = CreateWindowEx(0, m_szAppName, m_szAppTitle, WS_OVERLAPPEDWINDOW, //& ~WS_THICKFRAME,
  228.         160, rDesktop.bottom - 150, 300, 150, NULL, NULL, m_hInstance, NULL);
  229.     if (!m_hWnd) 
  230.     {
  231.         DbgLog((LOG_ERROR, 0, 
  232.             TEXT("ERROR: CreateWindowEx() failed (Error %ld)"), 
  233.             GetLastError())) ;
  234.         return false ;
  235.     }
  236.  
  237.     // We now create the toolbar
  238.     INITCOMMONCONTROLSEX cc;
  239.     cc.dwSize = sizeof(INITCOMMONCONTROLSEX);
  240.     cc.dwICC = ICC_BAR_CLASSES; // register only the toolbar control
  241.     InitCommonControlsEx(&cc);
  242.     
  243.     TBBUTTON tbb[] = 
  244.     {
  245.         0, ID_PLAYBACK_PREVIOUSCHAPTER, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, 0,
  246.         1, ID_PLAYBACK_REWIND,          TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, 0,
  247.         2, ID_PLAYBACK_PAUSE,           TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, 0,
  248.         3, ID_PLAYBACK_PLAY,            TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, 0,
  249.         4, ID_PLAYBACK_STOP,            TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, 0,
  250.         5, ID_PLAYBACK_FASTFORWARD,     TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, 0,
  251.         6, ID_PLAYBACK_NEXTCHAPTER,     TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, 0,
  252.         9, 0,                           TBSTATE_ENABLED, TBSTYLE_SEP,    0, 0, 0, 0,     
  253.         7, ID_PLAYBACK_MENUROOT,        TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, 0,
  254.         8, ID_OPTIONS_FULLSCREEN,       TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, 0,
  255.         9, ID_PLAYBACK_STEPFORWARD,     TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, 0
  256.     };
  257.  
  258.     m_hwndToolBar = CreateToolbarEx(m_hWnd, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | CCS_TOP
  259.         | TBSTYLE_TOOLTIPS, 1, 10, m_hInstance, IDR_TOOLBAR1, tbb, 11, 0, 0, 0, 0,
  260.         sizeof(TBBUTTON));
  261.     if (!m_hwndToolBar) 
  262.     {
  263.         DbgLog((LOG_ERROR, 0, 
  264.             TEXT("ERROR: CreateToolbarEx() failed (Error %ld)"), 
  265.             GetLastError())) ;
  266.         return false ;
  267.     }
  268.  
  269.     // we now set up the dvd playback class
  270.     m_pDvdCore = new CDvdCore(m_hInstance, this);
  271.     if (!m_pDvdCore->Init())
  272.     {
  273.         DbgLog((LOG_ERROR, 0, TEXT("ERROR: CDvdCore::Init() failed"))) ;
  274.         return false;
  275.     }
  276.  
  277.     m_pDvdCore->SetVideoWindowTitle(TEXT("DvdSample Video Window"));
  278.  
  279.     // and finally, we make the window visible
  280.     ShowWindow(m_hWnd, nCmdShow);
  281.     UpdateWindow(m_hWnd) ;
  282.         
  283.     return true;
  284. }
  285.  
  286.  
  287. //------------------------------------------------------------------------------
  288. // Name: WndProc()
  289. // Desc: This method is our main window procedure.  It parses the messages
  290. //       and farms out the work to other procedures.
  291. //------------------------------------------------------------------------------
  292.  
  293. LRESULT CApp::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  294. {
  295.     static HDC  hDC ;
  296.     static PAINTSTRUCT ps ;
  297.     
  298.     switch (message) {
  299.         
  300.     case WM_INITMENUPOPUP:
  301. //        UpdateMenuState() ;
  302.         break ;
  303.         
  304.     case WM_PAINT:
  305.         hDC = BeginPaint(hWnd, &ps) ;
  306.         ASSERT(hDC) ;
  307.         g_App.DrawStatus(hDC);
  308.         EndPaint(hWnd, &ps) ;
  309.         break ;
  310.         
  311.     case WM_KEYUP:
  312.         g_App.KeyProc(wParam, lParam) ;
  313.         break ;
  314.         
  315.     case WM_COMMAND:
  316.         g_App.MenuProc(hWnd, wParam, lParam) ;
  317.         break;
  318.         
  319.     case WM_NOTIFY:
  320.         return g_App.ToolTipProc(hWnd, message, wParam, lParam);
  321.         break;
  322.  
  323.     case WM_DESTROY:
  324.         PostQuitMessage(0);
  325.         break;
  326.  
  327.     case WM_SIZE:
  328.         // we do this to cause the toolbar to resize correctly
  329.         SendMessage(g_App.m_hwndToolBar, WM_SIZE, wParam, lParam);
  330.         return DefWindowProc(hWnd, message, wParam, lParam);
  331.         break;
  332.         
  333.     default:
  334.         return (DefWindowProc(hWnd, message, wParam, lParam));
  335.     }
  336.     
  337.     return 0 ; // let Windows know we handled the message
  338.  
  339. }
  340.  
  341.  
  342. //------------------------------------------------------------------------------
  343. // Name: ToolTipProc()
  344. // Desc: This method is a MessageProc for our toolbar tooltips.
  345. //       This checks whether the WM_NOTIFY message is really a tooltip.
  346. //       If it is, we compare it to the buttons on the toolbar and send the right text back.
  347. //       Note that older code would use TTN_NEEDTEXT instead of TTN_GETDISPINFO.
  348. //------------------------------------------------------------------------------
  349.  
  350. LRESULT CApp::ToolTipProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  351. {
  352.     DbgLog((LOG_TRACE, 5, TEXT("CApp::ToolTipProc()"))) ;
  353.  
  354.     LPNMTTDISPINFO TText;
  355.     TText = (LPNMTTDISPINFO) lParam;
  356.     if (TTN_GETDISPINFO == TText->hdr.code)
  357.     {
  358.         switch (TText->hdr.idFrom)
  359.         {
  360.             case ID_PLAYBACK_PREVIOUSCHAPTER:
  361.                 TText->lpszText = TEXT("Previous Chapter");
  362.                 break;
  363.             case ID_PLAYBACK_REWIND:
  364.                 TText->lpszText = TEXT("Rewind");
  365.                 break;
  366.             case ID_PLAYBACK_PAUSE:
  367.                 TText->lpszText = TEXT("Pause");
  368.                 break;
  369.             case ID_PLAYBACK_PLAY:
  370.                 TText->lpszText = TEXT("Play");
  371.                 break;
  372.             case ID_PLAYBACK_STOP:
  373.                 TText->lpszText = TEXT("Stop");
  374.                 break;
  375.             case ID_PLAYBACK_FASTFORWARD:
  376.                 TText->lpszText = TEXT("FastForward");
  377.                 break;
  378.             case ID_PLAYBACK_NEXTCHAPTER:
  379.                 TText->lpszText = TEXT("Next Chapter");
  380.                 break;
  381.             case ID_PLAYBACK_MENUROOT:
  382.                 TText->lpszText = TEXT("Root Menu / Resume");
  383.                 break;
  384.             case ID_OPTIONS_FULLSCREEN:
  385.                 TText->lpszText = TEXT("Full Screen");
  386.                 break;
  387.             case ID_PLAYBACK_STEPFORWARD:
  388.                 TText->lpszText = TEXT("Step Forward");
  389.                 break;
  390.         }
  391.         return 0;
  392.     }
  393.     else
  394.         return DefWindowProc(hWnd, message, wParam, lParam); // it wasn't a tooltip message
  395. }
  396.  
  397.  
  398. //------------------------------------------------------------------------------
  399. // Name: CApp::MenuProc()
  400. // Desc: This method handles all of the menu messages for our application.  It is
  401. //       passed these messages by the main message proc.
  402. //------------------------------------------------------------------------------
  403.  
  404. LRESULT CApp::MenuProc(HWND hWnd, WPARAM wParam, LPARAM lParam)
  405. {
  406.     DbgLog((LOG_TRACE, 5, TEXT("CApp::MenuProc()"))) ;
  407.  
  408.     HMENU hMenu = GetMenu(hWnd) ;
  409.  
  410.     //Parse the menu selections:
  411.     switch (LOWORD(wParam)) 
  412.     {
  413.     case ID_PLAYBACK_PLAY:
  414.         m_pDvdCore->Play();
  415.         break;
  416.  
  417.     case ID_PLAYBACK_PREVIOUSCHAPTER:
  418.         m_pDvdCore->PrevChapter();
  419.         break;
  420.  
  421.     case ID_PLAYBACK_REWIND:
  422.         m_pDvdCore->Rewind();
  423.         break;
  424.  
  425.     case ID_PLAYBACK_PAUSE:
  426.         m_pDvdCore->Pause();
  427.         break;
  428.  
  429.     case ID_PLAYBACK_STOP:
  430.         m_pDvdCore->Stop();
  431.         break;
  432.  
  433.     case ID_PLAYBACK_FASTFORWARD:
  434.         m_pDvdCore->FastForward();
  435.         break;
  436.  
  437.     case ID_PLAYBACK_NEXTCHAPTER:
  438.         m_pDvdCore->NextChapter();
  439.         break;
  440.  
  441.     case ID_PLAYBACK_MENUROOT:
  442.         m_pDvdCore->RootMenu();
  443.         break;
  444.  
  445.     case ID_OPTIONS_FULLSCREEN:
  446.         {
  447.             m_pDvdCore->ToggleFullScreen();
  448.         }
  449.        break;
  450.  
  451.     case ID_PLAYBACK_TITLEMENU:
  452.         m_pDvdCore->TitleMenu();
  453.         break;
  454.  
  455.     case ID_FILE_EXIT:
  456.         DestroyWindow(m_hWnd);
  457.         break;
  458.  
  459.     case ID_OPTIONS_CLOSEDCAPTION:
  460.         if (false == m_bCaptionsOn) // turn them on
  461.         {
  462.             HMENU hSubMenu = GetSubMenu(hMenu, 2); // Options is the 3rd menu starting with 0
  463.             CheckMenuItem(hSubMenu, ID_OPTIONS_CLOSEDCAPTION, MF_BYCOMMAND | MF_CHECKED);
  464.             if (m_pDvdCore->EnableCaptions(true))
  465.                 m_bCaptionsOn = true;
  466.         }
  467.         else // turn them off
  468.         {
  469.             HMENU hSubMenu = GetSubMenu(hMenu, 2); // Options is the 3rd menu starting with 0
  470.             CheckMenuItem(hSubMenu, ID_OPTIONS_CLOSEDCAPTION, MF_BYCOMMAND | MF_UNCHECKED);
  471.             if (m_pDvdCore->EnableCaptions(false))
  472.                 m_bCaptionsOn = false;
  473.         }
  474.        break;
  475.  
  476.     case ID_OPTIONS_SAVEBOOKMARK:
  477.         m_pDvdCore->SaveBookmark();
  478.         break;
  479.  
  480.     case ID_OPTIONS_RESTOREBOOKMARK:
  481.         m_pDvdCore->RestoreBookmark();
  482.         break;
  483.  
  484.     case ID_OPTIONS_PARENTALLEVEL:
  485.         if (Nav_Stopped != m_pDvdCore->GetState() && Graph_Stopped2 != m_pDvdCore->GetState())
  486.             // can't change parental level except in stop state
  487.         {
  488.             MessageBox(m_hWnd, 
  489.                 TEXT("Can't change parental control level during playback. Please stop (twice) first."), 
  490.                 TEXT("Error"), MB_OK | MB_ICONINFORMATION) ;
  491.             break ;
  492.         }
  493.         DialogBox(m_hInstance, MAKEINTRESOURCE(IDD_PARENTLEVELS), m_hWnd,
  494.             reinterpret_cast<DLGPROC>(SelectParentalLevel));
  495.  
  496.         break;
  497.  
  498.     case ID_HELP_ABOUTDVDSAMPLE:
  499.         {
  500.             CAboutDlg aDlg(m_hInstance, m_hWnd);
  501.             aDlg.DoModal();
  502.         }
  503.         break;
  504.  
  505.     case ID_OPTIONS_SUBPICTURE:
  506.         {
  507.             CSPLangDlg aDlg(m_hInstance, m_hWnd);
  508.             aDlg.DoModal();
  509.         }
  510.         break;
  511.  
  512.     case ID_OPTIONS_AUDIOLANGUAGE:
  513.         {
  514.             CAudioLangDlg aDlg(m_hInstance, m_hWnd);
  515.             aDlg.DoModal();
  516.         }
  517.         break;
  518.  
  519.     case ID_OPTIONS_ANGLE:
  520.         {
  521.             CAngleDlg aDlg(m_hInstance, m_hWnd);
  522.             aDlg.DoModal();
  523.         }
  524.         break;
  525.  
  526.     case ID_FILE_SELECTDISC:
  527.         OnSelectDisc();
  528.         break;
  529.  
  530.     case ID_PLAYBACK_STEPFORWARD:
  531.         m_pDvdCore->FrameStep();
  532.         break;
  533.  
  534.     case ID_PLAYBACK_GOTO_CHAPTER:
  535.         {
  536.             CChapterDlg aDlg(m_hInstance, m_hWnd);
  537.             if (false == aDlg.DoModal())
  538.                 break;
  539.             m_pDvdCore->PlayChapter(aDlg.GetChapter());
  540.         }
  541.         break;
  542.         
  543.     case ID_PLAYBACK_GOTO_TITLE:
  544.         {
  545.             CTitleDlg aDlg(m_hInstance, m_hWnd);
  546.             if (false == aDlg.DoModal())
  547.                 break;
  548.             m_pDvdCore->PlayChapterInTitle(aDlg.GetTitle(), aDlg.GetChapter());
  549.         }
  550.         break;
  551.  
  552.     case ID_PLAYBACK_GOTO_TIME:
  553.         {
  554.             CTimeDlg aDlg(m_hInstance, m_hWnd);
  555.  
  556.             DVD_HMSF_TIMECODE time = m_pDvdCore->GetTime();
  557.             aDlg.SetTime(time);
  558.  
  559.             if (false == aDlg.DoModal())
  560.                 break;
  561.             m_pDvdCore->PlayTime(aDlg.GetTime());
  562.         }
  563.         break;
  564.  
  565.     case ID_OPTIONS_GETDISCTEXT:
  566.         m_pDvdCore->GetDvdText();
  567.         break;
  568.  
  569.     case ID_OPTIONS_GETAUDIOATTRIBUTES:
  570.         m_pDvdCore->GetAudioAttributes();
  571.         break;
  572.  
  573.     case ID_OPTIONS_GETVIDEOATTRIBUTES:
  574.         m_pDvdCore->GetVideoAttributes();
  575.         break;
  576.  
  577.     case ID_OPTIONS_GETSUBPICTUREATTRIBUTES:
  578.         m_pDvdCore->GetSPAttributes();
  579.         break;
  580.  
  581.     case ID_OPTIONS_SETKARAOKEMIXING:
  582.         {
  583.             CKaraokeDlg aDlg(m_hInstance, m_hWnd);
  584.             aDlg.DoModal(); // all work happens in the dialog code
  585.         }
  586.         break;
  587.  
  588.     default:
  589.         break;
  590.     }
  591.  
  592.     return 0;
  593. }
  594.  
  595.  
  596. //------------------------------------------------------------------------------
  597. // Name: CApp::KeyProc()
  598. // Desc: This method will process all key presses sent to our application window.
  599. //       At present it passes all of the keys along to the DvdCore but this is where
  600. //       you would implement shortcut keys, etc.
  601. //------------------------------------------------------------------------------
  602.  
  603. LRESULT CApp::KeyProc(WPARAM wParam, LPARAM lParam)
  604. {
  605.     DbgLog((LOG_TRACE, 5, TEXT("CApp::KeyProc()"))) ;
  606.  
  607.     switch (wParam)
  608.     {
  609.     case VK_ESCAPE: // exit full screen
  610.     case VK_RETURN: // activate the currently selected button
  611.     case VK_LEFT: // select the left button
  612.     case VK_RIGHT: // select the right button
  613.     case VK_UP: // select the upper button
  614.     case VK_DOWN: // select the lower button
  615.         return m_pDvdCore->OnKeyEvent(wParam, lParam); // pass these keys on to the Core.
  616.     }
  617.     return DefWindowProc(m_hWnd, WM_KEYUP, wParam, lParam);
  618. }
  619.  
  620.  
  621. //------------------------------------------------------------------------------
  622. // Name: CApp::SelectParentalLevel()
  623. // Desc: This method is the MessageProc for the Parental Level Dialog.  It is used
  624. //       to allow the user to select the parental level setting.
  625. //
  626. //       The Dialog wrapper class is not used to demonstrate an alternate way to 
  627. //       handle dialogs.
  628. //------------------------------------------------------------------------------
  629.  
  630. BOOL CALLBACK CApp::SelectParentalLevel(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  631. {
  632.     DbgLog((LOG_TRACE, 5, TEXT("CApp::SelectParentalLevel()"))) ;
  633.  
  634.     switch (message) 
  635.     {
  636.     case WM_INITDIALOG:
  637.         g_App.MakeParentLevelList(hDlg, IDC_LEVEL_LIST) ;
  638.         return TRUE;
  639.         
  640.     case WM_COMMAND:
  641.         switch (LOWORD(wParam))
  642.         {
  643.         case IDOK:
  644.             {
  645.                 LONG  lLevel ;
  646.                 lLevel = SendDlgItemMessage(hDlg, IDC_LEVEL_LIST, LB_GETCURSEL, 
  647.                     static_cast<WPARAM>(0), static_cast<LPARAM>(0) );
  648.                 if (CB_ERR == lLevel)
  649.                     DbgLog((LOG_ERROR, 1, TEXT("WARNING: Couldn't get selected parental control level (Error %d)"), lLevel)) ;
  650.                 else
  651.                     g_App.m_pDvdCore->SetParentalLevel(g_App.m_pParentLevels->GetValue(lLevel)) ;
  652.             }
  653.             
  654.             // Now fall through to just end the dialog
  655.             
  656.         case IDCANCEL:
  657.             EndDialog(hDlg, TRUE);
  658.             return TRUE;
  659.         }
  660.         break;
  661.         
  662.         default:
  663.             break ;
  664.     }
  665.     
  666.     return FALSE;
  667. }
  668.  
  669.  
  670.  
  671. //------------------------------------------------------------------------------
  672. // Name: CApp::UpdateStatus()
  673. // Desc: This method is notified every time that status of the player changes
  674. //       (Time, title, Chapter, etc.).  This invalidates the client rectangle to force
  675. //       a redraw of the screen.
  676. //------------------------------------------------------------------------------
  677.  
  678. void CApp::UpdateStatus(void)
  679. {
  680.     DbgLog((LOG_TRACE, 5, TEXT("CApp::UpdateStatus()"))) ;
  681.  
  682.     RECT Rect;
  683.     if (FALSE != GetClientRect(m_hWnd, &Rect))
  684.     {
  685.         Rect.top += 30; // so we don't redraw the toolbar - 30 is just a rough number
  686.         InvalidateRect(m_hWnd, &Rect, TRUE);
  687.     }
  688.     else
  689.     {
  690.         DWORD res = GetLastError();
  691.         DbgLog((LOG_ERROR, 1, TEXT("GetClientRect failed: %#x"), res)) ;
  692.     }
  693. }
  694.  
  695.  
  696. //------------------------------------------------------------------------------
  697. // Name: CApp::DrawStatus()
  698. // Desc: This method draws our status test (time, title, chapter) on the screen
  699. //------------------------------------------------------------------------------
  700.  
  701. void CApp::DrawStatus(HDC hDC)
  702. {
  703.     DbgLog((LOG_TRACE, 5, TEXT("CApp::DrawStatus()"))) ;
  704.  
  705.     TCHAR location[25];
  706.     wsprintf(location, TEXT("Title: %-6uChapter: %u"), m_pDvdCore->GetTitle(), 
  707.         m_pDvdCore->GetChapter());
  708.     TextOut(hDC, 10, 50, location, lstrlen(location));
  709.  
  710.     TCHAR time[15];
  711.     wsprintf(time, TEXT("Time: %02d:%02d:%02d"), m_pDvdCore->GetTime().bHours, 
  712.         m_pDvdCore->GetTime().bMinutes, m_pDvdCore->GetTime().bSeconds);
  713.     TextOut(hDC, 10, 65, time, lstrlen(time));
  714.  
  715.     if (timeGetTime() <= (m_dwProhibitedTime + 5000)) // if less than 5 seconds has passed
  716.     {
  717.         SetTextColor(hDC, RGB(255, 0, 0));
  718.         TextOut(hDC, 180, 80, TEXT("Prohibited!"), 11);
  719.     }
  720. }
  721.  
  722.  
  723.  
  724. //------------------------------------------------------------------------------
  725. // Name: CApp::OnSelectDisc()
  726. // Desc: This method brings up a common file dialog to ask the user to find the
  727. //       dvd disc they wish to watch.  We look for the video_ts.ifo file.
  728. //------------------------------------------------------------------------------
  729.  
  730. bool CApp::OnSelectDisc()
  731. {
  732.     DbgLog((LOG_TRACE, 5, TEXT("CApp::OnSelectDisc()"))) ;
  733.  
  734.     OPENFILENAME  ofn ; // structure used by the common file dialog
  735.     TCHAR         szFileName[MAX_PATH] ;
  736.     
  737.     // Init the filename buffer with *.ifo
  738.     lstrcpy(szFileName, TEXT("*.ifo")) ;
  739.     
  740.     ZeroMemory(&ofn, sizeof(OPENFILENAME)) ;
  741.     ofn.lStructSize = sizeof(OPENFILENAME) ;
  742.     ofn.hwndOwner = m_hWnd ;
  743.     ofn.lpstrFilter = TEXT("IFO Files\0*.ifo\0All Files\0*.*\0") ;
  744.     ofn.nFilterIndex = 1 ;
  745.     ofn.lpstrFile = szFileName ;
  746.     ofn.nMaxFile = sizeof(szFileName) ;
  747.     ofn.lpstrFileTitle = NULL ;
  748.     ofn.lpstrTitle = TEXT("Select DVD-Video Volume") ;
  749.     ofn.nMaxFileTitle = 0 ;
  750.     ofn.lpstrInitialDir = NULL ;
  751.     ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY ;
  752.     
  753.     // GetOpenFileName will bring up the common file dialog in open mode
  754.     if (GetOpenFileName(&ofn)) // user specified a file
  755.     {      
  756.         return m_pDvdCore->SetDirectory(szFileName);
  757.     }
  758.     
  759.     // Either failed or user hit Esc.
  760.     DWORD dw = CommDlgExtendedError() ;
  761.     DbgLog((LOG_TRACE, 3, TEXT("GetOpenFileName() cancelled/failed with error %lu"), dw)) ;
  762.  
  763.     return false ; // DVD-Video volume not changed
  764. }
  765.  
  766.  
  767. //------------------------------------------------------------------------------
  768. // Name: CApp::Prohibited()
  769. // Desc: This method is called by the DVDCore whenever an operation is attempted that
  770. //       is prohibited by UOP.  We set a time value and then invalidate the rectangle.
  771. //------------------------------------------------------------------------------
  772.  
  773. void CApp::Prohibited()
  774. {
  775.     DbgLog((LOG_TRACE, 5, TEXT("CApp::Prohibited()"))) ;
  776.  
  777.     m_dwProhibitedTime = timeGetTime();
  778.  
  779.     RECT Rect;
  780.     if (FALSE != GetClientRect(m_hWnd, &Rect))
  781.     {
  782.         Rect.top += 30; // so we don't redraw the toolbar - 30 is just a rough number
  783.         InvalidateRect(m_hWnd, &Rect, TRUE);
  784.     }
  785.     else
  786.     {
  787.         DWORD res = GetLastError();
  788.         DbgLog((LOG_ERROR, 1, TEXT("GetClientRect failed: %#x"), res)) ;
  789.     }
  790. }
  791.  
  792.  
  793. //------------------------------------------------------------------------------
  794. // Name: CApp::Exit()
  795. // Desc: This method is part of IDvdCallBack.  It is called by the DVDCore whenever 
  796. //       the playback window si closed.  We then close down the application. 
  797. //------------------------------------------------------------------------------
  798.  
  799. void CApp::Exit()
  800. {
  801.     DbgLog((LOG_TRACE, 5, TEXT("CApp::Exit()"))) ;
  802.     PostQuitMessage(0);
  803. }
  804.  
  805.  
  806. //------------------------------------------------------------------------------
  807. // Name: CApp::GetAppWindow()
  808. // Desc: This method is a member of IDVDCallback.  It returns the location and size
  809. //       of the player window to the application.
  810. //------------------------------------------------------------------------------
  811.  
  812. RECT CApp::GetAppWindow()
  813. {
  814.     RECT rWindow;
  815.     GetWindowRect(m_hWnd, &rWindow);
  816.     return rWindow;
  817. }
  818.  
  819.  
  820. //------------------------------------------------------------------------------
  821. // Name: CApp::MakeParentLevelList()
  822. // Desc: This method creates a list of parental levels and adds them to the
  823. //       parental level dialog box's listbox.
  824. //------------------------------------------------------------------------------
  825.  
  826. int CApp::MakeParentLevelList(HWND hDlg, int iListID)
  827. {
  828.     DbgLog((LOG_TRACE, 5, TEXT("CApp::MakeParentalLevelList(0x%lx, %d)"),
  829.         hDlg, iListID)) ;
  830.     
  831.     int      iLevels = m_pParentLevels->GetCount() ;
  832.     int      iResult ;
  833.     
  834.     // add all defined parental levels
  835.     for (int i = 0 ; i < iLevels ; i++)
  836.     {
  837.         // Add to the listbox now
  838.         iResult = SendDlgItemMessage(hDlg, iListID, LB_ADDSTRING, (WPARAM) 0, 
  839.             (LPARAM)(LPVOID) m_pParentLevels->GetName(i)) ;
  840.         if (LB_ERR == iResult || LB_ERRSPACE == iResult)
  841.         {
  842.             DbgLog((LOG_ERROR, 1, 
  843.                 TEXT("Error (%d) adding parental level '%s'(%d) to list"), 
  844.                 iResult, m_pParentLevels->GetName(i), i)) ;
  845.         }
  846.     }
  847.     
  848.     if (iLevels > 0)
  849.     {
  850.         iResult = SendDlgItemMessage(hDlg, iListID, LB_SETCURSEL, 
  851.             (WPARAM) m_pDvdCore->GetParentalLevel(), (LPARAM) 0) ;
  852.         if (LB_ERR == iResult)
  853.         {
  854.             DbgLog((LOG_ERROR, 1, 
  855.                 TEXT("WARNING: Couldn't set %ld as selected parent level (Error %d)"),
  856.                 m_ulParentCtrlLevel, iResult)) ;
  857.         }
  858.     }
  859.     return iLevels ;
  860. }
  861.  
  862.  
  863. //------------------------------------------------------------------------------
  864. // Name: CDVDLanguages::CDVDLanguages()
  865. // Desc: This is the constructor.  It sets up our lookup table
  866. //       Only 10 languages have been used here as a sample.
  867. //       The list can be extended to include any language listed in ISO 639.
  868. //------------------------------------------------------------------------------
  869. CDVDLanguages::CDVDLanguages()
  870. {
  871.     DbgLog((LOG_TRACE, 5, TEXT("CDVDLanguages::CDVDLanguages()"))) ;
  872.  
  873.     m_lcidCodes[0] = 0x0407 ;    m_apszLangNames[0] = TEXT("German") ;
  874.     m_lcidCodes[1] = 0x0409 ;    m_apszLangNames[1] = TEXT("English") ;
  875.     m_lcidCodes[2] = 0x040a ;    m_apszLangNames[2] = TEXT("Spanish") ;
  876.     m_lcidCodes[3] = 0x040c ;    m_apszLangNames[3] = TEXT("French") ;
  877.     m_lcidCodes[4] = 0x0411 ;    m_apszLangNames[4] = TEXT("Japanese") ;
  878.     m_lcidCodes[5] = 0x0412 ;    m_apszLangNames[5] = TEXT("Korean") ;
  879.     m_lcidCodes[6] = 0x0413 ;    m_apszLangNames[6] = TEXT("Dutch") ;
  880.     m_lcidCodes[7] = 0x0816 ;    m_apszLangNames[7] = TEXT("Portuguese") ;
  881.     m_lcidCodes[8] = 0x041d ;    m_apszLangNames[8] = TEXT("Swedish") ;
  882.     m_lcidCodes[9] = 0x0804 ;    m_apszLangNames[9] = TEXT("Chinese") ;
  883. }
  884.  
  885.  
  886. //------------------------------------------------------------------------------
  887. // Name: CDVDLanguages::GetLangString()
  888. // Desc: This method is our lookup function.  It takes an LCID language code
  889. //       and returns an English string language name.
  890. //------------------------------------------------------------------------------
  891.  
  892. bool CDVDLanguages::GetLangString(LCID LangCode, PTSTR pszLang, int iMaxLen)
  893. {
  894.     DbgLog((LOG_TRACE, 5, TEXT("CDVDLanguages::GetLangString()"))) ;
  895.  
  896.     for (int i = 0 ; i < 10 ; i++)
  897.     {
  898.         if (LangCode == m_lcidCodes[i])  // match!!
  899.         {
  900.             if (iMaxLen < lstrlen(m_apszLangNames[i]))
  901.             {
  902.                 lstrcpy(pszLang, m_apszLangNames[i]) ;
  903.                 return true ;  // got a match
  904.             }
  905.             // let it fall through if that fails
  906.         }
  907.     }
  908.     if (iMaxLen < lstrlen(TEXT("Unknown")))
  909.     {
  910.         lstrcpy(pszLang, TEXT("Unknown")) ;
  911.     }
  912.     return false ;  // didn't get a match
  913. }
  914.  
  915.  
  916. //------------------------------------------------------------------------------
  917. // Name: CParentLevels::CParentLevels()
  918. // Desc: This is the constructor for CParentLevels.  It can be modified to change
  919. //       the parental levels shown to the user.
  920. //       Remember that the mapping of parental levels to MPAA ratings shown here
  921. //       is only valid for the U.S. and Canada.  In other countries, the parental
  922. //       levels will have different specific meanings, although parental level 1
  923. //       is always the least restrictive level and level 8 is the most restrictive.
  924. //------------------------------------------------------------------------------
  925.  
  926. CParentLevels::CParentLevels()
  927. {
  928.     DbgLog((LOG_TRACE, 5, TEXT("CParentLevels::CParentLevels()"))) ;
  929.  
  930.     m_iCount = LEVELS ;
  931.     m_alpszNames[0] = TEXT(" G ") ;         m_aiValues[0] = 1 ;
  932.     m_alpszNames[1] = TEXT(" PG ") ;        m_aiValues[1] = 3 ;
  933.     m_alpszNames[2] = TEXT(" PG-13 ") ;     m_aiValues[2] = 4 ;
  934.     m_alpszNames[3] = TEXT(" R ") ;         m_aiValues[3] = 6 ;
  935.     m_alpszNames[4] = TEXT(" NC-17 ") ;     m_aiValues[4] = 7 ;
  936.     m_alpszNames[5] = TEXT(" Not Rated ") ; m_aiValues[5] = 8 ;
  937. }
  938.  
  939.  
  940.  
  941.