windows-nt/Source/XPSP1/NT/printscan/ui/photowiz/preview.cpp
2020-09-26 16:20:57 +08:00

1460 lines
39 KiB
C++

/*****************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORPORATION, 1998
*
* TITLE: preview.cpp
*
* VERSION: 1.0
*
* AUTHOR: RickTu
*
* DATE: 11/02/00
*
* DESCRIPTION: Template Preview Window implementation
*
*****************************************************************************/
#include <precomp.h>
#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
<Notes>
*****************************************************************************/
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
<Notes>
*****************************************************************************/
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<HMENU>(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;
}