/***************************************************************************** * * (C) COPYRIGHT MICROSOFT CORPORATION, 1998 * * TITLE: preview.cpp * * VERSION: 1.0 * * AUTHOR: RickTu * * DATE: 11/02/00 * * DESCRIPTION: Template Preview Window implementation * *****************************************************************************/ #include #pragma hdrstop /***************************************************************************** GetProgressControlRect Takes preivew window as an input, returns a rectangle that contains the size of the progress control *****************************************************************************/ void GetProgressControlRect( HWND hwnd, RECT * pRect ) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("GetProgressControlRect()"))); if (pRect) { if (hwnd) { RECT rcWnd = {0}; GetClientRect( hwnd, &rcWnd ); WIA_TRACE((TEXT("GetProgressControlRect: client rect is %d,%d,%d,%d"),rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom)); pRect->left = rcWnd.left + ((rcWnd.right - rcWnd.left) / 10); pRect->right = rcWnd.right - (pRect->left - rcWnd.left); pRect->top = rcWnd.top + ((rcWnd.bottom - rcWnd.top) / 2) + 15; // // Themes requires that progress bars be at least 10 pix high // pRect->bottom = pRect->top + 10; WIA_TRACE((TEXT("GetProgressControlRect: progress control rect being returned as %d,%d,%d,%d"),pRect->left,pRect->top,pRect->right,pRect->bottom)); } } } /***************************************************************************** CPreviewBitmap constructor/destructor *****************************************************************************/ CPreviewBitmap::CPreviewBitmap( CWizardInfoBlob * pWizInfo, HWND hwnd, INT iTemplateIndex ) : _hwndPreview(hwnd), _iTemplateIndex(iTemplateIndex), _hWorkThread(NULL), _dwWorkThreadId(0), _pWizInfo(pWizInfo), _bThreadIsStalled(FALSE) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW_BITMAP,TEXT("CPreviewBitmap::CPreviewBitmap( %i )"),iTemplateIndex)); if (_pWizInfo) { _pWizInfo->AddRef(); } _hEventForMessageQueueCreation = CreateEvent( NULL, FALSE, FALSE, NULL ); } CPreviewBitmap::~CPreviewBitmap() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW_BITMAP,TEXT("CPreviewBitmap::~CPreviewBitmap( %i )"),_iTemplateIndex)); CAutoCriticalSection lock(_csItem); // // Tell thread to exit and then for it to exit... // if (_hWorkThread && _dwWorkThreadId) { PostThreadMessage( _dwWorkThreadId, PVB_MSG_EXIT_THREAD, 0, 0 ); WiaUiUtil::MsgWaitForSingleObject( _hWorkThread, INFINITE ); CloseHandle( _hWorkThread ); } // // Now that the thread is closed (or never created), close the event handle... // if (_hEventForMessageQueueCreation) { CloseHandle( _hEventForMessageQueueCreation ); _hEventForMessageQueueCreation = NULL; } // // Let go of wizard class // if (_pWizInfo) { _pWizInfo->Release(); _pWizInfo = NULL; } } /***************************************************************************** CPreviewBitmap::MessageQueueCreated Called once message queue is created in thread proc... *****************************************************************************/ VOID CPreviewBitmap::MessageQueueCreated() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW_BITMAP,TEXT("CPreviewBitmap::MessageQueueCreated( %i )"),_iTemplateIndex)); if (_hEventForMessageQueueCreation) { SetEvent(_hEventForMessageQueueCreation); } } /***************************************************************************** CPreivewBitmap::GetPreview Called by preview window to have us post the preview bitmap back to them... *****************************************************************************/ HRESULT CPreviewBitmap::GetPreview() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW_BITMAP,TEXT("CPreviewBitmap::GetPreview( %i )"),_iTemplateIndex)); HRESULT hr = S_OK; // // First, see if our thread is already running... // CAutoCriticalSection lock(_csItem); if (_pWizInfo && (!_bThreadIsStalled)) { if (!_pWizInfo->IsWizardShuttingDown()) { if (!_hWorkThread) { _hWorkThread = CreateThread( NULL, 0, s_PreviewBitmapWorkerThread, (LPVOID)this, CREATE_SUSPENDED, &_dwWorkThreadId ); if (_hWorkThread) { // // If we created the thread, set it's priority to slight below normal so other // things run okay. This can be a CPU intensive task... // SetThreadPriority( _hWorkThread, THREAD_PRIORITY_BELOW_NORMAL ); ResumeThread( _hWorkThread ); // // Wait for message queue to be created... // if (_hEventForMessageQueueCreation) { WaitForSingleObject( _hEventForMessageQueueCreation, INFINITE ); } } else { WIA_ERROR((TEXT("GetPreview: CreateThread failed w/GLE=%d"),GetLastError())); hr = E_OUTOFMEMORY; } } } } // // If we have the thread, then tell it to generate a new preview... // if (SUCCEEDED(hr) && _hWorkThread && _dwWorkThreadId) { PostThreadMessage( _dwWorkThreadId, PVB_MSG_GENERATE_PREVIEW, 0, 0 ); } WIA_RETURN_HR(hr); } /***************************************************************************** CPreviewBitmap::GeneratePreview This function is called by the worker thread to generate a new preview for this template... *****************************************************************************/ VOID CPreviewBitmap::GeneratePreview() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW_BITMAP,TEXT("CPreviewBitmap::GeneratePreview( %i )"),_iTemplateIndex)); // // we always generate a new bitmap here, because we only get called if // the preview window doesn't have a bitmap for this template yet or // if something has caused the previews to become invalid... // if (_pWizInfo && (!_pWizInfo->IsWizardShuttingDown()) && (!_bThreadIsStalled)) { HBITMAP bmp = _pWizInfo->RenderPreview( _iTemplateIndex, _hwndPreview ); if (bmp) { // // We use sendmessage here to make sure this bitmap doesn't get // lost in transit. // LRESULT lRes = -1; if (!_pWizInfo->IsWizardShuttingDown() && (!_bThreadIsStalled)) { lRes = SendMessage( _hwndPreview, PV_MSG_PREVIEW_BITMAP_AVAILABLE, (WPARAM)_iTemplateIndex, (LPARAM)bmp ); } if ((lRes == -1) || (lRes == 0)) { // // For some reason, there was an error. So clean up by deleting // the bitmap here... // WIA_ERROR((TEXT("CPreviewBitmap::GeneratePreview - SendMessage returned error, deleting bitmap!"))); DeleteObject( (HGDIOBJ)bmp ); } } else { WIA_ERROR((TEXT("CPreviewBitmap::GeneratePreview - RenderPreview returned null bmp!"))); } } } /***************************************************************************** CPreviewBitmap::StallThread Terminate the background thread (gracefully) and don't allow it to start again until RestartThread is called... *****************************************************************************/ VOID CPreviewBitmap::StallThread() { CAutoCriticalSection lock(_csItem); _bThreadIsStalled = TRUE; if (_hWorkThread && _dwWorkThreadId) { PostThreadMessage( _dwWorkThreadId, PVB_MSG_EXIT_THREAD, 0, 0 ); WiaUiUtil::MsgWaitForSingleObject( _hWorkThread, INFINITE ); CloseHandle( _hWorkThread ); _hWorkThread = NULL; _dwWorkThreadId = 0; } } /***************************************************************************** CPreviewBitmap::RestartThread Allow background thread to be started up again... *****************************************************************************/ VOID CPreviewBitmap::RestartThread() { CAutoCriticalSection lock(_csItem); _bThreadIsStalled = FALSE; } /***************************************************************************** CPreviewBitmap::s_PreviewBitmapWorkerThread Thread proc that does all the work of generating the bitmaps *****************************************************************************/ DWORD CPreviewBitmap::s_PreviewBitmapWorkerThread(void *pv) { CPreviewBitmap * pPB = (CPreviewBitmap *)pv; if (pPB) { // // Add-ref the DLL so that it doesn't get unloaded while we're running... // HMODULE hDll = GetThreadHMODULE( s_PreviewBitmapWorkerThread ); // // Make sure COM is initialized for this thread... // HRESULT hrCo = PPWCoInitialize(); // // Create the message queue... // MSG msg; PeekMessage( &msg, NULL, WM_USER, WM_USER, PM_NOREMOVE ); // // Signal that we're ready to receive messages... // pPB->MessageQueueCreated(); // // Loop until we get message to quit... // BOOL bExit = FALSE; while ((!bExit) && (-1!=GetMessage( &msg, NULL, PVB_MSG_START, PVB_MSG_END ))) { switch (msg.message) { case PVB_MSG_GENERATE_PREVIEW: pPB->GeneratePreview(); break; case PVB_MSG_EXIT_THREAD: bExit = TRUE; break; } } // // Unitialize COM if we initialized it earlier... // PPWCoUninitialize( hrCo ); // // Remove our reference on the DLL and exit... // if (hDll) { WIA_TRACE((TEXT("Exiting preview bitmap worker thread via FLAET..."))); FreeLibraryAndExitThread( hDll, 0 ); } } WIA_TRACE((TEXT("Exiting preview bitmap worker thread via error path..."))); return 0; } /***************************************************************************** CPreviewWindow contructor/desctructor *****************************************************************************/ CPreviewWindow::CPreviewWindow( CWizardInfoBlob * pWizInfo ) : _pWizInfo(pWizInfo), _LastTemplate(PV_NO_LAST_TEMPLATE_CHOSEN), _NumTemplates(0), _hwnd(NULL), _hwndProgress(NULL), _hPreviewList(NULL), _hStillWorkingBitmap(NULL), _bThreadsAreStalled(FALSE) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::CPreviewWindow"))); if (_pWizInfo) { _pWizInfo->AddRef(); } } CPreviewWindow::~CPreviewWindow() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::~CPreviewWindow"))); // // Make sure we clear out any remaining background info... // ShutDownBackgroundThreads(); // // Kill the progress window if it exists... // if (_hwndProgress) { DestroyWindow( _hwndProgress ); _hwndProgress = NULL; } // // Tear down whatever is remaining... // if (_hStillWorkingBitmap) { DeleteObject( (HGDIOBJ)_hStillWorkingBitmap ); } if (_pWizInfo) { _pWizInfo->Release(); } } /***************************************************************************** CPreviewWindow::StallBackgroundThreads() Tell the preview generation threads to stall out while the number of copies is changed. The threads will stay stalled until a call to CPreviewWindow::RestartBackgroundThreads() is made... *****************************************************************************/ VOID CPreviewWindow::StallBackgroundThreads() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::StallBackgroundThreads()"))); CAutoCriticalSection lock(_csList); _bThreadsAreStalled = TRUE; if (_hPreviewList) { for (INT i=0; i < _NumTemplates; i++) { // // Stall the thread... // if (_hPreviewList[i].pPreviewBitmap) { _hPreviewList[i].pPreviewBitmap->StallThread(); } // // Invalidate current bitmaps... // _hPreviewList[i].bValid = FALSE; _hPreviewList[i].bBitmapGenerationInProgress = FALSE; if (_hPreviewList[i].hPrevBmp) { DeleteObject( (HGDIOBJ)_hPreviewList[i].hPrevBmp ); _hPreviewList[i].hPrevBmp = NULL; } } } } /***************************************************************************** CPreviewWindow::RestartBackgroundThreads Tell the preview generation threads to start back up again... *****************************************************************************/ VOID CPreviewWindow::RestartBackgroundThreads() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::RestartBackgroundThreads()"))); CAutoCriticalSection lock(_csList); if (_hPreviewList) { for (INT i=0; i < _NumTemplates; i++) { if (_hPreviewList[i].pPreviewBitmap) { _hPreviewList[i].pPreviewBitmap->RestartThread(); } } } _bThreadsAreStalled = FALSE; // // Redraw currently selected template... // if (_LastTemplate != PV_NO_LAST_TEMPLATE_CHOSEN) { PostMessage( _hwnd, PV_MSG_GENERATE_NEW_PREVIEW, _LastTemplate, 0 ); } // // Tell the user we're working on a preview for them... // if (_hStillWorkingBitmap) { DrawBitmap( _hStillWorkingBitmap, NULL ); } } /***************************************************************************** CPreivewWindow::ShutDownBackgroundThread() Terminates the background threads and waits until they are gone... *****************************************************************************/ VOID CPreviewWindow::ShutDownBackgroundThreads() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::ShutDownBackgroundThreads()"))); // // Let's tear down the background threads... // _csList.Enter(); if (_hPreviewList) { for (INT i = 0; i < _NumTemplates; i++) { if (_hPreviewList[i].hPrevBmp) { DeleteObject( (HGDIOBJ)_hPreviewList[i].hPrevBmp ); _hPreviewList[i].hPrevBmp = NULL; } if (_hPreviewList[i].pPreviewBitmap) { delete _hPreviewList[i].pPreviewBitmap; _hPreviewList[i].pPreviewBitmap = NULL; } } delete [] _hPreviewList; _hPreviewList = NULL; } _csList.Leave(); // // Notify wizard that we've shut down // if (_pWizInfo) { _pWizInfo->PreviewIsShutDown(); } } /***************************************************************************** CPreviewWindow::InitList If not already done, initialize the bitmap list for the window... *****************************************************************************/ VOID CPreviewWindow::_InitList() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::_InitList()"))); CAutoCriticalSection lock(_csList); if (_pWizInfo && (!_pWizInfo->IsWizardShuttingDown())) { if (!_hPreviewList) { // // Create a list for holding the hBitmap previews... // if (_pWizInfo) { _NumTemplates = _pWizInfo->CountOfTemplates(); _hPreviewList = new PREVIEW_STATE [_NumTemplates]; if (_hPreviewList) { // // Pre-initialize each entry // for (INT i = 0; i < _NumTemplates; i++) { _hPreviewList[i].hPrevBmp = NULL; _hPreviewList[i].bValid = FALSE; _hPreviewList[i].bBitmapGenerationInProgress = FALSE; _hPreviewList[i].pPreviewBitmap = new CPreviewBitmap( _pWizInfo, _hwnd, i ); } } } } } } /***************************************************************************** CPreviewWindow::InvalidateAllPreviews Marks all the previews as invalid -- must be re-computed *****************************************************************************/ VOID CPreviewWindow::InvalidateAllPreviews() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::InvalidateAllPreviews()"))); CAutoCriticalSection lock(_csList); if (_hPreviewList) { for (INT i = 0; i < _NumTemplates; i++) { _hPreviewList[i].bValid = FALSE; _hPreviewList[i].bBitmapGenerationInProgress = FALSE; if (_hPreviewList[i].hPrevBmp) { DeleteObject( (HGDIOBJ)_hPreviewList[i].hPrevBmp ); _hPreviewList[i].hPrevBmp = NULL; } } } if (_hStillWorkingBitmap) { DeleteObject(_hStillWorkingBitmap); _hStillWorkingBitmap = NULL; } } /***************************************************************************** CPreviewWindow::DrawBitmap *****************************************************************************/ VOID CPreviewWindow::DrawBitmap( HBITMAP hBitmap, HDC hdc ) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::DrawBitmap()"))); // // Don't bother painting the bitmap if we don't have an image. // if (!hBitmap) return; Gdiplus::Bitmap bmp( hBitmap, NULL ); if (Gdiplus::Ok == bmp.GetLastStatus()) { Gdiplus::Graphics * g; if (hdc) g = Gdiplus::Graphics::FromHDC( hdc ); else g = Gdiplus::Graphics::FromHWND( _hwnd ); if (g && (Gdiplus::Ok == g->GetLastStatus())) { g->DrawImage( &bmp, 0, 0 ); if (Gdiplus::Ok != g->GetLastStatus()) { WIA_ERROR((TEXT("DrawBitmap: g->DrawImage call failed, Status = %d"),g->GetLastStatus())); } } else { WIA_ERROR((TEXT("DrawBitmap: couldn't create GDI+ Graphics from Bitmap"))); } if (g) { delete g; } } } /***************************************************************************** CPreviewWindow::ShowStillWorking Shows the "generating a preview" message... *****************************************************************************/ VOID CPreviewWindow::ShowStillWorking( HWND hwnd ) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::ShowStillWorking()"))); if (_pWizInfo && (!_pWizInfo->IsWizardShuttingDown())) { CAutoCriticalSection lock(_csList); // // Get size of preview window // RECT rcWnd = {0}; GetClientRect( hwnd, &rcWnd ); Gdiplus::RectF rectWindow( 0.0, 0.0, (Gdiplus::REAL)(rcWnd.right - rcWnd.left), (Gdiplus::REAL)(rcWnd.bottom - rcWnd.top) ); // // Clear out window... // Gdiplus::Graphics g( hwnd ); if (Gdiplus::Ok == g.GetLastStatus()) { // // First, draw bounding rectangle // g.SetPageUnit( Gdiplus::UnitPixel ); g.SetPageScale( 1.0 ); DWORD dw = GetSysColor( COLOR_BTNFACE ); Gdiplus::Color wndClr(255,GetRValue(dw),GetGValue(dw),GetBValue(dw)); Gdiplus::SolidBrush br(wndClr); // // Clear out the contents // g.FillRectangle( &br, rectWindow ); // // Frame the rectangle // rectWindow.Inflate( -1, -1 ); Gdiplus::Color black(255,0,0,0); Gdiplus::SolidBrush BlackBrush( black ); Gdiplus::Pen BlackPen( &BlackBrush, (Gdiplus::REAL)1.0 ); g.DrawRectangle( &BlackPen, rectWindow ); // // Draw text about generating preview... // CSimpleString strText(IDS_DOWNLOADINGTHUMBNAIL, g_hInst); Gdiplus::StringFormat DefaultStringFormat; Gdiplus::Font Verdana( TEXT("Verdana"), 8.0 ); Gdiplus::REAL FontH = (Gdiplus::REAL)Verdana.GetHeight( &g ); rectWindow.Y += ((rectWindow.Height - FontH) / (Gdiplus::REAL)2.0); rectWindow.Height = FontH; DefaultStringFormat.SetAlignment(Gdiplus::StringAlignmentCenter); g.DrawString( strText, strText.Length(), &Verdana, rectWindow, &DefaultStringFormat, &BlackBrush ); } } } /***************************************************************************** CPreviewWindow::GenerateWorkingBitmap Creates the "generating a preview" bitmap... *****************************************************************************/ VOID CPreviewWindow::GenerateWorkingBitmap( HWND hwnd ) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::GenerateWorkingBitmap()"))); if (_pWizInfo && (!_pWizInfo->IsWizardShuttingDown())) { CAutoCriticalSection lock(_csList); // // Do we need to generate a new one...? // if (!_hStillWorkingBitmap) { // // Get size of preview window // RECT rcWnd = {0}; GetClientRect( hwnd, &rcWnd ); Gdiplus::RectF rectWindow( 0.0, 0.0, (Gdiplus::REAL)(rcWnd.right - rcWnd.left), (Gdiplus::REAL)(rcWnd.bottom - rcWnd.top) ); WIA_TRACE((TEXT("GenerateWorkingBitmap: rectWindow is (%d,%d) @ (%d,%d)"),(INT)rectWindow.Width, (INT)rectWindow.Height, (INT)rectWindow.X, (INT)rectWindow.Y)); // // Size progress control // if (_hwndProgress) { RECT rcProgress = {0}; GetProgressControlRect( hwnd, &rcProgress ); MoveWindow( _hwndProgress, rcProgress.left, rcProgress.top, (rcProgress.right - rcProgress.left), (rcProgress.bottom - rcProgress.top), TRUE ); } // // Allocate memory for bitmap // INT stride = ((INT)rectWindow.Width * sizeof(long)); if ( (stride % 4) != 0) { stride += (4 - (stride % 4)); } BYTE * data = new BYTE[ stride * (INT)rectWindow.Height ]; if (data) { memset( data, 0, stride * (INT)rectWindow.Height ); Gdiplus::Bitmap bmp( (INT)rectWindow.Width, (INT)rectWindow.Height, stride, PixelFormat32bppRGB, data ); if (Gdiplus::Ok == bmp.GetLastStatus()) { // // Draw a rectangle, 1 pixel wide, around the outside // with an interior that is white // Gdiplus::Graphics g( &bmp ); if (Gdiplus::Ok == g.GetLastStatus()) { // // First, draw bounding rectangle // g.SetPageUnit( Gdiplus::UnitPixel ); g.SetPageScale( 1.0 ); DWORD dw = GetSysColor( COLOR_BTNFACE ); Gdiplus::Color wndClr(255,GetRValue(dw),GetGValue(dw),GetBValue(dw)); Gdiplus::SolidBrush br(wndClr); // // Clear out the contents // g.FillRectangle( &br, rectWindow ); // // Frame the rectangle // rectWindow.Inflate( -1, -1 ); Gdiplus::Color black(255,0,0,0); Gdiplus::SolidBrush BlackBrush( black ); Gdiplus::Pen BlackPen( &BlackBrush, (Gdiplus::REAL)1.0 ); g.DrawRectangle( &BlackPen, rectWindow ); // // Draw text about generating preview... // CSimpleString strText(IDS_DOWNLOADINGTHUMBNAIL, g_hInst); Gdiplus::StringFormat DefaultStringFormat; Gdiplus::Font Verdana( TEXT("Verdana"), 8.0 ); Gdiplus::REAL FontH = (Gdiplus::REAL)Verdana.GetHeight( &g ); rectWindow.Y += ((rectWindow.Height - FontH) / (Gdiplus::REAL)2.0); rectWindow.Height = FontH; DefaultStringFormat.SetAlignment(Gdiplus::StringAlignmentCenter); g.DrawString( strText, strText.Length(), &Verdana, rectWindow, &DefaultStringFormat, &BlackBrush ); // // Get the HBITMAP to return... // bmp.GetHBITMAP( wndClr, &_hStillWorkingBitmap ); WIA_TRACE((TEXT("GenerateWorkingBitmap: created _hStillWorkingBitmap as 0x%x"),_hStillWorkingBitmap)); } else { WIA_ERROR((TEXT("GenerateWorkingBitmap: couldn't get graphics from bitmap"))); } } else { WIA_ERROR((TEXT("GenerateWorkingBitmap: couldn't create bitmap"))); } delete [] data; } else { WIA_ERROR((TEXT("GenerateWorkingBitmap: couldn't allocate data for bitmap"))); } } else { WIA_TRACE((TEXT("GenerateWorkingBitmap: _hStillWorkingBitmap is already valid, not generating a new one..."))); } } else { WIA_ERROR((TEXT("GenerateWorkingBitmap: _pWizInfo is NULL or wizard is shutting down, NOT generating bitmap..."))); } } /***************************************************************************** CPreviewWindow::GenerateNewPreview Generates a new preview bitmap for the given template on a background thread. *****************************************************************************/ VOID CPreviewWindow::GenerateNewPreview( INT iTemplate ) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::GenerateNewPreview( iTemplate = %d )"),iTemplate)); CAutoCriticalSection lock(_csList); if (_pWizInfo && (!_pWizInfo->IsWizardShuttingDown())) { // // If we're not already generating a preview for this item, then queue // up a request for a new preview... // if (_hPreviewList) { if (iTemplate < _NumTemplates) { if (!_hPreviewList[iTemplate].bBitmapGenerationInProgress) { if (_hPreviewList[iTemplate].pPreviewBitmap) { _hPreviewList[iTemplate].bBitmapGenerationInProgress = TRUE; _hPreviewList[iTemplate].pPreviewBitmap->GetPreview(); } } } else { WIA_ERROR((TEXT("GenerateNewPreview: iTemplate >= _NumTemplates!"))); } } else { WIA_ERROR((TEXT("GenerateNewPreview: _hPreviewList is NULL!"))); } } } /***************************************************************************** CPreviewWindow::GetPreviewBitmap Retrieves current preview bitmap if there is a valid one already computed. Otherwise, returns NULL. *****************************************************************************/ HBITMAP CPreviewWindow::GetPreviewBitmap( INT iTemplate ) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::GetPreviewBitmap( iTemplate = %d )"),iTemplate)); CAutoCriticalSection lock(_csList); if (_hPreviewList) { if (iTemplate < _NumTemplates) { if (_hPreviewList[iTemplate].bValid) { return _hPreviewList[iTemplate].hPrevBmp; } } else { WIA_ERROR((TEXT("GetPreviewBitmap: iTemplate >= _NumTemplates!"))); } } else { WIA_ERROR((TEXT("GetPreviewBitmap: _hPreviewList is NULL!"))); } return NULL; } /***************************************************************************** CPreviewWindow::OnSetNewTemplate wParam holds index of new template to do preview for *****************************************************************************/ LRESULT CPreviewWindow::OnSetNewTemplate( WPARAM wParam, HDC hdc ) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::OnSetNewTemplate( wParam = %d )"),wParam)); // // Make sure have an bitmap list to work with // _InitList(); CAutoCriticalSection lock(_csList); // // Get hBitmap of preview... // if (((INT)wParam < _NumTemplates) && _hPreviewList) { _LastTemplate = (INT)wParam; if (_LastTemplate != PV_NO_LAST_TEMPLATE_CHOSEN) { HBITMAP hBmp = GetPreviewBitmap( (INT)wParam ); if (hBmp) { // // Turn off the progress meter // if (_hwndProgress) { WIA_TRACE((TEXT("CPreviewWindow::OnSetNewTemplate - setting progress window to SW_HIDE"))); ShowWindow( _hwndProgress, SW_HIDE ); } WIA_TRACE((TEXT("CPreviewWindow::OnSetNewTemplate - preview is available, drawing it..."))); DrawBitmap( hBmp, hdc ); } else { // // no preview bitmap exists for this item // so, queue one up to be made... WIA_TRACE((TEXT("CPreviewWindow::OnSetNewTemplate - preview is not available, requesting it..."))); PostMessage( _hwnd, PV_MSG_GENERATE_NEW_PREVIEW, wParam, 0 ); // // Tell the user we're working on a preview for them... // if (_hStillWorkingBitmap) { WIA_TRACE((TEXT("CPreviewWindow::OnSetNewTemplate - still working bitmap is available, drawing it..."))); DrawBitmap( _hStillWorkingBitmap, hdc ); // // Show the progress meter... // if (_hwndProgress) { WIA_TRACE((TEXT("CPreviewWindow::OnSetNewTemplate - setting progress window to SW_SHOW"))); ShowWindow( _hwndProgress, SW_SHOW ); } } else { WIA_ERROR((TEXT("CPreviewWindow::OnSetNewTemplate - still working bitmap is NOT available, showing nothing!"))); } } } else { WIA_ERROR((TEXT("CPreviewWindow::OnSetNewTemplate - called to show template -1!"))); } } else { WIA_ERROR((TEXT("either bad index or _hPreviewList doesn't exist!"))); } return 0; } /***************************************************************************** CPreviewWindow::_OnPaint Handle WM_PAINT for our preview window *****************************************************************************/ LRESULT CPreviewWindow::_OnPaint() { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::_OnPaint()"))); if (GetUpdateRect( _hwnd, NULL, FALSE )) { PAINTSTRUCT ps = {0}; HDC hdcPaint = BeginPaint( _hwnd, &ps ); if (_LastTemplate != PV_NO_LAST_TEMPLATE_CHOSEN) { OnSetNewTemplate( _LastTemplate, hdcPaint ); } EndPaint( _hwnd, &ps ); } return 0; } /***************************************************************************** CPreviewWindow:_OnSize Handles WM_SIZE *****************************************************************************/ LRESULT CPreviewWindow::_OnSize( WPARAM wParam, LPARAM lParam ) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::_OnSize( new size is %d by %d )"),LOWORD(lParam),HIWORD(lParam))); // // If the size changes, we need to invalidate the "Generating preview" // bitmap... // CAutoCriticalSection lock(_csList); if (_hStillWorkingBitmap) { WIA_TRACE((TEXT("CPreviewWindow::_OnSize - deleting _hStillWorkingBitmap"))); DeleteObject(_hStillWorkingBitmap); _hStillWorkingBitmap = NULL; } // // If we have the progress control, resize it... // if (_hwndProgress) { RECT rc = {0}; GetProgressControlRect( _hwnd, &rc ); 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 )); MoveWindow( _hwndProgress, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE ); } return 1; } /***************************************************************************** CPreviewWindow::_OnNewPreviewAvailable This is called when the CPreviewBitmap class has rendered a new preview and wants us to update... We must return TRUE if we handle the message and everything went okay. wParam = index of template lParam = HBITMAP of preview. Note, we now own this. *****************************************************************************/ LRESULT CPreviewWindow::_OnNewPreviewAvailable( WPARAM wParam, LPARAM lParam ) { WIA_PUSH_FUNCTION_MASK((TRACE_PREVIEW,TEXT("CPreviewWindow::_OnNewPreviewAvailable( %i )"),wParam)); LRESULT lRes = -1; CAutoCriticalSection lock(_csList); if (_hPreviewList) { if ((INT)wParam < _NumTemplates) { if (!_hPreviewList[wParam].bValid) { if (_hPreviewList[wParam].bBitmapGenerationInProgress) { // // We're expecting this bitmap! // if (lParam) { if (_hPreviewList[wParam].hPrevBmp) { DeleteObject( (HGDIOBJ)_hPreviewList[wParam].hPrevBmp ); } _hPreviewList[wParam].hPrevBmp = (HBITMAP)lParam; _hPreviewList[wParam].bValid = TRUE; _hPreviewList[wParam].bBitmapGenerationInProgress = FALSE; lRes = 1; // // Do we need to draw this new bitmap? // if (_LastTemplate == (INT)wParam) { // // Turn off the progress meter // if (_hwndProgress) { WIA_TRACE((TEXT("CPreviewWindow::_OnNewPreviewAvailable - setting progress window to SW_HIDE"))); ShowWindow( _hwndProgress, SW_HIDE ); } // // Draw new template... // DrawBitmap( _hPreviewList[wParam].hPrevBmp ); } } } else { // // Looks like the preview was invalidated! So, dump this // bitmap -- this should happen automatically by returning // an error code... // WIA_TRACE((TEXT("_OnNewPreviewAvailable: Dumping bitmap because bBitmapGenerationInProgress was false"))); } } else { WIA_ERROR((TEXT("_OnNewPreviewAvailable: Template bitmap is already valid?"))); } } else { WIA_ERROR((TEXT("_OnNewPreviewAvailable: bad template index!"))); } } else { WIA_ERROR((TEXT("_OnNewPreviewAvailable: There's no _hPreviewList!"))); } return lRes; } /***************************************************************************** CPreviewWindow::DoHandleMessage Handles incoming window messages *****************************************************************************/ LRESULT CPreviewWindow::DoHandleMessage( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { WIA_PUSH_FUNCTION_MASK((TRACE_DLGPROC, TEXT("CPreviewWindow::DoHandleMessage( 0x%x, 0x%x, 0x%x, 0x%x )"),hwnd,uMsg,wParam,lParam)); switch (uMsg) { case WM_NCCREATE: return TRUE; case WM_CREATE: { _hwnd = hwnd; _InitList(); RECT rc = {0}; GetProgressControlRect( hwnd, &rc ); // // Create progress bar, initially hidden // _hwndProgress = CreateWindow( PROGRESS_CLASS, TEXT(""), WS_CHILD|PBS_MARQUEE, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hwnd, reinterpret_cast(IDC_PREVIEW_PROGRESS), NULL, NULL ); if (_hwndProgress) { // // Put it in marquee mode // SendMessage( _hwndProgress, PBM_SETMARQUEE, TRUE, 100 ); } } return 0; case WM_PAINT: return _OnPaint(); case WM_SIZE: return _OnSize( wParam, lParam ); case PW_SETNEWTEMPLATE: if (_LastTemplate == (INT)wParam) { if (_hPreviewList) { if (_hPreviewList[wParam].bValid) { // // Don't need to draw again, so return... // return 0; } } } return OnSetNewTemplate( wParam ); case PV_MSG_GENERATE_NEW_PREVIEW: GenerateNewPreview( (INT)wParam ); return 0; case PV_MSG_PREVIEW_BITMAP_AVAILABLE: return _OnNewPreviewAvailable( wParam, lParam ); } return 0; }