Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1459 lines
41 KiB

  1. /*****************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1998
  4. *
  5. * TITLE: preview.cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: RickTu
  10. *
  11. * DATE: 11/02/00
  12. *
  13. * DESCRIPTION: Template Preview Window implementation
  14. *
  15. *****************************************************************************/
  16. #include <precomp.h>
  17. #pragma hdrstop
  18. /*****************************************************************************
  19. GetProgressControlRect
  20. Takes preivew window as an input, returns a rectangle that contains
  21. the size of the progress control
  22. *****************************************************************************/
  23. void GetProgressControlRect( HWND hwnd, RECT * pRect )
  24. {
  25. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("GetProgressControlRect()")));
  26. if (pRect)
  27. {
  28. if (hwnd)
  29. {
  30. RECT rcWnd = {0};
  31. GetClientRect( hwnd, &rcWnd );
  32. WIA_TRACE((TEXT("GetProgressControlRect: client rect is %d,%d,%d,%d"),rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom));
  33. pRect->left = rcWnd.left + ((rcWnd.right - rcWnd.left) / 10);
  34. pRect->right = rcWnd.right - (pRect->left - rcWnd.left);
  35. pRect->top = rcWnd.top + ((rcWnd.bottom - rcWnd.top) / 2) + 15;
  36. //
  37. // Themes requires that progress bars be at least 10 pix high
  38. //
  39. pRect->bottom = pRect->top + 10;
  40. WIA_TRACE((TEXT("GetProgressControlRect: progress control rect being returned as %d,%d,%d,%d"),pRect->left,pRect->top,pRect->right,pRect->bottom));
  41. }
  42. }
  43. }
  44. /*****************************************************************************
  45. CPreviewBitmap constructor/destructor
  46. *****************************************************************************/
  47. CPreviewBitmap::CPreviewBitmap( CWizardInfoBlob * pWizInfo, HWND hwnd, INT iTemplateIndex )
  48. : _hwndPreview(hwnd),
  49. _iTemplateIndex(iTemplateIndex),
  50. _hWorkThread(NULL),
  51. _dwWorkThreadId(0),
  52. _pWizInfo(pWizInfo),
  53. _bThreadIsStalled(FALSE)
  54. {
  55. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW_BITMAP,TEXT("CPreviewBitmap::CPreviewBitmap( %i )"),iTemplateIndex));
  56. if (_pWizInfo)
  57. {
  58. _pWizInfo->AddRef();
  59. }
  60. _hEventForMessageQueueCreation = CreateEvent( NULL, FALSE, FALSE, NULL );
  61. }
  62. CPreviewBitmap::~CPreviewBitmap()
  63. {
  64. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW_BITMAP,TEXT("CPreviewBitmap::~CPreviewBitmap( %i )"),_iTemplateIndex));
  65. CAutoCriticalSection lock(_csItem);
  66. //
  67. // Tell thread to exit and then for it to exit...
  68. //
  69. if (_hWorkThread && _dwWorkThreadId)
  70. {
  71. PostThreadMessage( _dwWorkThreadId, PVB_MSG_EXIT_THREAD, 0, 0 );
  72. WiaUiUtil::MsgWaitForSingleObject( _hWorkThread, INFINITE );
  73. CloseHandle( _hWorkThread );
  74. }
  75. //
  76. // Now that the thread is closed (or never created), close the event handle...
  77. //
  78. if (_hEventForMessageQueueCreation)
  79. {
  80. CloseHandle( _hEventForMessageQueueCreation );
  81. _hEventForMessageQueueCreation = NULL;
  82. }
  83. //
  84. // Let go of wizard class
  85. //
  86. if (_pWizInfo)
  87. {
  88. _pWizInfo->Release();
  89. _pWizInfo = NULL;
  90. }
  91. }
  92. /*****************************************************************************
  93. CPreviewBitmap::MessageQueueCreated
  94. Called once message queue is created in thread proc...
  95. *****************************************************************************/
  96. VOID CPreviewBitmap::MessageQueueCreated()
  97. {
  98. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW_BITMAP,TEXT("CPreviewBitmap::MessageQueueCreated( %i )"),_iTemplateIndex));
  99. if (_hEventForMessageQueueCreation)
  100. {
  101. SetEvent(_hEventForMessageQueueCreation);
  102. }
  103. }
  104. /*****************************************************************************
  105. CPreivewBitmap::GetPreview
  106. Called by preview window to have us post the preview bitmap back to them...
  107. *****************************************************************************/
  108. HRESULT CPreviewBitmap::GetPreview()
  109. {
  110. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW_BITMAP,TEXT("CPreviewBitmap::GetPreview( %i )"),_iTemplateIndex));
  111. HRESULT hr = S_OK;
  112. //
  113. // First, see if our thread is already running...
  114. //
  115. CAutoCriticalSection lock(_csItem);
  116. if (_pWizInfo && (!_bThreadIsStalled))
  117. {
  118. if (!_pWizInfo->IsWizardShuttingDown())
  119. {
  120. if (!_hWorkThread)
  121. {
  122. _hWorkThread = CreateThread( NULL, 0, s_PreviewBitmapWorkerThread, (LPVOID)this, CREATE_SUSPENDED, &_dwWorkThreadId );
  123. if (_hWorkThread)
  124. {
  125. //
  126. // If we created the thread, set it's priority to slight below normal so other
  127. // things run okay. This can be a CPU intensive task...
  128. //
  129. SetThreadPriority( _hWorkThread, THREAD_PRIORITY_BELOW_NORMAL );
  130. ResumeThread( _hWorkThread );
  131. //
  132. // Wait for message queue to be created...
  133. //
  134. if (_hEventForMessageQueueCreation)
  135. {
  136. WaitForSingleObject( _hEventForMessageQueueCreation, INFINITE );
  137. }
  138. }
  139. else
  140. {
  141. WIA_ERROR((TEXT("GetPreview: CreateThread failed w/GLE=%d"),GetLastError()));
  142. hr = E_OUTOFMEMORY;
  143. }
  144. }
  145. }
  146. }
  147. //
  148. // If we have the thread, then tell it to generate a new preview...
  149. //
  150. if (SUCCEEDED(hr) && _hWorkThread && _dwWorkThreadId)
  151. {
  152. PostThreadMessage( _dwWorkThreadId, PVB_MSG_GENERATE_PREVIEW, 0, 0 );
  153. }
  154. WIA_RETURN_HR(hr);
  155. }
  156. /*****************************************************************************
  157. CPreviewBitmap::GeneratePreview
  158. This function is called by the worker thread to generate a new
  159. preview for this template...
  160. *****************************************************************************/
  161. VOID CPreviewBitmap::GeneratePreview()
  162. {
  163. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW_BITMAP,TEXT("CPreviewBitmap::GeneratePreview( %i )"),_iTemplateIndex));
  164. //
  165. // we always generate a new bitmap here, because we only get called if
  166. // the preview window doesn't have a bitmap for this template yet or
  167. // if something has caused the previews to become invalid...
  168. //
  169. if (_pWizInfo && (!_pWizInfo->IsWizardShuttingDown()) && (!_bThreadIsStalled))
  170. {
  171. HBITMAP bmp = _pWizInfo->RenderPreview( _iTemplateIndex, _hwndPreview );
  172. if (bmp)
  173. {
  174. //
  175. // We use sendmessage here to make sure this bitmap doesn't get
  176. // lost in transit.
  177. //
  178. LRESULT lRes = -1;
  179. if (!_pWizInfo->IsWizardShuttingDown() && (!_bThreadIsStalled))
  180. {
  181. lRes = SendMessage( _hwndPreview, PV_MSG_PREVIEW_BITMAP_AVAILABLE, (WPARAM)_iTemplateIndex, (LPARAM)bmp );
  182. }
  183. if ((lRes == -1) || (lRes == 0))
  184. {
  185. //
  186. // For some reason, there was an error. So clean up by deleting
  187. // the bitmap here...
  188. //
  189. WIA_ERROR((TEXT("CPreviewBitmap::GeneratePreview - SendMessage returned error, deleting bitmap!")));
  190. DeleteObject( (HGDIOBJ)bmp );
  191. }
  192. }
  193. else
  194. {
  195. WIA_ERROR((TEXT("CPreviewBitmap::GeneratePreview - RenderPreview returned null bmp!")));
  196. }
  197. }
  198. }
  199. /*****************************************************************************
  200. CPreviewBitmap::StallThread
  201. Terminate the background thread (gracefully) and don't allow it
  202. to start again until RestartThread is called...
  203. *****************************************************************************/
  204. VOID CPreviewBitmap::StallThread()
  205. {
  206. CAutoCriticalSection lock(_csItem);
  207. _bThreadIsStalled = TRUE;
  208. if (_hWorkThread && _dwWorkThreadId)
  209. {
  210. PostThreadMessage( _dwWorkThreadId, PVB_MSG_EXIT_THREAD, 0, 0 );
  211. WiaUiUtil::MsgWaitForSingleObject( _hWorkThread, INFINITE );
  212. CloseHandle( _hWorkThread );
  213. _hWorkThread = NULL;
  214. _dwWorkThreadId = 0;
  215. }
  216. }
  217. /*****************************************************************************
  218. CPreviewBitmap::RestartThread
  219. Allow background thread to be started up again...
  220. *****************************************************************************/
  221. VOID CPreviewBitmap::RestartThread()
  222. {
  223. CAutoCriticalSection lock(_csItem);
  224. _bThreadIsStalled = FALSE;
  225. }
  226. /*****************************************************************************
  227. CPreviewBitmap::s_PreviewBitmapWorkerThread
  228. Thread proc that does all the work of generating the bitmaps
  229. *****************************************************************************/
  230. DWORD CPreviewBitmap::s_PreviewBitmapWorkerThread(void *pv)
  231. {
  232. CPreviewBitmap * pPB = (CPreviewBitmap *)pv;
  233. if (pPB)
  234. {
  235. //
  236. // Add-ref the DLL so that it doesn't get unloaded while we're running...
  237. //
  238. HMODULE hDll = GetThreadHMODULE( s_PreviewBitmapWorkerThread );
  239. //
  240. // Make sure COM is initialized for this thread...
  241. //
  242. HRESULT hrCo = PPWCoInitialize();
  243. //
  244. // Create the message queue...
  245. //
  246. MSG msg;
  247. PeekMessage( &msg, NULL, WM_USER, WM_USER, PM_NOREMOVE );
  248. //
  249. // Signal that we're ready to receive messages...
  250. //
  251. pPB->MessageQueueCreated();
  252. //
  253. // Loop until we get message to quit...
  254. //
  255. BOOL bExit = FALSE;
  256. while ((!bExit) && (-1!=GetMessage( &msg, NULL, PVB_MSG_START, PVB_MSG_END )))
  257. {
  258. switch (msg.message)
  259. {
  260. case PVB_MSG_GENERATE_PREVIEW:
  261. pPB->GeneratePreview();
  262. break;
  263. case PVB_MSG_EXIT_THREAD:
  264. bExit = TRUE;
  265. break;
  266. }
  267. }
  268. //
  269. // Unitialize COM if we initialized it earlier...
  270. //
  271. PPWCoUninitialize( hrCo );
  272. //
  273. // Remove our reference on the DLL and exit...
  274. //
  275. if (hDll)
  276. {
  277. WIA_TRACE((TEXT("Exiting preview bitmap worker thread via FLAET...")));
  278. FreeLibraryAndExitThread( hDll, 0 );
  279. }
  280. }
  281. WIA_TRACE((TEXT("Exiting preview bitmap worker thread via error path...")));
  282. return 0;
  283. }
  284. /*****************************************************************************
  285. CPreviewWindow contructor/desctructor
  286. <Notes>
  287. *****************************************************************************/
  288. CPreviewWindow::CPreviewWindow( CWizardInfoBlob * pWizInfo )
  289. : _pWizInfo(pWizInfo),
  290. _LastTemplate(PV_NO_LAST_TEMPLATE_CHOSEN),
  291. _NumTemplates(0),
  292. _hwnd(NULL),
  293. _hwndProgress(NULL),
  294. _hPreviewList(NULL),
  295. _hStillWorkingBitmap(NULL),
  296. _bThreadsAreStalled(FALSE)
  297. {
  298. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::CPreviewWindow")));
  299. if (_pWizInfo)
  300. {
  301. _pWizInfo->AddRef();
  302. }
  303. }
  304. CPreviewWindow::~CPreviewWindow()
  305. {
  306. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::~CPreviewWindow")));
  307. //
  308. // Make sure we clear out any remaining background info...
  309. //
  310. ShutDownBackgroundThreads();
  311. //
  312. // Kill the progress window if it exists...
  313. //
  314. if (_hwndProgress)
  315. {
  316. DestroyWindow( _hwndProgress );
  317. _hwndProgress = NULL;
  318. }
  319. //
  320. // Tear down whatever is remaining...
  321. //
  322. if (_hStillWorkingBitmap)
  323. {
  324. DeleteObject( (HGDIOBJ)_hStillWorkingBitmap );
  325. }
  326. if (_pWizInfo)
  327. {
  328. _pWizInfo->Release();
  329. }
  330. }
  331. /*****************************************************************************
  332. CPreviewWindow::StallBackgroundThreads()
  333. Tell the preview generation threads to stall out while
  334. the number of copies is changed. The threads will stay
  335. stalled until a call to CPreviewWindow::RestartBackgroundThreads()
  336. is made...
  337. *****************************************************************************/
  338. VOID CPreviewWindow::StallBackgroundThreads()
  339. {
  340. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::StallBackgroundThreads()")));
  341. CAutoCriticalSection lock(_csList);
  342. _bThreadsAreStalled = TRUE;
  343. if (_hPreviewList)
  344. {
  345. for (INT i=0; i < _NumTemplates; i++)
  346. {
  347. //
  348. // Stall the thread...
  349. //
  350. if (_hPreviewList[i].pPreviewBitmap)
  351. {
  352. _hPreviewList[i].pPreviewBitmap->StallThread();
  353. }
  354. //
  355. // Invalidate current bitmaps...
  356. //
  357. _hPreviewList[i].bValid = FALSE;
  358. _hPreviewList[i].bBitmapGenerationInProgress = FALSE;
  359. if (_hPreviewList[i].hPrevBmp)
  360. {
  361. DeleteObject( (HGDIOBJ)_hPreviewList[i].hPrevBmp );
  362. _hPreviewList[i].hPrevBmp = NULL;
  363. }
  364. }
  365. }
  366. }
  367. /*****************************************************************************
  368. CPreviewWindow::RestartBackgroundThreads
  369. Tell the preview generation threads to start back up again...
  370. *****************************************************************************/
  371. VOID CPreviewWindow::RestartBackgroundThreads()
  372. {
  373. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::RestartBackgroundThreads()")));
  374. CAutoCriticalSection lock(_csList);
  375. if (_hPreviewList)
  376. {
  377. for (INT i=0; i < _NumTemplates; i++)
  378. {
  379. if (_hPreviewList[i].pPreviewBitmap)
  380. {
  381. _hPreviewList[i].pPreviewBitmap->RestartThread();
  382. }
  383. }
  384. }
  385. _bThreadsAreStalled = FALSE;
  386. //
  387. // Redraw currently selected template...
  388. //
  389. if (_LastTemplate != PV_NO_LAST_TEMPLATE_CHOSEN)
  390. {
  391. PostMessage( _hwnd, PV_MSG_GENERATE_NEW_PREVIEW, _LastTemplate, 0 );
  392. }
  393. //
  394. // Tell the user we're working on a preview for them...
  395. //
  396. if (_hStillWorkingBitmap)
  397. {
  398. DrawBitmap( _hStillWorkingBitmap, NULL );
  399. }
  400. }
  401. /*****************************************************************************
  402. CPreivewWindow::ShutDownBackgroundThread()
  403. Terminates the background threads and waits until they are gone...
  404. *****************************************************************************/
  405. VOID CPreviewWindow::ShutDownBackgroundThreads()
  406. {
  407. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::ShutDownBackgroundThreads()")));
  408. //
  409. // Let's tear down the background threads...
  410. //
  411. _csList.Enter();
  412. if (_hPreviewList)
  413. {
  414. for (INT i = 0; i < _NumTemplates; i++)
  415. {
  416. if (_hPreviewList[i].hPrevBmp)
  417. {
  418. DeleteObject( (HGDIOBJ)_hPreviewList[i].hPrevBmp );
  419. _hPreviewList[i].hPrevBmp = NULL;
  420. }
  421. if (_hPreviewList[i].pPreviewBitmap)
  422. {
  423. delete _hPreviewList[i].pPreviewBitmap;
  424. _hPreviewList[i].pPreviewBitmap = NULL;
  425. }
  426. }
  427. delete [] _hPreviewList;
  428. _hPreviewList = NULL;
  429. }
  430. _csList.Leave();
  431. //
  432. // Notify wizard that we've shut down
  433. //
  434. if (_pWizInfo)
  435. {
  436. _pWizInfo->PreviewIsShutDown();
  437. }
  438. }
  439. /*****************************************************************************
  440. CPreviewWindow::InitList
  441. If not already done, initialize the bitmap list for the window...
  442. *****************************************************************************/
  443. VOID CPreviewWindow::_InitList()
  444. {
  445. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::_InitList()")));
  446. CAutoCriticalSection lock(_csList);
  447. if (_pWizInfo && (!_pWizInfo->IsWizardShuttingDown()))
  448. {
  449. if (!_hPreviewList)
  450. {
  451. //
  452. // Create a list for holding the hBitmap previews...
  453. //
  454. if (_pWizInfo)
  455. {
  456. _NumTemplates = _pWizInfo->CountOfTemplates();
  457. _hPreviewList = new PREVIEW_STATE [_NumTemplates];
  458. if (_hPreviewList)
  459. {
  460. //
  461. // Pre-initialize each entry
  462. //
  463. for (INT i = 0; i < _NumTemplates; i++)
  464. {
  465. _hPreviewList[i].hPrevBmp = NULL;
  466. _hPreviewList[i].bValid = FALSE;
  467. _hPreviewList[i].bBitmapGenerationInProgress = FALSE;
  468. _hPreviewList[i].pPreviewBitmap = new CPreviewBitmap( _pWizInfo, _hwnd, i );
  469. }
  470. }
  471. }
  472. }
  473. }
  474. }
  475. /*****************************************************************************
  476. CPreviewWindow::InvalidateAllPreviews
  477. Marks all the previews as invalid -- must be re-computed
  478. *****************************************************************************/
  479. VOID CPreviewWindow::InvalidateAllPreviews()
  480. {
  481. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::InvalidateAllPreviews()")));
  482. CAutoCriticalSection lock(_csList);
  483. if (_hPreviewList)
  484. {
  485. for (INT i = 0; i < _NumTemplates; i++)
  486. {
  487. _hPreviewList[i].bValid = FALSE;
  488. _hPreviewList[i].bBitmapGenerationInProgress = FALSE;
  489. if (_hPreviewList[i].hPrevBmp)
  490. {
  491. DeleteObject( (HGDIOBJ)_hPreviewList[i].hPrevBmp );
  492. _hPreviewList[i].hPrevBmp = NULL;
  493. }
  494. }
  495. }
  496. if (_hStillWorkingBitmap)
  497. {
  498. DeleteObject(_hStillWorkingBitmap);
  499. _hStillWorkingBitmap = NULL;
  500. }
  501. }
  502. /*****************************************************************************
  503. CPreviewWindow::DrawBitmap
  504. <Notes>
  505. *****************************************************************************/
  506. VOID CPreviewWindow::DrawBitmap( HBITMAP hBitmap, HDC hdc )
  507. {
  508. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::DrawBitmap()")));
  509. //
  510. // Don't bother painting the bitmap if we don't have an image.
  511. //
  512. if (!hBitmap)
  513. return;
  514. Gdiplus::Bitmap bmp( hBitmap, NULL );
  515. if (Gdiplus::Ok == bmp.GetLastStatus())
  516. {
  517. Gdiplus::Graphics * g;
  518. if (hdc)
  519. g = Gdiplus::Graphics::FromHDC( hdc );
  520. else
  521. g = Gdiplus::Graphics::FromHWND( _hwnd );
  522. if (g && (Gdiplus::Ok == g->GetLastStatus()))
  523. {
  524. g->DrawImage( &bmp, 0, 0 );
  525. if (Gdiplus::Ok != g->GetLastStatus())
  526. {
  527. WIA_ERROR((TEXT("DrawBitmap: g->DrawImage call failed, Status = %d"),g->GetLastStatus()));
  528. }
  529. }
  530. else
  531. {
  532. WIA_ERROR((TEXT("DrawBitmap: couldn't create GDI+ Graphics from Bitmap")));
  533. }
  534. if (g)
  535. {
  536. delete g;
  537. }
  538. }
  539. }
  540. /*****************************************************************************
  541. CPreviewWindow::ShowStillWorking
  542. Shows the "generating a preview" message...
  543. *****************************************************************************/
  544. VOID CPreviewWindow::ShowStillWorking( HWND hwnd )
  545. {
  546. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::ShowStillWorking()")));
  547. if (_pWizInfo && (!_pWizInfo->IsWizardShuttingDown()))
  548. {
  549. CAutoCriticalSection lock(_csList);
  550. //
  551. // Get size of preview window
  552. //
  553. RECT rcWnd = {0};
  554. GetClientRect( hwnd, &rcWnd );
  555. Gdiplus::RectF rectWindow( 0.0, 0.0, (Gdiplus::REAL)(rcWnd.right - rcWnd.left), (Gdiplus::REAL)(rcWnd.bottom - rcWnd.top) );
  556. //
  557. // Clear out window...
  558. //
  559. Gdiplus::Graphics g( hwnd );
  560. if (Gdiplus::Ok == g.GetLastStatus())
  561. {
  562. //
  563. // First, draw bounding rectangle
  564. //
  565. g.SetPageUnit( Gdiplus::UnitPixel );
  566. g.SetPageScale( 1.0 );
  567. DWORD dw = GetSysColor( COLOR_BTNFACE );
  568. Gdiplus::Color wndClr(255,GetRValue(dw),GetGValue(dw),GetBValue(dw));
  569. Gdiplus::SolidBrush br(wndClr);
  570. //
  571. // Clear out the contents
  572. //
  573. g.FillRectangle( &br, rectWindow );
  574. //
  575. // Frame the rectangle
  576. //
  577. rectWindow.Inflate( -1, -1 );
  578. Gdiplus::Color black(255,0,0,0);
  579. Gdiplus::SolidBrush BlackBrush( black );
  580. Gdiplus::Pen BlackPen( &BlackBrush, (Gdiplus::REAL)1.0 );
  581. g.DrawRectangle( &BlackPen, rectWindow );
  582. //
  583. // Draw text about generating preview...
  584. //
  585. CSimpleString strText(IDS_DOWNLOADINGTHUMBNAIL, g_hInst);
  586. Gdiplus::StringFormat DefaultStringFormat;
  587. Gdiplus::Font Verdana( TEXT("Verdana"), 8.0 );
  588. Gdiplus::REAL FontH = (Gdiplus::REAL)Verdana.GetHeight( &g );
  589. rectWindow.Y += ((rectWindow.Height - FontH) / (Gdiplus::REAL)2.0);
  590. rectWindow.Height = FontH;
  591. DefaultStringFormat.SetAlignment(Gdiplus::StringAlignmentCenter);
  592. g.DrawString( strText, strText.Length(), &Verdana, rectWindow, &DefaultStringFormat, &BlackBrush );
  593. }
  594. }
  595. }
  596. /*****************************************************************************
  597. CPreviewWindow::GenerateWorkingBitmap
  598. Creates the "generating a preview" bitmap...
  599. *****************************************************************************/
  600. VOID CPreviewWindow::GenerateWorkingBitmap( HWND hwnd )
  601. {
  602. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::GenerateWorkingBitmap()")));
  603. if (_pWizInfo && (!_pWizInfo->IsWizardShuttingDown()))
  604. {
  605. CAutoCriticalSection lock(_csList);
  606. //
  607. // Do we need to generate a new one...?
  608. //
  609. if (!_hStillWorkingBitmap)
  610. {
  611. //
  612. // Get size of preview window
  613. //
  614. RECT rcWnd = {0};
  615. GetClientRect( hwnd, &rcWnd );
  616. Gdiplus::RectF rectWindow( 0.0, 0.0, (Gdiplus::REAL)(rcWnd.right - rcWnd.left), (Gdiplus::REAL)(rcWnd.bottom - rcWnd.top) );
  617. WIA_TRACE((TEXT("GenerateWorkingBitmap: rectWindow is (%d,%d) @ (%d,%d)"),(INT)rectWindow.Width, (INT)rectWindow.Height, (INT)rectWindow.X, (INT)rectWindow.Y));
  618. //
  619. // Size progress control
  620. //
  621. if (_hwndProgress)
  622. {
  623. RECT rcProgress = {0};
  624. GetProgressControlRect( hwnd, &rcProgress );
  625. MoveWindow( _hwndProgress,
  626. rcProgress.left,
  627. rcProgress.top,
  628. (rcProgress.right - rcProgress.left),
  629. (rcProgress.bottom - rcProgress.top),
  630. TRUE
  631. );
  632. }
  633. //
  634. // Allocate memory for bitmap
  635. //
  636. INT stride = ((INT)rectWindow.Width * sizeof(long));
  637. if ( (stride % 4) != 0)
  638. {
  639. stride += (4 - (stride % 4));
  640. }
  641. BYTE * data = new BYTE[ stride * (INT)rectWindow.Height ];
  642. if (data)
  643. {
  644. memset( data, 0, stride * (INT)rectWindow.Height );
  645. Gdiplus::Bitmap bmp( (INT)rectWindow.Width, (INT)rectWindow.Height, stride, PixelFormat32bppRGB, data );
  646. if (Gdiplus::Ok == bmp.GetLastStatus())
  647. {
  648. //
  649. // Draw a rectangle, 1 pixel wide, around the outside
  650. // with an interior that is white
  651. //
  652. Gdiplus::Graphics g( &bmp );
  653. if (Gdiplus::Ok == g.GetLastStatus())
  654. {
  655. //
  656. // First, draw bounding rectangle
  657. //
  658. g.SetPageUnit( Gdiplus::UnitPixel );
  659. g.SetPageScale( 1.0 );
  660. DWORD dw = GetSysColor( COLOR_BTNFACE );
  661. Gdiplus::Color wndClr(255,GetRValue(dw),GetGValue(dw),GetBValue(dw));
  662. Gdiplus::SolidBrush br(wndClr);
  663. //
  664. // Clear out the contents
  665. //
  666. g.FillRectangle( &br, rectWindow );
  667. //
  668. // Frame the rectangle
  669. //
  670. rectWindow.Inflate( -1, -1 );
  671. Gdiplus::Color black(255,0,0,0);
  672. Gdiplus::SolidBrush BlackBrush( black );
  673. Gdiplus::Pen BlackPen( &BlackBrush, (Gdiplus::REAL)1.0 );
  674. g.DrawRectangle( &BlackPen, rectWindow );
  675. //
  676. // Draw text about generating preview...
  677. //
  678. CSimpleString strText(IDS_DOWNLOADINGTHUMBNAIL, g_hInst);
  679. Gdiplus::StringFormat DefaultStringFormat;
  680. Gdiplus::Font Verdana( TEXT("Verdana"), 8.0 );
  681. Gdiplus::REAL FontH = (Gdiplus::REAL)Verdana.GetHeight( &g );
  682. rectWindow.Y += ((rectWindow.Height - FontH) / (Gdiplus::REAL)2.0);
  683. rectWindow.Height = FontH;
  684. DefaultStringFormat.SetAlignment(Gdiplus::StringAlignmentCenter);
  685. g.DrawString( strText, strText.Length(), &Verdana, rectWindow, &DefaultStringFormat, &BlackBrush );
  686. //
  687. // Get the HBITMAP to return...
  688. //
  689. bmp.GetHBITMAP( wndClr, &_hStillWorkingBitmap );
  690. WIA_TRACE((TEXT("GenerateWorkingBitmap: created _hStillWorkingBitmap as 0x%x"),_hStillWorkingBitmap));
  691. }
  692. else
  693. {
  694. WIA_ERROR((TEXT("GenerateWorkingBitmap: couldn't get graphics from bitmap")));
  695. }
  696. }
  697. else
  698. {
  699. WIA_ERROR((TEXT("GenerateWorkingBitmap: couldn't create bitmap")));
  700. }
  701. delete [] data;
  702. }
  703. else
  704. {
  705. WIA_ERROR((TEXT("GenerateWorkingBitmap: couldn't allocate data for bitmap")));
  706. }
  707. }
  708. else
  709. {
  710. WIA_TRACE((TEXT("GenerateWorkingBitmap: _hStillWorkingBitmap is already valid, not generating a new one...")));
  711. }
  712. }
  713. else
  714. {
  715. WIA_ERROR((TEXT("GenerateWorkingBitmap: _pWizInfo is NULL or wizard is shutting down, NOT generating bitmap...")));
  716. }
  717. }
  718. /*****************************************************************************
  719. CPreviewWindow::GenerateNewPreview
  720. Generates a new preview bitmap for the given template on a background thread.
  721. *****************************************************************************/
  722. VOID CPreviewWindow::GenerateNewPreview( INT iTemplate )
  723. {
  724. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::GenerateNewPreview( iTemplate = %d )"),iTemplate));
  725. CAutoCriticalSection lock(_csList);
  726. if (_pWizInfo && (!_pWizInfo->IsWizardShuttingDown()))
  727. {
  728. //
  729. // If we're not already generating a preview for this item, then queue
  730. // up a request for a new preview...
  731. //
  732. if (_hPreviewList)
  733. {
  734. if (iTemplate < _NumTemplates)
  735. {
  736. if (!_hPreviewList[iTemplate].bBitmapGenerationInProgress)
  737. {
  738. if (_hPreviewList[iTemplate].pPreviewBitmap)
  739. {
  740. _hPreviewList[iTemplate].bBitmapGenerationInProgress = TRUE;
  741. _hPreviewList[iTemplate].pPreviewBitmap->GetPreview();
  742. }
  743. }
  744. }
  745. else
  746. {
  747. WIA_ERROR((TEXT("GenerateNewPreview: iTemplate >= _NumTemplates!")));
  748. }
  749. }
  750. else
  751. {
  752. WIA_ERROR((TEXT("GenerateNewPreview: _hPreviewList is NULL!")));
  753. }
  754. }
  755. }
  756. /*****************************************************************************
  757. CPreviewWindow::GetPreviewBitmap
  758. Retrieves current preview bitmap if there is a valid one already
  759. computed. Otherwise, returns NULL.
  760. *****************************************************************************/
  761. HBITMAP CPreviewWindow::GetPreviewBitmap( INT iTemplate )
  762. {
  763. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::GetPreviewBitmap( iTemplate = %d )"),iTemplate));
  764. CAutoCriticalSection lock(_csList);
  765. if (_hPreviewList)
  766. {
  767. if (iTemplate < _NumTemplates)
  768. {
  769. if (_hPreviewList[iTemplate].bValid)
  770. {
  771. return _hPreviewList[iTemplate].hPrevBmp;
  772. }
  773. }
  774. else
  775. {
  776. WIA_ERROR((TEXT("GetPreviewBitmap: iTemplate >= _NumTemplates!")));
  777. }
  778. }
  779. else
  780. {
  781. WIA_ERROR((TEXT("GetPreviewBitmap: _hPreviewList is NULL!")));
  782. }
  783. return NULL;
  784. }
  785. /*****************************************************************************
  786. CPreviewWindow::OnSetNewTemplate
  787. wParam holds index of new template to do preview for
  788. *****************************************************************************/
  789. LRESULT CPreviewWindow::OnSetNewTemplate( WPARAM wParam, HDC hdc )
  790. {
  791. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::OnSetNewTemplate( wParam = %d )"),wParam));
  792. //
  793. // Make sure have an bitmap list to work with
  794. //
  795. _InitList();
  796. CAutoCriticalSection lock(_csList);
  797. //
  798. // Get hBitmap of preview...
  799. //
  800. if (((INT)wParam < _NumTemplates) && _hPreviewList)
  801. {
  802. _LastTemplate = (INT)wParam;
  803. if (_LastTemplate != PV_NO_LAST_TEMPLATE_CHOSEN)
  804. {
  805. HBITMAP hBmp = GetPreviewBitmap( (INT)wParam );
  806. if (hBmp)
  807. {
  808. //
  809. // Turn off the progress meter
  810. //
  811. if (_hwndProgress)
  812. {
  813. WIA_TRACE((TEXT("CPreviewWindow::OnSetNewTemplate - setting progress window to SW_HIDE")));
  814. ShowWindow( _hwndProgress, SW_HIDE );
  815. }
  816. WIA_TRACE((TEXT("CPreviewWindow::OnSetNewTemplate - preview is available, drawing it...")));
  817. DrawBitmap( hBmp, hdc );
  818. }
  819. else
  820. {
  821. //
  822. // no preview bitmap exists for this item
  823. // so, queue one up to be made...
  824. WIA_TRACE((TEXT("CPreviewWindow::OnSetNewTemplate - preview is not available, requesting it...")));
  825. PostMessage( _hwnd, PV_MSG_GENERATE_NEW_PREVIEW, wParam, 0 );
  826. //
  827. // Tell the user we're working on a preview for them...
  828. //
  829. if (_hStillWorkingBitmap)
  830. {
  831. WIA_TRACE((TEXT("CPreviewWindow::OnSetNewTemplate - still working bitmap is available, drawing it...")));
  832. DrawBitmap( _hStillWorkingBitmap, hdc );
  833. //
  834. // Show the progress meter...
  835. //
  836. if (_hwndProgress)
  837. {
  838. WIA_TRACE((TEXT("CPreviewWindow::OnSetNewTemplate - setting progress window to SW_SHOW")));
  839. ShowWindow( _hwndProgress, SW_SHOW );
  840. }
  841. }
  842. else
  843. {
  844. WIA_ERROR((TEXT("CPreviewWindow::OnSetNewTemplate - still working bitmap is NOT available, showing nothing!")));
  845. }
  846. }
  847. }
  848. else
  849. {
  850. WIA_ERROR((TEXT("CPreviewWindow::OnSetNewTemplate - called to show template -1!")));
  851. }
  852. }
  853. else
  854. {
  855. WIA_ERROR((TEXT("either bad index or _hPreviewList doesn't exist!")));
  856. }
  857. return 0;
  858. }
  859. /*****************************************************************************
  860. CPreviewWindow::_OnPaint
  861. Handle WM_PAINT for our preview window
  862. *****************************************************************************/
  863. LRESULT CPreviewWindow::_OnPaint()
  864. {
  865. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::_OnPaint()")));
  866. if (GetUpdateRect( _hwnd, NULL, FALSE ))
  867. {
  868. PAINTSTRUCT ps = {0};
  869. HDC hdcPaint = BeginPaint( _hwnd, &ps );
  870. if (_LastTemplate != PV_NO_LAST_TEMPLATE_CHOSEN)
  871. {
  872. OnSetNewTemplate( _LastTemplate, hdcPaint );
  873. }
  874. EndPaint( _hwnd, &ps );
  875. }
  876. return 0;
  877. }
  878. /*****************************************************************************
  879. CPreviewWindow:_OnSize
  880. Handles WM_SIZE
  881. *****************************************************************************/
  882. LRESULT CPreviewWindow::_OnSize( WPARAM wParam, LPARAM lParam )
  883. {
  884. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::_OnSize( new size is %d by %d )"),LOWORD(lParam),HIWORD(lParam)));
  885. //
  886. // If the size changes, we need to invalidate the "Generating preview"
  887. // bitmap...
  888. //
  889. CAutoCriticalSection lock(_csList);
  890. if (_hStillWorkingBitmap)
  891. {
  892. WIA_TRACE((TEXT("CPreviewWindow::_OnSize - deleting _hStillWorkingBitmap")));
  893. DeleteObject(_hStillWorkingBitmap);
  894. _hStillWorkingBitmap = NULL;
  895. }
  896. //
  897. // If we have the progress control, resize it...
  898. //
  899. if (_hwndProgress)
  900. {
  901. RECT rc = {0};
  902. GetProgressControlRect( _hwnd, &rc );
  903. WIA_TRACE((TEXT("CPreviewWindow::_OnSize - calling MoveWindow( _hwndProgress, %d, %d, %d, %d, TRUE )"),rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top ));
  904. MoveWindow( _hwndProgress,
  905. rc.left,
  906. rc.top,
  907. rc.right - rc.left,
  908. rc.bottom - rc.top,
  909. TRUE
  910. );
  911. }
  912. return 1;
  913. }
  914. /*****************************************************************************
  915. CPreviewWindow::_OnNewPreviewAvailable
  916. This is called when the CPreviewBitmap class has rendered a new
  917. preview and wants us to update...
  918. We must return TRUE if we handle the message and everything went okay.
  919. wParam = index of template
  920. lParam = HBITMAP of preview. Note, we now own this.
  921. *****************************************************************************/
  922. LRESULT CPreviewWindow::_OnNewPreviewAvailable( WPARAM wParam, LPARAM lParam )
  923. {
  924. WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::_OnNewPreviewAvailable( %i )"),wParam));
  925. LRESULT lRes = -1;
  926. CAutoCriticalSection lock(_csList);
  927. if (_hPreviewList)
  928. {
  929. if ((INT)wParam < _NumTemplates)
  930. {
  931. if (!_hPreviewList[wParam].bValid)
  932. {
  933. if (_hPreviewList[wParam].bBitmapGenerationInProgress)
  934. {
  935. //
  936. // We're expecting this bitmap!
  937. //
  938. if (lParam)
  939. {
  940. if (_hPreviewList[wParam].hPrevBmp)
  941. {
  942. DeleteObject( (HGDIOBJ)_hPreviewList[wParam].hPrevBmp );
  943. }
  944. _hPreviewList[wParam].hPrevBmp = (HBITMAP)lParam;
  945. _hPreviewList[wParam].bValid = TRUE;
  946. _hPreviewList[wParam].bBitmapGenerationInProgress = FALSE;
  947. lRes = 1;
  948. //
  949. // Do we need to draw this new bitmap?
  950. //
  951. if (_LastTemplate == (INT)wParam)
  952. {
  953. //
  954. // Turn off the progress meter
  955. //
  956. if (_hwndProgress)
  957. {
  958. WIA_TRACE((TEXT("CPreviewWindow::_OnNewPreviewAvailable - setting progress window to SW_HIDE")));
  959. ShowWindow( _hwndProgress, SW_HIDE );
  960. }
  961. //
  962. // Draw new template...
  963. //
  964. DrawBitmap( _hPreviewList[wParam].hPrevBmp );
  965. }
  966. }
  967. }
  968. else
  969. {
  970. //
  971. // Looks like the preview was invalidated! So, dump this
  972. // bitmap -- this should happen automatically by returning
  973. // an error code...
  974. //
  975. WIA_TRACE((TEXT("_OnNewPreviewAvailable: Dumping bitmap because bBitmapGenerationInProgress was false")));
  976. }
  977. }
  978. else
  979. {
  980. WIA_ERROR((TEXT("_OnNewPreviewAvailable: Template bitmap is already valid?")));
  981. }
  982. }
  983. else
  984. {
  985. WIA_ERROR((TEXT("_OnNewPreviewAvailable: bad template index!")));
  986. }
  987. }
  988. else
  989. {
  990. WIA_ERROR((TEXT("_OnNewPreviewAvailable: There's no _hPreviewList!")));
  991. }
  992. return lRes;
  993. }
  994. /*****************************************************************************
  995. CPreviewWindow::DoHandleMessage
  996. Handles incoming window messages
  997. *****************************************************************************/
  998. LRESULT CPreviewWindow::DoHandleMessage( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  999. {
  1000. WIA_PUSH_FUNCTION_MASK((TRACE_DLGPROC, TEXT("CPreviewWindow::DoHandleMessage( 0x%x, 0x%x, 0x%x, 0x%x )"),hwnd,uMsg,wParam,lParam));
  1001. switch (uMsg)
  1002. {
  1003. case WM_NCCREATE:
  1004. return TRUE;
  1005. case WM_CREATE:
  1006. {
  1007. _hwnd = hwnd;
  1008. _InitList();
  1009. RECT rc = {0};
  1010. GetProgressControlRect( hwnd, &rc );
  1011. //
  1012. // Create progress bar, initially hidden
  1013. //
  1014. _hwndProgress = CreateWindow( PROGRESS_CLASS,
  1015. TEXT(""),
  1016. WS_CHILD|PBS_MARQUEE,
  1017. rc.left,
  1018. rc.top,
  1019. rc.right - rc.left,
  1020. rc.bottom - rc.top,
  1021. hwnd,
  1022. reinterpret_cast<HMENU>(IDC_PREVIEW_PROGRESS),
  1023. NULL,
  1024. NULL
  1025. );
  1026. if (_hwndProgress)
  1027. {
  1028. //
  1029. // Put it in marquee mode
  1030. //
  1031. SendMessage( _hwndProgress, PBM_SETMARQUEE, TRUE, 100 );
  1032. }
  1033. }
  1034. return 0;
  1035. case WM_PAINT:
  1036. return _OnPaint();
  1037. case WM_SIZE:
  1038. return _OnSize( wParam, lParam );
  1039. case PW_SETNEWTEMPLATE:
  1040. if (_LastTemplate == (INT)wParam)
  1041. {
  1042. if (_hPreviewList)
  1043. {
  1044. if (_hPreviewList[wParam].bValid)
  1045. {
  1046. //
  1047. // Don't need to draw again, so return...
  1048. //
  1049. return 0;
  1050. }
  1051. }
  1052. }
  1053. return OnSetNewTemplate( wParam );
  1054. case PV_MSG_GENERATE_NEW_PREVIEW:
  1055. GenerateNewPreview( (INT)wParam );
  1056. return 0;
  1057. case PV_MSG_PREVIEW_BITMAP_AVAILABLE:
  1058. return _OnNewPreviewAvailable( wParam, lParam );
  1059. }
  1060. return 0;
  1061. }