PageThird.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /******************************************************************************
  2. |* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  3. |* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  4. |* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  5. |* PARTICULAR PURPOSE.
  6. |*
  7. |* Copyright 1995-2005 Nero AG. All Rights Reserved.
  8. |*-----------------------------------------------------------------------------
  9. |* NeroSDK / NVAPIExample
  10. |*
  11. |* PROGRAM: PageThird.cpp
  12. |*
  13. |* PURPOSE: Implementation of the third page.
  14. ******************************************************************************/
  15. #include "stdafx.h"
  16. #include "NVAPIExample.h"
  17. #include "NVAPIExampleDlg.h"
  18. #include "PageThird.h"
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. #define UM_START_PROCESS (WM_APP + 1)
  25. #define TIMER_INTERVAL 500 /* ms */
  26. #define TIMER_ID 100
  27. CPageThird::CPageThird(CSheet * pParent)
  28. : CPage(CPageThird::IDD, pParent)
  29. , m_bActiveState (false)
  30. , m_bAbort (false)
  31. {
  32. //{{AFX_DATA_INIT(CPageThird)
  33. //}}AFX_DATA_INIT
  34. }
  35. void CPageThird::DoDataExchange(CDataExchange* pDX)
  36. {
  37. CPage::DoDataExchange(pDX);
  38. //{{AFX_DATA_MAP(CPageThird)
  39. DDX_Control(pDX, IDC_TOTAL_TIME, c_TotalTime);
  40. DDX_Control(pDX, IDC_PROGRESS_PERCENT, c_Percent);
  41. DDX_Control(pDX, IDC_PROGRESS, c_Progress);
  42. DDX_Control(pDX, IDC_MESSAGES, c_Messages);
  43. //}}AFX_DATA_MAP
  44. }
  45. BEGIN_MESSAGE_MAP(CPageThird, CPage)
  46. //{{AFX_MSG_MAP(CPageThird)
  47. ON_WM_TIMER()
  48. //}}AFX_MSG_MAP
  49. ON_MESSAGE(UM_START_PROCESS, OnStartProcess)
  50. ON_MESSAGE(UM_NERO_USER_DIALOG, OnNeroUserDialog)
  51. ON_MESSAGE(UM_NERO_IDLE_CALLBACK, OnNeroIdleCallback)
  52. END_MESSAGE_MAP()
  53. /////////////////////////////////////////////////////////////////////////////
  54. // CPageThird message handlers
  55. bool CPageThird::Create (void)
  56. {
  57. return CDialog::Create (m_lpszTemplateName, m_pParentWnd) != FALSE;
  58. }
  59. bool CPageThird::OnNext (void)
  60. {
  61. // If we are in an active state, the button is used for abortion. So,
  62. // abort and eat the button click.
  63. //
  64. if (m_bActiveState)
  65. {
  66. m_bAbort = true;
  67. return true;
  68. }
  69. else
  70. {
  71. CNVAPIExampleDlg * pParentSheet = (CNVAPIExampleDlg *) GetParent();
  72. if (pParentSheet)
  73. pParentSheet->SwitchPage(0);
  74. return true;
  75. }
  76. }
  77. void CPageThird::OnChangeState (bool bActivate, bool bForward)
  78. {
  79. // If the page is activated in the forward direction...
  80. //
  81. if (bActivate && bForward)
  82. {
  83. // Change into active state and remember the initial tick count
  84. // so we can time this transcoding and burning.
  85. //
  86. m_bActiveState = true;
  87. m_dwStartTickCount = GetTickCount ();
  88. // Start the timer that will update the elapsed time.
  89. //
  90. SetTimer (TIMER_ID, TIMER_INTERVAL, NULL);
  91. // Change Next button to Abort and disable the other one.
  92. //
  93. CString sAbort;
  94. sAbort.LoadString (IDS_BUTTON_ABORT);
  95. GetParent ()->GetDlgItem (IDOK)->SetWindowText (sAbort);
  96. GetParent ()->GetDlgItem (IDCANCEL)->EnableWindow (false);
  97. // Reset the position of the progress bar and remove all items from
  98. // the message list ctrl.
  99. //
  100. c_Progress.SetPos (0);
  101. c_Percent.SetWindowText ("");
  102. c_TotalTime.SetWindowText ("");
  103. c_Messages.DeleteAllItems ();
  104. // Reset all relevant variables.
  105. //
  106. m_LastAction = (ProgressAction) -1;
  107. m_sLastItemname.Empty ();
  108. m_bAbort = false;
  109. InsertMessage (IDS_STARTING_TRANSCODING);
  110. // Post a message to ourseleves so that everything is painted
  111. // before we begin.
  112. //
  113. PostMessage (UM_START_PROCESS);
  114. }
  115. }
  116. LRESULT CPageThird::OnStartProcess (WPARAM wParam, LPARAM lParam)
  117. {
  118. // Now start transcoding. The method won't return until it finishes
  119. // but we have a progress callback to monitor the process.
  120. //
  121. try
  122. {
  123. INeroBurnContextPtr pBurnContext;
  124. CPageData * pPageData = GetPageData ();
  125. VARIANT_BOOL bSuccess = pPageData->m_pProject->CreateNeroBurnContext (NeroAPIGlueGetModuleHandle (),
  126. this,
  127. &pBurnContext);
  128. if (!bSuccess)
  129. {
  130. // Transcoding was unsuccessful...
  131. //
  132. if (m_bAbort)
  133. {
  134. // If unsuccessful and aborted, simply display the aborted
  135. // message.
  136. //
  137. CString sAborted;
  138. sAborted.LoadString (IDS_ERROR_ABORTED);
  139. InsertMessage (sAborted);
  140. AfxMessageBox (IDS_ERROR_ABORTED);
  141. }
  142. else
  143. {
  144. // If there was an error, insert another message line into the
  145. // message listctrl and display an error message box!
  146. //
  147. IErrorPtr pError = pPageData->m_pProject->LastError;
  148. USES_CONVERSION;
  149. CString sError;
  150. CString sFormat;
  151. sFormat.LoadString (IDS_TRANSCODING_ERROR_FORMAT);
  152. sError.Format (sFormat, pError->ErrCode, W2CA (pError->XMLID), W2CA (pError->ErrText));
  153. InsertMessage (sError);
  154. AfxMessageBox (IDS_ERROR_TRANSCODING);
  155. }
  156. }
  157. else
  158. {
  159. // Ok, now do the burning...
  160. //
  161. InsertMessage (IDS_STARTING_BURNING);
  162. bool bBurnError = true;
  163. // Open the device...
  164. //
  165. NERO_DEVICEHANDLE hDevice = NeroOpenDevice (pPageData->m_pDeviceInfo);
  166. if (hDevice != NULL)
  167. {
  168. NERO_PROGRESS * pNeroProgress;
  169. // Create NERO_PROGRESS structure using API.
  170. //
  171. pNeroProgress = NeroCreateProgress ();
  172. if (pNeroProgress != NULL)
  173. {
  174. // Fill-in the NERO_PROGRESS structure wiht our own
  175. // callbacks.
  176. //
  177. pNeroProgress->npAbortedCallback = NeroAbortedCallback;
  178. pNeroProgress->npAddLogLineCallback = NeroAddLogLineCallback;
  179. pNeroProgress->npProgressCallback = NeroProgressCallback;
  180. pNeroProgress->npUserData = this;
  181. // Now, finally start burning using the NERO_CD_FORMAT
  182. // and NERO_WRITE_CD as returned from NeroVisionAPI.
  183. // The burn speed and recorder were previously selected
  184. // by the user.
  185. //
  186. NEROAPI_BURN_ERROR err;
  187. err = NeroBurn (hDevice,
  188. (NERO_CD_FORMAT) pBurnContext->NERO_CD_FORMAT,
  189. pBurnContext->NERO_WRITE_CD,
  190. NBF_WRITE|NBF_DAO,
  191. pPageData->m_dwBurnSpeed,
  192. pNeroProgress);
  193. bBurnError = err != NEROAPI_BURN_OK;
  194. NeroFreeMem (pNeroProgress);
  195. }
  196. NeroCloseDevice (hDevice);
  197. }
  198. // Display an appropriate message depending on the status of
  199. // the burn operation.
  200. //
  201. AfxMessageBox (bBurnError? IDS_BURN_FAILED: IDS_BURN_OK);
  202. }
  203. }
  204. catch (...)
  205. {
  206. AfxMessageBox (IDS_UNEXPECTED_NVAPI_ERROR);
  207. }
  208. // When everything is finally done, restore the buttons to original
  209. // state.
  210. //
  211. RestoreButtons ();
  212. return 0;
  213. }
  214. // This is a helper message to insert a message into the log using a
  215. // message string ID.
  216. //
  217. void CPageThird::InsertMessage (UINT uMessageID)
  218. {
  219. CString sMessage;
  220. sMessage.LoadString (uMessageID);
  221. InsertMessage (sMessage);
  222. }
  223. // This is a helper message to insert a message into the log using a
  224. // direct string pointer.
  225. //
  226. void CPageThird::InsertMessage (LPCSTR psMessage)
  227. {
  228. int iIndex = c_Messages.InsertItem (c_Messages.GetItemCount (), psMessage, 0);
  229. c_Messages.EnsureVisible (iIndex, false);
  230. c_Messages.UpdateWindow ();
  231. }
  232. BOOL CPageThird::OnInitDialog()
  233. {
  234. CPage::OnInitDialog();
  235. // Insert a single column into the listctrl and make sure that the
  236. // width is set to maximum minus the size of the vertical scrollbar.
  237. //
  238. CRect rcMessages;
  239. c_Messages.GetClientRect (&rcMessages);
  240. CString sColumnCaption;
  241. sColumnCaption.LoadString (IDS_MESSAGES_COLUMN);
  242. c_Messages.InsertColumn (0,
  243. sColumnCaption,
  244. LVCFMT_LEFT,
  245. rcMessages.Width () - ::GetSystemMetrics (SM_CXVSCROLL));
  246. c_Messages.SetExtendedStyle (LVS_EX_FULLROWSELECT);
  247. c_Progress.SetRange (0, 100);
  248. return TRUE; // return TRUE unless you set the focus to a control
  249. // EXCEPTION: OCX Property Pages should return FALSE
  250. }
  251. STDMETHODIMP CPageThird::raw_OnProgress (
  252. enum ProgressAction action,
  253. BSTR itemname,
  254. double currentRemain,
  255. double currentTotal,
  256. float currentFraction,
  257. double totalRemain,
  258. double totalTotal,
  259. float totalFraction)
  260. {
  261. USES_CONVERSION;
  262. CString sNewItemname = W2CA (itemname);
  263. // If either the action or the item name changed, let's insert another
  264. // message line.
  265. //
  266. if (action != m_LastAction ||
  267. sNewItemname != m_sLastItemname)
  268. {
  269. m_LastAction = action;
  270. m_sLastItemname = sNewItemname;
  271. // These phases are supported by NeroVisionAPI. Their stings are
  272. // in the string table.
  273. //
  274. static UINT uActionIDs[] = {
  275. IDS_ACTION_ESTIMATING,
  276. IDS_ACTION_PREPARING,
  277. IDS_ACTION_TRANSCODING,
  278. IDS_ACTION_GENERATING,
  279. IDS_ACTION_ANALYZING,
  280. };
  281. // Make sure the action is within known bounds.
  282. //
  283. if (action < Estimating || action > Analyzing)
  284. {
  285. action = Estimating;
  286. }
  287. // Format and insert the message line.
  288. //
  289. CString sAction;
  290. CString sMessage;
  291. sAction.LoadString (uActionIDs[action]);
  292. sMessage.Format ("%s %s", sAction, sNewItemname);
  293. InsertMessage (sMessage);
  294. }
  295. // Update the progress bar and pump the messages so that everything
  296. // remains responsive.
  297. //
  298. SetPercent ((int) (totalFraction*100));
  299. ((CNVAPIExampleApp *)AfxGetApp ())->PumpMessages ();
  300. return S_OK;
  301. }
  302. // This is a helper method to set both the progress bar and a textual
  303. // progress percent.
  304. //
  305. void CPageThird::SetPercent (int iPercent)
  306. {
  307. CString sPercent;
  308. sPercent.Format ("%d%%", iPercent);
  309. c_Percent.SetWindowText (sPercent);
  310. c_Progress.SetPos (iPercent);
  311. }
  312. STDMETHODIMP CPageThird::raw_ShouldCancel (
  313. VARIANT_BOOL * pbCancel)
  314. {
  315. // Cancel the transcoding operation as needed and pump the messages.
  316. //
  317. *pbCancel = m_bAbort? VARIANT_TRUE: VARIANT_FALSE;
  318. ((CNVAPIExampleApp *)AfxGetApp ())->PumpMessages ();
  319. return S_OK;
  320. }
  321. void CPageThird::RestoreButtons (void)
  322. {
  323. // If we are in an active state it means that we are either
  324. // transcoding or burning. Either way, we should abort the process.
  325. //
  326. m_bActiveState = false;
  327. KillTimer (TIMER_ID);
  328. CString sBack;
  329. sBack.LoadString (IDS_BUTTON_BACK);
  330. GetParent ()->GetDlgItem (IDCANCEL)->EnableWindow (true);
  331. GetParent ()->GetDlgItem (IDCANCEL)->SetWindowText (sBack);
  332. CString sFinish;
  333. sFinish.LoadString (IDS_BUTTON_FINISH);
  334. GetParent ()->GetDlgItem (IDOK)->SetWindowText (sFinish);
  335. }
  336. // The aborted callback only returns our aborted flag.
  337. //
  338. BOOL NERO_CALLBACK_ATTR CPageThird::NeroAbortedCallback (void *pUserData)
  339. {
  340. CPageThird * pThis = (CPageThird *) pUserData;
  341. return pThis->m_bAbort;
  342. }
  343. // Add log line callback inserts a new message into the log.
  344. //
  345. void NERO_CALLBACK_ATTR CPageThird::NeroAddLogLineCallback (void *pUserData, NERO_TEXT_TYPE type, const char *text)
  346. {
  347. CPageThird * pThis = (CPageThird *) pUserData;
  348. pThis->InsertMessage (text);
  349. }
  350. // Progress callback advances the progress bar.
  351. //
  352. BOOL NERO_CALLBACK_ATTR CPageThird::NeroProgressCallback (void *pUserData, DWORD dwProgressInPercent)
  353. {
  354. CPageThird * pThis = (CPageThird *) pUserData;
  355. pThis->SetPercent (dwProgressInPercent);
  356. return pThis->m_bAbort;
  357. }
  358. // This handler is for our user message UM_NERO_USER_DIALOG which is sent
  359. // to us by our parent and in turn by the application which owns the real
  360. // user dialog and idle handlers.
  361. //
  362. LRESULT CPageThird::OnNeroUserDialog (WPARAM wParam, LPARAM lParam)
  363. {
  364. return (LRESULT) NeroUserDialog ((NeroUserDlgInOut) wParam, (void *) lParam);
  365. }
  366. NeroUserDlgInOut CPageThird::NeroUserDialog (NeroUserDlgInOut type, void *data)
  367. {
  368. // We handle here only a few of the user dialog messages.
  369. //
  370. switch (type)
  371. {
  372. case DLG_WAITCD:
  373. {
  374. // When the cd is requested, display the localized version
  375. // of the message in the list ctrl log.
  376. //
  377. LPSTR psText = NeroGetLocalizedWaitCDTexts ((NERO_WAITCD_TYPE) (int)data);
  378. if (psText != NULL)
  379. {
  380. InsertMessage (psText);
  381. NeroFreeMem (psText);
  382. }
  383. }
  384. return DLG_RETURN_EXIT;
  385. case DLG_WAITCD_REMINDER:
  386. // Just insert the reminder message in the log.
  387. //
  388. InsertMessage (IDS_WAITCD_REMAINDER);
  389. return DLG_RETURN_EXIT;
  390. case DLG_WAITCD_DONE:
  391. // When waiting on a cd is done, insert a message.
  392. //
  393. InsertMessage (IDS_WAITCD_DONE);
  394. return DLG_RETURN_EXIT;
  395. case DLG_FILESEL_IMAGE:
  396. {
  397. CString sFilter;
  398. sFilter.LoadString (IDS_NERO_IMAGE_FILES_FILTER);
  399. CFileDialog fd (FALSE,
  400. "txt",
  401. NULL,
  402. OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
  403. sFilter,
  404. this);
  405. if (IDOK == fd.DoModal ())
  406. {
  407. if (fd.GetPathName ().GetLength () < MAX_PATH)
  408. {
  409. strcpy ((char *) data, fd.GetPathName ());
  410. return DLG_RETURN_CONTINUE;
  411. }
  412. }
  413. }
  414. return DLG_RETURN_EXIT;
  415. case DLG_WAITCD_MEDIA_INFO:
  416. {
  417. // Insert the info about the media present and requested.
  418. //
  419. const NERO_DLG_WAITCD_MEDIA_INFO * pMediaInfo = (const NERO_DLG_WAITCD_MEDIA_INFO *) data;
  420. ATLASSERT (pMediaInfo != NULL);
  421. CString sFormat;
  422. CString sMessage;
  423. sFormat.LoadString (IDS_FORMAT_WAITCD_MEDIA_INFO);
  424. sMessage.Format (sFormat, pMediaInfo->ndwmiLastDetectedMediaName,
  425. pMediaInfo->ndwmiRequestedMediaName);
  426. InsertMessage (sMessage);
  427. // The return value is ignored.
  428. //
  429. return DLG_RETURN_EXIT;
  430. }
  431. default:
  432. return DLG_RETURN_NOT_HANDLED;
  433. }
  434. }
  435. // We know about NeroAPI's idle callback by handling a user message
  436. // UM_NERO_IDLE_CALLBACK. All we are required to do is return our aborted
  437. // flag.
  438. //
  439. LRESULT CPageThird::OnNeroIdleCallback (WPARAM wParam, LPARAM lParam)
  440. {
  441. return (LRESULT) m_bAbort;
  442. }
  443. void CPageThird::OnTimer(UINT nIDEvent)
  444. {
  445. if (nIDEvent == TIMER_ID)
  446. {
  447. // When our timer fires, let's update the elapsed time.
  448. //
  449. DWORD dwDelta = (GetTickCount () - m_dwStartTickCount + 500)/1000;
  450. DWORD dwHours = dwDelta/3600;
  451. DWORD dwMinutes = (dwDelta%3600)/60;
  452. DWORD dwSeconds = dwDelta%60;
  453. CString sTime;
  454. sTime.Format ("%02d:%02d:%02d", dwHours, dwMinutes, dwSeconds);
  455. c_TotalTime.SetWindowText (sTime);
  456. }
  457. CPage::OnTimer(nIDEvent);
  458. }