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

2647 lines
91 KiB
C++

#include "precomp.h"
#pragma hdrstop
#include <windows.h>
#include <wia.h>
#include <wiadef.h>
#include <commctrl.h>
#include <comctrlp.h>
#include <propidl.h>
#include "simstr.h"
#include "camdlg.h"
#include "camdlg.rh"
#include "simcrack.h"
#include "pviewids.h"
#include "dlgunits.h"
#include "miscutil.h"
#include "waitcurs.h"
#include "movewnd.h"
#include "simrect.h"
#include "simbstr.h"
#include "uiexthlp.h"
#include "gwiaevnt.h"
#include "wiacsh.h"
#include "wiadevdp.h"
//
// Thread queue messages
//
#define TQ_DESTROY (WM_USER+1)
#define TQ_GETTHUMBNAIL (WM_USER+2)
#define TQ_GETPREVIEW (WM_USER+3)
#define TQ_DELETEITEM (WM_USER+4)
//
// Control ids
//
#define IDC_TOOLBAR 1112
#define IDC_SIZEBOX 1113
//
// The UI thread will notify us that it took ownership of the data.
// otherwise, it will be deleted in the worker thread
//
#define HANDLED_THREAD_MESSAGE 1000
//
// Help IDs
//
static const DWORD g_HelpIDs[] =
{
IDC_CAMDLG_BIG_TITLE, -1,
IDC_CAMDLG_SUBTITLE, -1,
IDC_TOOLBAR_FRAME, IDH_WIA_BUTTONS,
IDC_TOOLBAR, IDH_WIA_BUTTONS,
IDOK, IDH_WIA_GET_PICS,
IDC_THUMBNAILLIST, IDH_WIA_PIC_LIST,
IDC_YOU_CAN_ALSO, IDH_WIA_VIEW_PIC_INFO,
IDC_CAMDLG_PROPERTIES, IDH_WIA_VIEW_PIC_INFO,
IDC_PREVIEW, IDH_WIA_PREVIEW_DETAIL,
IDC_INNER_PREVIEW_WINDOW, IDH_WIA_PREVIEW_DETAIL,
IDCANCEL, IDH_CANCEL,
0, 0
};
//
// Update timer
//
#define IDT_UPDATEPREVIEW 1000
#define UPDATE_PREVIEW_DELAY 500
//
// Number of milliseconds between percent display updates
//
#define PERCENT_UPDATE_GRANULARITY 1000
//
// Private messages
//
#define PWM_POSTINIT (WM_USER+1)
#define PWM_CHANGETOPARENT (WM_USER+2)
#define PWM_THUMBNAILSTATUS (WM_USER+3)
#define PWM_PREVIEWSTATUS (WM_USER+4)
#define PWM_PREVIEWPERCENT (WM_USER+5)
#define PWM_ITEMDELETED (WM_USER+6)
#define PWM_WIAEVENT (WM_USER+7)
//
// Thumbnail whitespace: the space in between images and their selection rectangles
// These values were discovered by trail and error. For instance, if you reduce
// c_nAdditionalMarginY to 20, you get really bizarre spacing problems in the list view
// in vertical mode. These values could become invalid in future versions of the listview.
//
static const int c_nAdditionalMarginX = 10;
static const int c_nAdditionalMarginY = 6;
static int c_nMinThumbnailWidth = 90;
static int c_nMinThumbnailHeight = 90;
static int c_nMaxThumbnailWidth = 120;
static int c_nMaxThumbnailHeight = 120;
//
// Button bar button bitmap sizes
//
static const int c_nButtonBitmapSizeX = 16;
static const int c_nButtonBitmapSizeY = 16;
//
// Button bar button sizes
//
static const int c_nButtonSizeX = 300; // Ridiculously large size to compensate for BTNS_AUTOSIZE bug.
static const int c_nButtonSizeY = 16;
//
// Default preview mode list width
//
static const int c_nDefaultListViewWidth = 120;
//
// These defines let me compile with pre-nt5 headers
//
#ifndef BTNS_SEP
#define BTNS_SEP TBSTYLE_SEP
#endif
#ifndef BTNS_BUTTON
#define BTNS_BUTTON TBSTYLE_BUTTON
#endif
#ifndef ListView_SetExtendedListViewStyleEx
#define ListView_SetExtendedListViewStyleEx( h, m, s )
#endif
class CGlobalInterfaceTableThreadMessage : public CNotifyThreadMessage
{
private:
DWORD m_dwGlobalInterfaceTableCookie;
private:
//
// No implementation
//
CGlobalInterfaceTableThreadMessage(void);
CGlobalInterfaceTableThreadMessage &operator=( const CGlobalInterfaceTableThreadMessage & );
CGlobalInterfaceTableThreadMessage( const CGlobalInterfaceTableThreadMessage & );
public:
CGlobalInterfaceTableThreadMessage( int nMessage, HWND hWndNotify, DWORD dwGlobalInterfaceTableCookie )
: CNotifyThreadMessage( nMessage, hWndNotify ),
m_dwGlobalInterfaceTableCookie(dwGlobalInterfaceTableCookie)
{
}
DWORD GlobalInterfaceTableCookie(void) const
{
return(m_dwGlobalInterfaceTableCookie);
}
};
class CThumbnailThreadMessage : public CGlobalInterfaceTableThreadMessage
{
private:
SIZE m_sizeThumb;
private:
//
// No implementation
//
CThumbnailThreadMessage(void);
CThumbnailThreadMessage &operator=( const CThumbnailThreadMessage & );
CThumbnailThreadMessage( const CThumbnailThreadMessage & );
public:
CThumbnailThreadMessage( HWND hWndNotify, DWORD dwGlobalInterfaceTableCookie, const SIZE &sizeThumb )
: CGlobalInterfaceTableThreadMessage( TQ_GETTHUMBNAIL, hWndNotify, dwGlobalInterfaceTableCookie ),
m_sizeThumb(sizeThumb)
{
}
const SIZE &ThumbSize(void) const
{
return(m_sizeThumb);
}
};
class CDeleteThreadMessage : public CGlobalInterfaceTableThreadMessage
{
private:
//
// No implementation
//
CDeleteThreadMessage(void);
CDeleteThreadMessage &operator=( const CDeleteThreadMessage & );
CDeleteThreadMessage( const CDeleteThreadMessage & );
public:
CDeleteThreadMessage( HWND hWndNotify, DWORD dwGlobalInterfaceTableCookie )
: CGlobalInterfaceTableThreadMessage( TQ_DELETEITEM, hWndNotify, dwGlobalInterfaceTableCookie )
{
}
};
class CPreviewThreadMessage : public CGlobalInterfaceTableThreadMessage
{
private:
CSimpleEvent m_CancelEvent;
private:
//
// No implementation
//
CPreviewThreadMessage(void);
CPreviewThreadMessage &operator=( const CPreviewThreadMessage & );
CPreviewThreadMessage( const CPreviewThreadMessage & );
public:
CPreviewThreadMessage( HWND hWndNotify, DWORD dwGlobalInterfaceTableCookie, HANDLE hCancelEvent )
: CGlobalInterfaceTableThreadMessage( TQ_GETPREVIEW, hWndNotify, dwGlobalInterfaceTableCookie ),
m_CancelEvent(hCancelEvent)
{
}
CSimpleEvent &CancelEvent(void)
{
return(m_CancelEvent);
}
};
BOOL WINAPI CCameraAcquireDialog::OnThreadDestroy( CThreadMessage * )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::OnThreadDestroy"));
return(FALSE);
}
BOOL WINAPI CCameraAcquireDialog::OnThreadDeleteItem( CThreadMessage *pMsg )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::OnThreadDeleteItem"));
CDeleteThreadMessage *pDeleteMsg = (CDeleteThreadMessage *)(pMsg);
if (pDeleteMsg)
{
CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
HRESULT hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void **)&pGlobalInterfaceTable);
if (SUCCEEDED(hr))
{
CComPtr<IWiaItem> pIWiaItem;
hr = pGlobalInterfaceTable->GetInterfaceFromGlobal( pDeleteMsg->GlobalInterfaceTableCookie(), IID_IWiaItem, (void**)&pIWiaItem );
if (SUCCEEDED(hr))
{
hr = WiaUiUtil::DeleteItemAndChildren(pIWiaItem);
WIA_TRACE((TEXT("********************* pIWiaItem->DeleteItem returned %08X"), hr ));
PostMessage( pDeleteMsg->NotifyWindow(), PWM_ITEMDELETED, pDeleteMsg->GlobalInterfaceTableCookie(), SUCCEEDED(hr) );
}
}
}
return(TRUE);
}
class CWiaDataCallback : public IWiaDataCallback
{
private:
ULONG m_cRef;
HWND m_hWndNotify;
DWORD m_dwGlobalInterfaceTableCookie;
CSimpleEvent m_CancelEvent;
DWORD m_dwPreviousTickCount;
int m_nPercentGranularity;
public:
CWiaDataCallback();
~CWiaDataCallback();
HRESULT _stdcall QueryInterface(const IID&,void**);
ULONG _stdcall AddRef();
ULONG _stdcall Release();
HRESULT _stdcall Initialize( HWND hWndNotify, DWORD dwGlobalInterfaceTableCookie, HANDLE hCancelEvent );
HRESULT _stdcall BandedDataCallback(
LONG lReason,
LONG lStatus,
LONG lPercentComplete,
LONG lOffset,
LONG lLength,
LONG lReserved,
LONG lResLength,
BYTE *pbBuffer );
};
HRESULT _stdcall CWiaDataCallback::QueryInterface(const IID& iid, void** ppv)
{
*ppv = NULL;
if (iid == IID_IUnknown || iid == IID_IWiaDataCallback)
{
*ppv = (IWiaDataCallback*)this;
}
else
{
return(E_NOINTERFACE);
}
AddRef();
return(S_OK);
}
ULONG _stdcall CWiaDataCallback::AddRef()
{
InterlockedIncrement((long*) &m_cRef);
return(m_cRef);
}
ULONG _stdcall CWiaDataCallback::Release()
{
ULONG ulRefCount = m_cRef - 1;
if (InterlockedDecrement((long*) &m_cRef) == 0)
{
delete this;
return(0);
}
return(ulRefCount);
}
CWiaDataCallback::CWiaDataCallback()
: m_cRef(0),
m_hWndNotify(NULL)
{
}
CWiaDataCallback::~CWiaDataCallback()
{
}
HRESULT _stdcall CWiaDataCallback::Initialize( HWND hWndNotify, DWORD dwGlobalInterfaceTableCookie, HANDLE hCancelEvent )
{
m_hWndNotify = hWndNotify;
m_dwGlobalInterfaceTableCookie = dwGlobalInterfaceTableCookie;
m_CancelEvent = hCancelEvent;
m_dwPreviousTickCount = 0xFFFFFF;
m_nPercentGranularity = 3;
return(S_OK);
}
HRESULT _stdcall CWiaDataCallback::BandedDataCallback(
LONG lMessage,
LONG lStatus,
LONG lPercentComplete,
LONG lOffset,
LONG lLength,
LONG lReserved,
LONG lResLength,
BYTE * /* pbBuffer */
)
{
WIA_TRACE((TEXT("BandedDataCallback: lMessage: %d, lStatus: %d, lPercentComplete: %d, lOffset: %d, lLength: %d, lReserved: %d, lResLength: %d"), lMessage, lStatus, lPercentComplete, lOffset, lLength, lReserved, lResLength ));
if (m_CancelEvent.Signalled())
return(S_FALSE);
switch (lMessage)
{
case IT_MSG_DATA_HEADER:
{
} // IT_MSG_DATA_HEADER
case IT_MSG_DATA:
{
} // IT_STATUS_TRANSFER_TO_CLIENT
break;
case IT_MSG_STATUS:
{
// Don't send status messages too frequently. Limit to one per PERCENT_UPDATE_GRANULARITY ms
DWORD dwTickCount = GetTickCount();
if ((dwTickCount - m_dwPreviousTickCount >= PERCENT_UPDATE_GRANULARITY) || (m_dwPreviousTickCount > dwTickCount))
{
m_dwPreviousTickCount = dwTickCount;
PostMessage( m_hWndNotify, PWM_PREVIEWPERCENT, (WPARAM)m_dwGlobalInterfaceTableCookie, (LPARAM)MAKELPARAM((WORD)lPercentComplete,(WORD)lStatus));
}
} // IT_MSG_STATUS
break;
case IT_MSG_TERMINATION:
{
} // IT_MSG_TERMINATION
break;
}
return(S_OK);
}
BOOL WINAPI CCameraAcquireDialog::OnGetPreview( CThreadMessage *pMsg )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::OnGetThumbnail"));
CSimpleStringWide strwImageName(L"");
CPreviewThreadMessage *pPreviewMsg = (CPreviewThreadMessage *)(pMsg);
if (pPreviewMsg)
{
CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
HRESULT hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGlobalInterfaceTable,
(void **)&pGlobalInterfaceTable);
if (SUCCEEDED(hr))
{
CComPtr<IWiaItem> pIWiaItem;
hr = pGlobalInterfaceTable->GetInterfaceFromGlobal( pPreviewMsg->GlobalInterfaceTableCookie(), IID_IWiaItem, (void**)&pIWiaItem );
if (SUCCEEDED(hr))
{
CComPtr<IWiaDataTransfer> pIBandedTran;
WIA_TRACE((TEXT("Preparing to call pIWiaItem->QueryInterface for IID_IWiaDataTransfer")));
hr = pIWiaItem->QueryInterface(IID_IWiaDataTransfer, (void**)&pIBandedTran);
if (SUCCEEDED(hr))
{
if (PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPA_FORMAT, WiaImgFmt_BMP, WIA_IPA_FIRST ) &&
PropStorageHelpers::SetProperty( pIWiaItem, WIA_IPA_TYMED, TYMED_FILE, WIA_IPA_FIRST ))
{
CWiaDataCallback* pCDataCB = new CWiaDataCallback();
WIA_TRACE((TEXT("Preparing to call pCDataCB->Initialize")));
if (pCDataCB)
{
hr = pCDataCB->Initialize( pPreviewMsg->NotifyWindow(), pPreviewMsg->GlobalInterfaceTableCookie(), pPreviewMsg->CancelEvent().Event() );
if (SUCCEEDED(hr))
{
WIA_TRACE((TEXT("Preparing to call pCDataCB->QueryInterface on IID_IWiaDataCallback")));
CComPtr<IWiaDataCallback> pIWiaDataCallback;
hr = pCDataCB->QueryInterface(IID_IWiaDataCallback,(void **)&pIWiaDataCallback);
if (SUCCEEDED(hr))
{
STGMEDIUM StgMedium;
StgMedium.tymed = TYMED_FILE;
StgMedium.pUnkForRelease = NULL;
StgMedium.hGlobal = NULL;
StgMedium.lpszFileName = NULL;
WIA_TRACE((TEXT("Preparing to call pIBandedTran->ibtGetData")));
hr = pIBandedTran->idtGetData( &StgMedium, pIWiaDataCallback );
if (SUCCEEDED(hr) && S_FALSE != hr)
{
strwImageName = StgMedium.lpszFileName;
WIA_TRACE((TEXT("pIBandedTran->ibtGetData returned %s"),StgMedium.lpszFileName));
}
else
{
WIA_PRINTHRESULT((hr,TEXT("CCameraAcquireDialog::OnGetPreview, ibtGetData failed")));
}
//
// Prevent leaks by freeing the filename. We don't call ReleaseStgMeduim, because
// it deletes the file as well.
//
if (SUCCEEDED(hr) && StgMedium.lpszFileName)
{
CoTaskMemFree(StgMedium.lpszFileName);
}
}
else
{
WIA_PRINTHRESULT((hr,TEXT("CCameraAcquireDialog::OnGetPreview, QI of IID_IWiaDataCallback failed")));
}
}
else
{
WIA_PRINTHRESULT((hr,TEXT("pCDataCB->Initialize failed")));
}
}
else
{
WIA_ERROR((TEXT("CCameraAcquireDialog::OnGetPreview, new on CWiaDataCallback failed")));
}
}
else
{
hr = MAKE_HRESULT(3,FACILITY_WIN32,ERROR_INVALID_DATA);
WIA_ERROR((TEXT("SetProperty on TYMED or FORMAT failed")));
}
}
else
{
WIA_PRINTHRESULT((hr,TEXT("CCameraAcquireDialog::OnGetPreview, QI of IID_IWiaDataTransfer failed")));
}
WIA_TRACE((TEXT("End CCameraAcquireDialog::OnGetPreviewBandedTransfer")));
}
}
//
// Allocate the filename string to return to the UI thread
//
CSimpleString *pstrDibFilename = new CSimpleString( CSimpleStringConvert::NaturalString(strwImageName) );
//
// Send the message to the UI thread
//
LRESULT lRes = SendMessage( pPreviewMsg->NotifyWindow(), PWM_PREVIEWSTATUS, pPreviewMsg->GlobalInterfaceTableCookie(), reinterpret_cast<LPARAM>(pstrDibFilename));
//
// If it fails for any reason, we will clean up to avoid leaks and orphaned temp files
//
if (HANDLED_THREAD_MESSAGE != lRes)
{
DeleteFile(CSimpleStringConvert::NaturalString(strwImageName));
if (pstrDibFilename)
{
delete pstrDibFilename;
}
}
}
return(TRUE);
}
BOOL WINAPI CCameraAcquireDialog::OnGetThumbnail( CThreadMessage *pMsg )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::OnGetThumbnail"));
HBITMAP hBmpThumbnail = NULL;
CThumbnailThreadMessage *pThumbMsg = (CThumbnailThreadMessage *)(pMsg);
if (pThumbMsg)
{
CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
HRESULT hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGlobalInterfaceTable,
(void **)&pGlobalInterfaceTable);
if (SUCCEEDED(hr))
{
CComPtr<IWiaItem> pIWiaItem;
hr = pGlobalInterfaceTable->GetInterfaceFromGlobal( pThumbMsg->GlobalInterfaceTableCookie(), IID_IWiaItem, (void**)&pIWiaItem );
if (SUCCEEDED(hr))
{
#if defined(DBG)
CSimpleStringWide strItemName;
PropStorageHelpers::GetProperty( pIWiaItem, WIA_IPA_FULL_ITEM_NAME, strItemName );
WIA_TRACE((TEXT("Getting thumbnail for %ws (0x%d, 0x%p)"), strItemName.String(), pThumbMsg->GlobalInterfaceTableCookie(), pIWiaItem.p ));
#endif
CComPtr<IWiaPropertyStorage> pIWiaPropertyStorage;
hr = pIWiaItem->QueryInterface(IID_IWiaPropertyStorage, (void**)&pIWiaPropertyStorage);
if (SUCCEEDED(hr))
{
PROPVARIANT PropVar[3];
PROPSPEC PropSpec[3];
PropSpec[0].ulKind = PRSPEC_PROPID;
PropSpec[0].propid = WIA_IPC_THUMB_WIDTH;
PropSpec[1].ulKind = PRSPEC_PROPID;
PropSpec[1].propid = WIA_IPC_THUMB_HEIGHT;
PropSpec[2].ulKind = PRSPEC_PROPID;
PropSpec[2].propid = WIA_IPC_THUMBNAIL;
hr = pIWiaPropertyStorage->ReadMultiple(ARRAYSIZE(PropSpec),PropSpec,PropVar );
if (SUCCEEDED(hr))
{
WIA_TRACE((TEXT("Attempting to get the thumbnail for GIT entry: %08X, %08X, %08X, %08X"),pThumbMsg->GlobalInterfaceTableCookie(),PropVar[0].vt,PropVar[1].vt,PropVar[2].vt));
if ((PropVar[0].vt == VT_I4 || PropVar[0].vt == VT_UI4) &&
(PropVar[1].vt == VT_I4 || PropVar[1].vt == VT_UI4) &&
(PropVar[2].vt == (VT_UI1|VT_VECTOR)))
{
UINT nBitmapDataSize = WiaUiUtil::Align(PropVar[0].ulVal*3,sizeof(DWORD)) * PropVar[1].ulVal;
if (nBitmapDataSize <= PropVar[2].caub.cElems)
{
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = PropVar[0].ulVal;
bmi.bmiHeader.biHeight = PropVar[1].ulVal;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
bmi.bmiHeader.biXPelsPerMeter = 0;
bmi.bmiHeader.biYPelsPerMeter = 0;
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biClrImportant = 0;
HDC hDC = GetDC(NULL);
if (hDC)
{
PBYTE *pBits;
HBITMAP hDibSection = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS, (PVOID*)&pBits, NULL, 0 );
if (hDibSection)
{
WIA_TRACE((TEXT("pBits: 0x%p, PropVar[2].caub.pElems: 0x%p, PropVar[2].caub.cElems: %d"), pBits, PropVar[2].caub.pElems, PropVar[2].caub.cElems));
CopyMemory( pBits, PropVar[2].caub.pElems, nBitmapDataSize );
hr = ScaleImage( hDC, hDibSection, hBmpThumbnail, pThumbMsg->ThumbSize());
if (SUCCEEDED(hr))
{
WIA_TRACE((TEXT("Sending this image (%p) to the notification window: %p"), hBmpThumbnail, pThumbMsg->NotifyWindow() ));
}
else hBmpThumbnail = NULL;
DeleteObject(hDibSection);
}
else
{
WIA_PRINTHRESULT((HRESULT_FROM_WIN32(GetLastError()),TEXT("CreateDIBSection failed")));
}
ReleaseDC(NULL,hDC);
}
else
{
WIA_PRINTHRESULT((HRESULT_FROM_WIN32(GetLastError()),TEXT("GetDC failed")));
}
}
else
{
WIA_ERROR((TEXT("nBitmapDataSize <= PropVar[2].caub.cElems was FALSE (%d, %d)"), nBitmapDataSize, PropVar[2].caub.cElems ));
}
}
PropVariantClear(&PropVar[0]);
PropVariantClear(&PropVar[1]);
PropVariantClear(&PropVar[2]);
}
else
{
WIA_PRINTHRESULT((hr,TEXT("pIWiaPropertyStorage->ReadMultiple failed")));
}
}
else
{
WIA_PRINTHRESULT((hr,TEXT("QueryInterface failed on IID_IWiaPropertyStorage")));
}
}
else
{
WIA_PRINTHRESULT((hr,TEXT("GetInterfaceFromGlobal failed on %08X"), pThumbMsg->GlobalInterfaceTableCookie() ));
}
}
else
{
WIA_PRINTHRESULT((hr,TEXT("CoCreateInstance failed on CLSID_StdGlobalInterfaceTable")));
}
//
// Send the message to the UI thread
//
LRESULT lRes = SendMessage( pThumbMsg->NotifyWindow(), PWM_THUMBNAILSTATUS, (WPARAM)pThumbMsg->GlobalInterfaceTableCookie(), (LPARAM)hBmpThumbnail );
//
// If it fails for any reason, we will clean up to avoid leaks
//
if (HANDLED_THREAD_MESSAGE != lRes)
{
if (hBmpThumbnail)
{
DeleteObject( hBmpThumbnail );
}
}
}
else
{
WIA_ERROR((TEXT("pThumbMsg")));
}
return(TRUE);
}
int CCameraAcquireDialog::FindItemInList( CCameraItem *pItem )
{
WIA_PUSH_FUNCTION((TEXT("CCameraAcquireDialog::FindItemInList( %08X )"), pItem ));
if (pItem)
{
HWND hwndList = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (hwndList)
{
for (int i=0;i<ListView_GetItemCount(hwndList);i++)
{
CCameraItem *pCurrItem = GetListItemNode(i);
if (pCurrItem)
{
WIA_TRACE((TEXT("Comparing %08X and %08X [%ws] [%ws]"), pCurrItem, pItem, pCurrItem->FullItemName().String(), pItem->FullItemName().String() ));
if (*pCurrItem == *pItem)
{
return i;
}
}
}
}
}
return(-1);
}
CCameraItem *CCameraAcquireDialog::GetCurrentPreviewItem(void)
{
CSimpleDynamicArray<int> aSelIndices;
GetSelectionIndices(aSelIndices);
if (0 == aSelIndices.Size())
return(NULL);
if (1 == aSelIndices.Size())
return(GetListItemNode(aSelIndices[0]));
return(NULL);
}
bool CCameraAcquireDialog::SetCurrentPreviewImage( const CSimpleString &strFilename, const CSimpleString &strTitle )
{
CWaitCursor wc;
bool bResult = true;
SendDlgItemMessage( m_hWnd, IDC_PREVIEW, WM_SETTEXT, 0, (LPARAM)strTitle.String() );
SIZE sizeSavedAspectRatio = m_CurrentAspectRatio;
// Set up a reasonable default
m_CurrentAspectRatio.cx = 4;
m_CurrentAspectRatio.cy = 3;
if (strFilename.Length())
{
HBITMAP hBmp = (HBITMAP)LoadImage( g_hInstance, strFilename.String(), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE );
if (hBmp)
{
BITMAP bm;
if (GetObject( hBmp, sizeof(BITMAP), &bm ))
{
m_CurrentAspectRatio.cx = bm.bmWidth;
m_CurrentAspectRatio.cy = bm.bmHeight;
}
}
SendDlgItemMessage( m_hWnd, IDC_PREVIEW, PWM_SETBITMAP, MAKEWPARAM(FALSE,FALSE), (LPARAM)hBmp );
if (memcmp(&sizeSavedAspectRatio,&m_CurrentAspectRatio,sizeof(SIZE)))
ResizeAll();
bResult = (hBmp != NULL);
}
else
{
if (SendDlgItemMessage( m_hWnd, IDC_PREVIEW, PWM_GETBITMAP, 0, 0 ))
SendDlgItemMessage( m_hWnd, IDC_PREVIEW, PWM_SETBITMAP, MAKEWPARAM(FALSE,FALSE), 0 );
if (memcmp(&sizeSavedAspectRatio,&m_CurrentAspectRatio,sizeof(SIZE)))
ResizeAll();
}
InvalidateRect( GetDlgItem( m_hWnd, IDC_PREVIEW ), NULL, FALSE );
UpdateWindow( GetDlgItem( m_hWnd, IDC_PREVIEW ) );
return(bResult);
}
// wParam = GIT cookie
// lParam = nPercent
LRESULT CCameraAcquireDialog::OnPreviewPercent( WPARAM wParam, LPARAM lParam )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::OnPreviewPercent"));
CCameraItem *pCameraItem = m_CameraItemList.Find( (DWORD)wParam );
if (pCameraItem)
{
pCameraItem->CurrentPreviewPercentage((int)LOWORD(lParam));
CCameraItem *pCurrSel = GetCurrentPreviewItem();
if (pCameraItem == pCurrSel)
{
UpdatePreview();
}
}
return(0);
}
// wParam = GIT cookie
// lParam = HBITMAP
LRESULT CCameraAcquireDialog::OnPreviewStatus( WPARAM wParam, LPARAM lParam )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::OnPreviewStatus"));
CSimpleString *pstrFilename = reinterpret_cast<CSimpleString*>(lParam);
if (pstrFilename)
{
CCameraItem *pCameraItem = m_CameraItemList.Find( static_cast<DWORD>(wParam) );
if (pCameraItem)
{
if (!pCameraItem->CancelQueueEvent().Signalled())
{
// If we weren't cancelled, set the filename
pCameraItem->PreviewFileName(*pstrFilename);
}
pCameraItem->CloseCancelEvent();
CCameraItem *pCurrSel = GetCurrentPreviewItem();
if (pCameraItem == pCurrSel)
{
SetCurrentPreviewImage( pCameraItem->PreviewFileName() );
}
}
delete pstrFilename;
}
return HANDLED_THREAD_MESSAGE;
}
LRESULT CCameraAcquireDialog::OnThumbnailStatus( WPARAM wParam, LPARAM lParam )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::OnThumbnailStatus"));
WIA_TRACE((TEXT("Looking for the item with the ID %08X"),wParam));
CCameraItem *pCameraItem = m_CameraItemList.Find( (DWORD)wParam );
if (pCameraItem)
{
WIA_TRACE((TEXT("Found a CameraItem * (%08X)"),pCameraItem));
HWND hwndList = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (hwndList)
{
WIA_TRACE((TEXT("Got the list control")));
HIMAGELIST hImageList = ListView_GetImageList( hwndList, LVSIL_NORMAL );
if (hImageList)
{
WIA_TRACE((TEXT("Got the image list")));
if ((HBITMAP)lParam)
{
WIA_TRACE((TEXT("hBitmap = %p"), lParam));
if (ImageList_Replace( hImageList, pCameraItem->ImageListIndex(), reinterpret_cast<HBITMAP>(lParam), NULL ))
{
WIA_TRACE((TEXT("Replaced the image in the list")));
int nItem = FindItemInList(pCameraItem);
if (nItem >= 0)
{
WIA_TRACE((TEXT("Found the item in the list")));
//
// Set the image to a dummy image
//
LV_ITEM lvItem;
::ZeroMemory(&lvItem,sizeof(LV_ITEM));
lvItem.iItem = nItem;
lvItem.mask = LVIF_IMAGE;
lvItem.iImage = -1;
ListView_SetItem( hwndList, &lvItem );
//
// Then set the image to the real image
//
::ZeroMemory(&lvItem,sizeof(LV_ITEM));
lvItem.iItem = nItem;
lvItem.mask = LVIF_IMAGE;
lvItem.iImage = pCameraItem->ImageListIndex();
ListView_SetItem( hwndList, &lvItem );
}
}
}
}
}
}
//
// Clean up the bitmap, regardless of any other failures, to avoid memory leaks
//
HBITMAP hBmpThumb = reinterpret_cast<HBITMAP>(lParam);
if (hBmpThumb)
{
DeleteObject(hBmpThumb);
}
return HANDLED_THREAD_MESSAGE;
}
static CThreadMessageMap g_MsgMap[] =
{
{ TQ_DESTROY, CCameraAcquireDialog::OnThreadDestroy },
{ TQ_GETTHUMBNAIL, CCameraAcquireDialog::OnGetThumbnail },
{ TQ_GETPREVIEW, CCameraAcquireDialog::OnGetPreview },
{ TQ_DELETEITEM, CCameraAcquireDialog::OnThreadDeleteItem },
{ 0, NULL}
};
//
// Sole constructor
//
CCameraAcquireDialog::CCameraAcquireDialog( HWND hWnd )
: m_hWnd(hWnd),
m_bPreviewActive(false),
m_pCurrentParentItem(NULL),
m_bFirstTime(true),
m_hBackgroundThread(NULL),
m_hBigFont(NULL),
m_nDialogMode(0),
m_hAccelTable(NULL),
m_nListViewWidth(0),
m_hIconLarge(NULL),
m_hIconSmall(NULL),
m_pThreadMessageQueue(NULL),
m_bTakePictureIsSupported(false),
m_ToolbarBitmapInfo( g_hInstance, IDB_TOOLBAR )
{
m_pThreadMessageQueue = new CThreadMessageQueue;
if (m_pThreadMessageQueue)
{
//
// Note that CBackgroundThread takes ownership of m_pThreadMessageQueue, and it doesn't have to be deleted in this thread
//
m_hBackgroundThread = CBackgroundThread::Create( m_pThreadMessageQueue, g_MsgMap, m_CancelEvent.Event(), g_hInstance );
}
m_sizeThumbnails.cx = c_nMaxThumbnailWidth;
m_sizeThumbnails.cy = c_nMaxThumbnailHeight;
m_CurrentAspectRatio.cx = 4;
m_CurrentAspectRatio.cy = 3;
WIA_ASSERT(m_hBackgroundThread != NULL);
}
HWND CCameraAcquireDialog::CreateCameraDialogToolbar(VOID)
{
ToolbarHelper::CButtonDescriptor aSingleSelModeButtons[] =
{
{ 0, IDC_ICONMODE, TBSTATE_ENABLED|TBSTATE_CHECKED, BTNS_AUTOSIZE|BTNS_BUTTON|BTNS_CHECK, true, NULL, IDS_ICONMODE },
{ 1, IDC_PREVIEWMODE, TBSTATE_ENABLED, BTNS_AUTOSIZE|BTNS_BUTTON|BTNS_CHECK, true, NULL, IDS_PREVIEWMODE },
{ 2, IDC_TAKEPICTURE, TBSTATE_ENABLED, BTNS_AUTOSIZE|BTNS_BUTTON, true, &m_bTakePictureIsSupported, IDS_TAKEPICTURE },
{ 4, IDC_DELETE, TBSTATE_ENABLED, BTNS_AUTOSIZE|BTNS_BUTTON, false, NULL, IDS_DELETE_SINGULAR }
};
ToolbarHelper::CButtonDescriptor aMultiSelModeButtons[] =
{
{ 0, IDC_ICONMODE, TBSTATE_ENABLED|TBSTATE_CHECKED, BTNS_AUTOSIZE|BTNS_BUTTON|BTNS_CHECK, true, NULL, IDS_ICONMODE },
{ 1, IDC_PREVIEWMODE, TBSTATE_ENABLED, BTNS_AUTOSIZE|BTNS_BUTTON|BTNS_CHECK, true, NULL, IDS_PREVIEWMODE },
{ 2, IDC_TAKEPICTURE, TBSTATE_ENABLED, BTNS_AUTOSIZE|BTNS_BUTTON, true, &m_bTakePictureIsSupported, IDS_TAKEPICTURE },
{ 3, IDC_SELECTALL, TBSTATE_ENABLED, BTNS_AUTOSIZE|BTNS_BUTTON, true, NULL, IDS_SELECTALL },
{ 4, IDC_DELETE, TBSTATE_ENABLED, BTNS_AUTOSIZE|BTNS_BUTTON, false, NULL, IDS_DELETE }
};
ToolbarHelper::CButtonDescriptor *pButtonDescriptors = aSingleSelModeButtons;
int nButtonDescriptorCount = ARRAYSIZE(aSingleSelModeButtons);
if (m_nDialogMode & MULTISEL_MODE)
{
pButtonDescriptors = aMultiSelModeButtons;
nButtonDescriptorCount = ARRAYSIZE(aMultiSelModeButtons);
}
return ToolbarHelper::CreateToolbar( m_hWnd, GetDlgItem( m_hWnd, IDC_CAMDLG_SUBTITLE ), GetDlgItem( m_hWnd, IDC_TOOLBAR_FRAME ), ToolbarHelper::AlignLeft|ToolbarHelper::AlignTop, IDC_TOOLBAR, m_ToolbarBitmapInfo, pButtonDescriptors, nButtonDescriptorCount );
}
HRESULT CCameraAcquireDialog::EnumerateItems( CCameraItem *pCurrentParent, IEnumWiaItem *pIEnumWiaItem )
{
WIA_PUSHFUNCTION(TEXT("CCameraItemList::EnumerateItems"));
HRESULT hr = E_FAIL;
if (pIEnumWiaItem != NULL)
{
hr = pIEnumWiaItem->Reset();
while (hr == S_OK)
{
CComPtr<IWiaItem> pIWiaItem;
hr = pIEnumWiaItem->Next(1, &pIWiaItem, NULL);
if (hr == S_OK)
{
CCameraItem *pNewCameraItem = new CCameraItem( pIWiaItem );
if (pNewCameraItem && pNewCameraItem->Item())
{
LONG ItemType = 0;
hr = pNewCameraItem->Item()->GetItemType(&ItemType);
if (SUCCEEDED(hr))
{
//
// If it is an image, add it to the list
//
if (ItemType & WiaItemTypeImage)
{
//
// Add it to the list
//
m_CameraItemList.Add( pCurrentParent, pNewCameraItem );
WIA_TRACE((TEXT("Found an image")));
}
//
// If it is a folder, enumerate its child items and recurse
//
else if (ItemType & WiaItemTypeFolder)
{
//
// Add this folder to the list
//
m_CameraItemList.Add( pCurrentParent, pNewCameraItem );
//
// Enumerate the child items
//
CComPtr <IEnumWiaItem> pIEnumChildItem;
if (S_OK == pIWiaItem->EnumChildItems(&pIEnumChildItem))
{
EnumerateItems( pNewCameraItem, pIEnumChildItem );
}
}
else
{
//
// Delete this item, since we didn't add it to the list
//
delete pNewCameraItem;
WIA_TRACE((TEXT("Found something that is NOT an image")));
}
}
}
}
}
}
return hr;
}
HRESULT CCameraAcquireDialog::EnumerateAllCameraItems(void)
{
CComPtr<IEnumWiaItem> pIEnumItem;
HRESULT hr = m_pDeviceDialogData->pIWiaItemRoot->EnumChildItems(&pIEnumItem);
if (hr == S_OK)
{
hr = EnumerateItems( NULL, pIEnumItem );
}
return(hr);
}
void CCameraAcquireDialog::OnItemCreatedEvent( CGenericWiaEventHandler::CEventMessage *pEventMessage )
{
//
// Get the listview, which we'll need later
//
HWND hwndListview = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (hwndListview)
{
//
// Get the image list
//
HIMAGELIST hImageList = ListView_GetImageList( hwndListview, LVSIL_NORMAL );
if (hImageList)
{
//
// Make sure we don't already have this item
//
CCameraItem *pCreatedItem = m_CameraItemList.Find(CSimpleBStr(pEventMessage->FullItemName()));
if (!pCreatedItem)
{
//
// Get the IWiaItem* for this item
//
CComPtr<IWiaItem> pWiaItem;
HRESULT hr = m_pDeviceDialogData->pIWiaItemRoot->FindItemByName(0,CSimpleBStr(pEventMessage->FullItemName()).BString(),&pWiaItem);
if (SUCCEEDED(hr) && pWiaItem.p)
{
//
// Create an item wrapper
//
CCameraItem *pNewCameraItem = new CCameraItem( pWiaItem );
if (pNewCameraItem && pNewCameraItem->Item())
{
//
// Add it to the list
//
m_CameraItemList.Add( NULL, pNewCameraItem );
//
// Generate a thumbnail
//
CreateThumbnail( pNewCameraItem, hImageList, false );
//
// If this item is in the current folder, add it to the listview
//
if (m_pCurrentParentItem == pNewCameraItem->Parent())
{
int nListViewCount = ListView_GetItemCount(hwndListview);
//
// Add the item
//
LVITEM lvItem = {0};
lvItem.iItem = nListViewCount;
lvItem.mask = LVIF_IMAGE|LVIF_PARAM;
lvItem.iImage = pNewCameraItem->ImageListIndex();
lvItem.lParam = reinterpret_cast<LPARAM>(pNewCameraItem);
int nIndex = ListView_InsertItem( hwndListview, &lvItem );
//
// Make sure the new item is visible
//
if (nIndex >= 0)
{
ListView_EnsureVisible( hwndListview, nIndex, FALSE );
}
}
//
// Request a thumbnail from the background thread
//
m_pThreadMessageQueue->Enqueue( new CThumbnailThreadMessage( m_hWnd, pNewCameraItem->GlobalInterfaceTableCookie(), m_sizeThumbnails ) );
}
}
}
}
}
}
bool CCameraAcquireDialog::PopulateList( CCameraItem *pOldParent )
{
//
// Which item should be selected?
//
int nSelItem = 0;
//
// Get the list view control
//
HWND hwndList = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (hwndList)
{
//
// Empty the list
//
ListView_DeleteAllItems( hwndList );
//
// Where to insert the current item
//
int nCurrentItem = 0;
CCameraItem *pCurr;
//
// If this is a child directory...
//
if (m_pCurrentParentItem)
{
//
// Start adding children
//
pCurr = m_pCurrentParentItem->Children();
//
// Insert a dummy item that the user can use to switch to the parent directory
//
LVITEM lvItem;
ZeroMemory( &lvItem, sizeof(lvItem) );
lvItem.iItem = nCurrentItem++;
lvItem.mask = LVIF_IMAGE|LVIF_PARAM;
lvItem.iImage = m_nParentFolderImageListIndex;
lvItem.lParam = 0;
ListView_InsertItem( hwndList, &lvItem );
}
//
// Otherwise, we are at the root
//
else pCurr = m_CameraItemList.Root();
//
// Iterate through this list of images, and add each one
//
while (pCurr)
{
//
// If this is the last parent directory, we want it to be selected instead of the first image
//
if (pOldParent && *pCurr == *pOldParent)
{
nSelItem = nCurrentItem;
}
//
// If this image hasn't been deleted
//
if (pCurr->DeleteState() != CCameraItem::Delete_Deleted)
{
//
// Add the item
//
LVITEM lvItem = {0};
lvItem.iItem = nCurrentItem++;
lvItem.mask = LVIF_IMAGE|LVIF_PARAM;
lvItem.iImage = pCurr->ImageListIndex();
lvItem.lParam = reinterpret_cast<LPARAM>(pCurr);
int nIndex = ListView_InsertItem( hwndList, &lvItem );
if (nIndex >= 0 && pCurr->DeleteState() == CCameraItem::Delete_Pending)
{
MarkItemDeletePending(nIndex,true);
}
}
//
// Advance
//
pCurr = pCurr->Next();
}
}
//
// If we've not calculated the width of the list in preview mode, attempt to do it
//
if (!m_nListViewWidth)
{
RECT rcItem;
if (ListView_GetItemRect( GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ), 0, &rcItem, LVIR_ICON ))
{
m_nListViewWidth = (rcItem.right-rcItem.left) + rcItem.left * 2 + GetSystemMetrics(SM_CXHSCROLL) + c_nAdditionalMarginX;
}
}
//
// Set the selected item to either the previous directory, or the first image
//
SetSelectedListItem(nSelItem);
return(true);
}
void CCameraAcquireDialog::CreateThumbnail( CCameraItem *pCurr, HIMAGELIST hImageList, bool bForce )
{
//
// Make sure we have a valid item
//
if (pCurr && (pCurr->ImageListIndex()<0 || bForce))
{
//
// Get the item name
//
CSimpleStringWide strItemName;
PropStorageHelpers::GetProperty( pCurr->Item(), WIA_IPA_ITEM_NAME, strItemName );
//
// Create the title for the icon
//
CSimpleString strIconTitle;
if (pCurr->IsFolder())
{
strIconTitle = CSimpleStringConvert::NaturalString(strItemName);
}
else if (strItemName.Length())
{
strIconTitle.Format( IDS_DOWNLOADINGTHUMBNAIL, g_hInstance, CSimpleStringConvert::NaturalString(strItemName).String() );
}
//
// Create the thumbnail
//
HBITMAP hBmp = WiaUiUtil::CreateIconThumbnail( GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ), m_sizeThumbnails.cx, m_sizeThumbnails.cy, g_hInstance, pCurr->IsImage()?IDI_UNAVAILABLE:IDI_FOLDER, strIconTitle );
if (hBmp)
{
//
// If we don't have an image yet, add it
//
if (pCurr->ImageListIndex()<0)
{
pCurr->ImageListIndex(ImageList_Add( hImageList, hBmp, NULL ));
}
//
// Otherwise, replace it
//
else
{
pCurr->ImageListIndex(ImageList_Replace( hImageList, pCurr->ImageListIndex(), hBmp, NULL ));
}
//
// Delete it, since the imagelist makes a copy
//
DeleteObject(hBmp);
}
}
}
void CCameraAcquireDialog::CreateThumbnails( CCameraItem *pRoot, HIMAGELIST hImageList, bool bForce )
{
CCameraItem *pCurr = pRoot;
while (pCurr)
{
//
// Create the thumbnail
//
CreateThumbnail( pCurr, hImageList, bForce );
//
// If there are children, recurse into that list
//
CreateThumbnails( pCurr->Children(), hImageList, bForce );
//
// Advance
//
pCurr = pCurr->Next();
}
}
void CCameraAcquireDialog::RequestThumbnails( CCameraItem *pRoot )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::RequestThumbnails"));
CCameraItem *pCurr = pRoot;
while (pCurr)
{
if (pCurr->IsImage())
{
m_pThreadMessageQueue->Enqueue( new CThumbnailThreadMessage( m_hWnd, pCurr->GlobalInterfaceTableCookie(), m_sizeThumbnails ) );
}
if (pCurr->Children())
{
RequestThumbnails( pCurr->Children() );
}
pCurr = pCurr->Next();
}
}
void CCameraAcquireDialog::CreateThumbnails( bool bForce )
{
HWND hwndList = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (hwndList)
{
HIMAGELIST hImageList = ListView_GetImageList( hwndList, LVSIL_NORMAL );
if (hImageList)
{
//
// Create the parent folder image
//
HBITMAP hParentBitmap = WiaUiUtil::CreateIconThumbnail( hwndList, m_sizeThumbnails.cx, m_sizeThumbnails.cy, g_hInstance, IDI_PARENTFOLDER, TEXT("(..)") );
if (hParentBitmap)
{
m_nParentFolderImageListIndex = ImageList_Add( hImageList, hParentBitmap, NULL );
DeleteObject(hParentBitmap);
}
CCameraAcquireDialog::CreateThumbnails( m_CameraItemList.Root(), hImageList, bForce );
}
}
}
bool CCameraAcquireDialog::FindMaximumThumbnailSize(void)
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::FindMaximumThumbnailSize"));
bool bResult = false;
if (m_pDeviceDialogData && m_pDeviceDialogData->pIWiaItemRoot)
{
LONG nWidth, nHeight;
if (PropStorageHelpers::GetProperty( m_pDeviceDialogData->pIWiaItemRoot, WIA_DPC_THUMB_WIDTH, nWidth ) &&
PropStorageHelpers::GetProperty( m_pDeviceDialogData->pIWiaItemRoot, WIA_DPC_THUMB_WIDTH, nHeight ))
{
m_sizeThumbnails.cx = max(c_nMinThumbnailWidth,min(nWidth,c_nMaxThumbnailWidth));
m_sizeThumbnails.cy = max(c_nMinThumbnailHeight,min(nHeight,c_nMaxThumbnailHeight));
}
else WIA_TRACE((TEXT("FindMaximumThumbnailSize: Unable to retrieve thumbnail size for device")));
}
return(bResult && m_sizeThumbnails.cx && m_sizeThumbnails.cy);
}
//
// Hook procedure and static variables used to handle accelerators
//
LRESULT CALLBACK CCameraAcquireDialog::DialogHookProc( int nCode, WPARAM wParam, LPARAM lParam )
{
if (nCode < 0)
return CallNextHookEx( s_hMessageHook, nCode, wParam, lParam );
if (nCode == MSGF_DIALOGBOX)
{
MSG *pMsg = reinterpret_cast<MSG*>(lParam);
if (pMsg)
{
if (pMsg->hwnd == s_hWndDialog || (s_hWndDialog && IsChild(s_hWndDialog,pMsg->hwnd)))
{
CCameraAcquireDialog *pCameraAcquireDialog = reinterpret_cast<CCameraAcquireDialog*>(GetWindowLongPtr(s_hWndDialog,DWLP_USER));
if (pCameraAcquireDialog && pCameraAcquireDialog->m_hAccelTable)
{
if (TranslateAccelerator(s_hWndDialog,pCameraAcquireDialog->m_hAccelTable,pMsg))
return 1; // Ensure the window won't process the message
}
}
}
}
return CallNextHookEx( s_hMessageHook, nCode, wParam, lParam );
}
LRESULT CCameraAcquireDialog::OnInitDialog( WPARAM, LPARAM lParam )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::OnInitDialog"));
CWaitCursor wc;
//
// Make sure the background queue was successfully created
//
if (!m_pThreadMessageQueue)
{
WIA_ERROR((TEXT("CAMDLG: unable to start background queue")));
EndDialog( m_hWnd, E_OUTOFMEMORY );
return(0);
}
m_pDeviceDialogData = (PDEVICEDIALOGDATA)lParam;
// Save the window handle for the hook
s_hWndDialog = m_hWnd;
// Install the message hook, which we use for accelerator support
s_hMessageHook = SetWindowsHookEx( WH_MSGFILTER, DialogHookProc, g_hInstance, GetCurrentThreadId() );
if (!s_hMessageHook)
{
WIA_ERROR((TEXT("CAMDLG: Unable to set thread msg hook")));
EndDialog( m_hWnd, HRESULT_FROM_WIN32(GetLastError()));
return(0);
}
// Make sure we have valid arguments
if (!m_pDeviceDialogData)
{
WIA_ERROR((TEXT("CAMDLG: Invalid paramater: PDEVICEDIALOGDATA")));
EndDialog( m_hWnd, E_INVALIDARG );
return(0);
}
// Initialialize our return stuff
if (m_pDeviceDialogData)
{
m_pDeviceDialogData->lItemCount = 0;
m_pDeviceDialogData->ppWiaItems = NULL;
}
// Make sure we have valid a valid device
if (!m_pDeviceDialogData->pIWiaItemRoot)
{
WIA_ERROR((TEXT("CAMDLG: Invalid paramaters: pIWiaItem")));
EndDialog( m_hWnd, E_INVALIDARG );
return(0);
}
//
// Find out if Take Picture is supported
//
m_bTakePictureIsSupported = WiaUiUtil::IsDeviceCommandSupported( m_pDeviceDialogData->pIWiaItemRoot, WIA_CMD_TAKE_PICTURE );
// Prevent multiple selection
if (m_pDeviceDialogData->dwFlags & WIA_DEVICE_DIALOG_SINGLE_IMAGE)
{
LONG_PTR lStyle = GetWindowLongPtr( GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ), GWL_STYLE );
SetWindowLongPtr( GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ), GWL_STYLE, lStyle | LVS_SINGLESEL );
// Set the single sel titles
CSimpleString( IDS_TITLE_SINGLE_SEL, g_hInstance ).SetWindowText( GetDlgItem( m_hWnd, IDC_CAMDLG_BIG_TITLE ) );
CSimpleString( IDS_SUBTITLE_SINGLE_SEL, g_hInstance ).SetWindowText( GetDlgItem( m_hWnd, IDC_CAMDLG_SUBTITLE ) );
CSimpleString( IDS_OK_SINGLE_SEL, g_hInstance ).SetWindowText( GetDlgItem( m_hWnd, IDOK ) );
m_nDialogMode = SINGLESEL_MODE;
}
else
{
// Set the multi sel subtitle
CSimpleString( IDS_TITLE_MULTI_SEL, g_hInstance ).SetWindowText( GetDlgItem( m_hWnd, IDC_CAMDLG_BIG_TITLE ) );
CSimpleString( IDS_SUBTITLE_MULTI_SEL, g_hInstance ).SetWindowText( GetDlgItem( m_hWnd, IDC_CAMDLG_SUBTITLE ) );
CSimpleString( IDS_OK_MULTI_SEL, g_hInstance ).SetWindowText( GetDlgItem( m_hWnd, IDOK ) );
m_nDialogMode = MULTISEL_MODE;
}
// Make the lovely font
m_hBigFont = WiaUiUtil::CreateFontWithPointSizeFromWindow( GetDlgItem(m_hWnd,IDC_CAMDLG_BIG_TITLE), 14, false, false );
if (m_hBigFont)
SendDlgItemMessage( m_hWnd, IDC_CAMDLG_BIG_TITLE, WM_SETFONT, reinterpret_cast<WPARAM>(m_hBigFont), MAKELPARAM(TRUE,0));
// Create the Tool Bar and resize the dialog to accommodate it
(void)CreateCameraDialogToolbar();
// Get the minimum size of the dialog
RECT rcWindow;
GetWindowRect( m_hWnd, &rcWindow );
m_sizeMinimumWindow.cx = rcWindow.right - rcWindow.left;
m_sizeMinimumWindow.cy = rcWindow.bottom - rcWindow.top;
// Initialize the preview control
WiaPreviewControl_AllowNullSelection( GetDlgItem( m_hWnd, IDC_PREVIEW ), TRUE );
WiaPreviewControl_ClearSelection( GetDlgItem( m_hWnd, IDC_PREVIEW ) );
WiaPreviewControl_DisableSelection( GetDlgItem( m_hWnd, IDC_PREVIEW ), TRUE );
WiaPreviewControl_SetBorderSize( GetDlgItem( m_hWnd, IDC_PREVIEW ), FALSE, FALSE, 0 );
WiaPreviewControl_SetBgAlpha( GetDlgItem( m_hWnd, IDC_PREVIEW ), FALSE, 0xFF );
// Set the lovely title
CSimpleStringWide strwDeviceName;
if (PropStorageHelpers::GetProperty( m_pDeviceDialogData->pIWiaItemRoot, WIA_DIP_DEV_NAME, strwDeviceName ))
{
CSimpleString().Format( IDS_CAMERADLG_TITLE, g_hInstance, strwDeviceName.String() ).SetWindowText( m_hWnd );
}
// Create the sizing control
(void)CreateWindowEx( 0, TEXT("scrollbar"), TEXT(""),
WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP|WS_CLIPSIBLINGS|SBS_SIZEBOXBOTTOMRIGHTALIGN|SBS_BOTTOMALIGN|WS_GROUP,
CSimpleRect(m_hWnd).Width()-GetSystemMetrics(SM_CXVSCROLL),
CSimpleRect(m_hWnd).Height()-GetSystemMetrics(SM_CYHSCROLL),
GetSystemMetrics(SM_CXVSCROLL),
GetSystemMetrics(SM_CYHSCROLL),
m_hWnd, reinterpret_cast<HMENU>(IDC_SIZEBOX),
g_hInstance, NULL );
// Reposition all the controls
ResizeAll();
// Center the window over its parent
WiaUiUtil::CenterWindow( m_hWnd, GetParent(m_hWnd) );
// Get the device icons and set the window icons
CSimpleStringWide strwDeviceId, strwClassId;
LONG nDeviceType;
if (PropStorageHelpers::GetProperty(m_pDeviceDialogData->pIWiaItemRoot,WIA_DIP_UI_CLSID,strwClassId) &&
PropStorageHelpers::GetProperty(m_pDeviceDialogData->pIWiaItemRoot,WIA_DIP_DEV_ID,strwDeviceId) &&
PropStorageHelpers::GetProperty(m_pDeviceDialogData->pIWiaItemRoot,WIA_DIP_DEV_TYPE,nDeviceType))
{
//
// Register for disconnect event
//
CGenericWiaEventHandler::RegisterForWiaEvent( strwDeviceId.String(), WIA_EVENT_DEVICE_DISCONNECTED, &m_DisconnectEvent, m_hWnd, PWM_WIAEVENT );
CGenericWiaEventHandler::RegisterForWiaEvent( strwDeviceId.String(), WIA_EVENT_ITEM_DELETED, &m_DeleteItemEvent, m_hWnd, PWM_WIAEVENT );
CGenericWiaEventHandler::RegisterForWiaEvent( strwDeviceId.String(), WIA_EVENT_ITEM_CREATED, &m_CreateItemEvent, m_hWnd, PWM_WIAEVENT );
if (SUCCEEDED(WiaUiExtensionHelper::GetDeviceIcons( CSimpleBStr(strwClassId), nDeviceType, &m_hIconSmall, &m_hIconLarge )))
{
if (m_hIconSmall)
{
SendMessage( m_hWnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(m_hIconSmall) );
}
if (m_hIconLarge)
{
SendMessage( m_hWnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(m_hIconLarge) );
}
}
}
int nAcceleratorCount = 0;
ACCEL Accelerators[10];
//
// Load the accelerator table resource and convert it to an ACCEL array
//
HACCEL hAccel = LoadAccelerators( g_hInstance, MAKEINTRESOURCE(IDR_CAMERA_ACCEL) );
if (hAccel)
{
//
// Copy the accelerator table to an array of ACCEL
//
nAcceleratorCount = CopyAcceleratorTable( hAccel, Accelerators, ARRAYSIZE(Accelerators) );
//
// Free the accelerator table
//
DestroyAcceleratorTable( hAccel );
}
//
// Create the accelerator table for the toolbar
//
nAcceleratorCount += ToolbarHelper::GetButtonBarAccelerators( GetDlgItem( m_hWnd, IDC_TOOLBAR ), Accelerators+nAcceleratorCount, ARRAYSIZE(Accelerators)-nAcceleratorCount );
if (nAcceleratorCount)
{
m_hAccelTable = CreateAcceleratorTable( Accelerators, nAcceleratorCount );
if (!m_hAccelTable)
{
WIA_PRINTHRESULT((HRESULT_FROM_WIN32(GetLastError()),TEXT("CreateAcceleratorTable failed")));
}
}
SetForegroundWindow(m_hWnd);
//
// Make sure the listview has the focus
//
SetFocus( GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ) );
return (TRUE);
}
VOID CCameraAcquireDialog::ResizeAll(VOID)
{
CSimpleRect rcClient(m_hWnd);
CMoveWindow mw;
CDialogUnits dialogUnits(m_hWnd);
// Resize the big title
mw.Size( GetDlgItem( m_hWnd, IDC_CAMDLG_BIG_TITLE ),
rcClient.Width() - dialogUnits.StandardMargin().cx * 2,
0,
CMoveWindow::NO_SIZEY );
// Resize the subtitle
mw.Size( GetDlgItem( m_hWnd, IDC_CAMDLG_SUBTITLE ),
rcClient.Width() - dialogUnits.StandardMargin().cx * 2,
0,
CMoveWindow::NO_SIZEY );
int nToolBarHeight = (int)(HIWORD((DWORD)(SendMessage(GetDlgItem( m_hWnd, IDC_TOOLBAR ), TB_GETBUTTONSIZE, 0,0))));
// Resize the toolbar frame
mw.Size( GetDlgItem(m_hWnd,IDC_TOOLBAR_FRAME),
rcClient.Width() - dialogUnits.StandardMargin().cx * 2,
nToolBarHeight + 4,
0 );
// Get the dialog's client coordinates of the toolbar frame's client rect
CSimpleRect rcToolbarFrameInside( GetDlgItem(m_hWnd,IDC_TOOLBAR_FRAME), CSimpleRect::ClientRect );
rcToolbarFrameInside = rcToolbarFrameInside.ClientToScreen(GetDlgItem(m_hWnd,IDC_TOOLBAR_FRAME));
rcToolbarFrameInside = rcToolbarFrameInside.ScreenToClient(m_hWnd);
// Move and resize the toolbar
mw.SizeMove( GetDlgItem( m_hWnd, IDC_TOOLBAR ),
rcToolbarFrameInside.left + 2,
rcToolbarFrameInside.top + 2,
rcClient.Width() - dialogUnits.StandardMargin().cx * 2 - 4,
nToolBarHeight,
0 );
// Save the bottom of this control for later
int nBottomOfToolbarFrame = CSimpleRect( GetDlgItem(m_hWnd,IDC_TOOLBAR_FRAME), CSimpleRect::WindowRect ).ScreenToClient(m_hWnd).top + nToolBarHeight + 4;
// Move the Properties control
mw.SizeMove( GetDlgItem( m_hWnd, IDC_CAMDLG_PROPERTIES ),
0,
rcClient.Height() - dialogUnits.StandardMargin().cy - dialogUnits.Y(8) + 2,
dialogUnits.StandardMargin().cx,
dialogUnits.Y(8) + 2,
CMoveWindow::NO_MOVEX|CMoveWindow::NO_SIZEX );
// Move the static text above it
mw.Move( GetDlgItem( m_hWnd, IDC_YOU_CAN_ALSO ),
dialogUnits.StandardMargin().cx,
rcClient.Height() - dialogUnits.StandardMargin().cy - dialogUnits.Y(8) - 2 - dialogUnits.Y(8)
);
CSimpleRect rcOK( GetDlgItem( m_hWnd, IDOK ), CSimpleRect::WindowRect );
CSimpleRect rcCancel( GetDlgItem( m_hWnd, IDOK ), CSimpleRect::WindowRect );
// Move the OK button
mw.Move( GetDlgItem( m_hWnd, IDOK ),
rcClient.Width() - dialogUnits.StandardMargin().cx - dialogUnits.StandardButtonMargin().cx - rcCancel.Width() - rcOK.Width(),
rcClient.Height() - dialogUnits.StandardMargin().cy - rcOK.Height(),
0 );
// Move the cancel button
mw.Move( GetDlgItem( m_hWnd, IDCANCEL ),
rcClient.Width() - dialogUnits.StandardMargin().cx - rcCancel.Width(),
rcClient.Height() - dialogUnits.StandardMargin().cy - rcCancel.Height(),
0 );
// Move the resizing handle
mw.Move( GetDlgItem( m_hWnd, IDC_SIZEBOX ),
rcClient.Width() - GetSystemMetrics(SM_CXVSCROLL),
rcClient.Height() - GetSystemMetrics(SM_CYHSCROLL)
);
int nHeightOfBottomControls =
dialogUnits.Y(8) + 2 + // Highlight control
dialogUnits.Y(8) + // Static description text
dialogUnits.StandardMargin().cy; // Top of these controls
CSimpleRect rcAvailableArea(
dialogUnits.StandardMargin().cx,
nBottomOfToolbarFrame + dialogUnits.StandardMargin().cy,
rcClient.right - dialogUnits.StandardMargin().cx,
rcClient.bottom - nHeightOfBottomControls - dialogUnits.StandardMargin().cy
);
if (m_bPreviewActive)
{
// If we've already calculated the actual width of the preview mode list, use it, otherwise use the default
int nListViewWidth = m_nListViewWidth ? m_nListViewWidth : c_nDefaultListViewWidth;
// Move the thumbnail list
mw.SizeMove( GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ),
rcAvailableArea.left,
rcAvailableArea.top,
nListViewWidth,
rcAvailableArea.Height()
);
// Remove the rect of the list view from the preview area
rcAvailableArea.left += nListViewWidth + dialogUnits.StandardMargin().cx;
// Use up the remaining area
mw.SizeMove( GetDlgItem( m_hWnd, IDC_PREVIEW ),
rcAvailableArea.left,
rcAvailableArea.top,
rcAvailableArea.Width(),
rcAvailableArea.Height() );
}
else
{
// Move the thumbnail list
mw.SizeMove( GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ),
rcAvailableArea.left,
rcAvailableArea.top,
rcAvailableArea.Width(),
rcAvailableArea.Height()
);
}
// Explicitly apply the moves, because the toolbar frame doesn't get painted properly
mw.Apply();
if (m_bPreviewActive)
{
// Show the preview in case it isn't visible
mw.Show( GetDlgItem( m_hWnd, IDC_PREVIEW ) );
}
else
{
// Hide the preview in case it is visible
mw.Hide( GetDlgItem( m_hWnd, IDC_PREVIEW ) );
}
//
// Update the dialog's background to remove any weird stuff left behind
//
InvalidateRect( m_hWnd, NULL, FALSE );
UpdateWindow( m_hWnd );
}
LRESULT CCameraAcquireDialog::OnItemDeleted( WPARAM wParam, LPARAM lParam )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::OnItemDeleted"));
CCameraItem *pDeletedItem = m_CameraItemList.Find((DWORD)wParam);
if (pDeletedItem)
{
BOOL bSuccess = (BOOL)lParam;
pDeletedItem->DeleteState( bSuccess ? CCameraItem::Delete_Deleted : CCameraItem::Delete_Visible );
if (pDeletedItem == m_pCurrentParentItem)
{
ChangeFolder(m_pCurrentParentItem->Parent());
}
int nIndex = FindItemInList(pDeletedItem);
if (nIndex >= 0)
{
if (bSuccess)
{
// Remove the item from the list
ListView_DeleteItem(GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ),nIndex);
// Make sure we leave something selected
if (!ListView_GetSelectedCount(GetDlgItem( m_hWnd, IDC_THUMBNAILLIST )))
{
int nItemCount = ListView_GetItemCount(GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ));
if (nItemCount)
{
if (nIndex >= nItemCount)
nIndex = nItemCount-1;
SetSelectedListItem(nIndex);
}
}
else
{
// Make sure we update control's state when the list is empty
HandleSelectionChange();
}
}
else
{
// If the delete failed, remove the deleted state
MarkItemDeletePending(nIndex,false);
// Tell the user
MessageBeep( MB_ICONASTERISK );
}
}
}
return (0);
}
LRESULT CCameraAcquireDialog::OnWiaEvent( WPARAM, LPARAM lParam )
{
WIA_PUSHFUNCTION(TEXT("CCameraAcquireDialog::OnWiaEvent"));
CGenericWiaEventHandler::CEventMessage *pEventMessage = reinterpret_cast<CGenericWiaEventHandler::CEventMessage *>(lParam);
if (pEventMessage)
{
if (pEventMessage->EventId() == WIA_EVENT_DEVICE_DISCONNECTED)
{
WIA_TRACE((TEXT("Received disconnect event")));
EndDialog( m_hWnd, WIA_ERROR_OFFLINE );
}
else if (pEventMessage->EventId() == WIA_EVENT_ITEM_CREATED)
{
OnItemCreatedEvent( pEventMessage );
}
else if (pEventMessage->EventId() == WIA_EVENT_ITEM_DELETED)
{
WIA_TRACE((TEXT("Received deleted item event")));
CCameraItem *pDeletedItem = m_CameraItemList.Find(CSimpleBStr(pEventMessage->FullItemName()));
if (pDeletedItem)
{
//
// If we're deleting the current parent item,
// select a new one.
//
if (pDeletedItem == m_pCurrentParentItem)
{
ChangeFolder(m_pCurrentParentItem->Parent());
}
int nIndex = FindItemInList(pDeletedItem);
if (nIndex >= 0)
{
//
// Remove the item from the listview
//
ListView_DeleteItem(GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ),nIndex);
//
// Make sure we leave something selected
//
if (!ListView_GetSelectedCount(GetDlgItem( m_hWnd, IDC_THUMBNAILLIST )))
{
int nItemCount = ListView_GetItemCount(GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ));
if (nItemCount)
{
if (nIndex >= nItemCount)
{
nIndex = nItemCount-1;
}
SetSelectedListItem(nIndex);
}
}
else
{
//
// Make sure we update control's state when the list is empty
//
HandleSelectionChange();
}
}
else
{
WIA_ERROR((TEXT("FindItemInList coulnd't find the item")));
}
//
// Mark the item as deleted.
//
pDeletedItem->DeleteState( CCameraItem::Delete_Deleted );
}
else
{
WIA_ERROR((TEXT("The item could not be found in m_CameraItemList")));
}
}
delete pEventMessage;
}
return HANDLED_EVENT_MESSAGE;
}
LRESULT CCameraAcquireDialog::OnEnterSizeMove( WPARAM, LPARAM )
{
SendDlgItemMessage( m_hWnd, IDC_PREVIEW, WM_ENTERSIZEMOVE, 0, 0 );
return(0);
}
LRESULT CCameraAcquireDialog::OnExitSizeMove( WPARAM, LPARAM )
{
SendDlgItemMessage( m_hWnd, IDC_PREVIEW, WM_EXITSIZEMOVE, 0, 0 );
return(0);
}
LRESULT CCameraAcquireDialog::OnSize( WPARAM, LPARAM )
{
ResizeAll();
return(0);
}
LRESULT CCameraAcquireDialog::OnShow( WPARAM, LPARAM )
{
if (m_bFirstTime)
{
PostMessage( m_hWnd, PWM_POSTINIT, 0, 0 );
m_bFirstTime = false;
}
return(0);
}
LRESULT CCameraAcquireDialog::OnGetMinMaxInfo( WPARAM, LPARAM lParam )
{
LPMINMAXINFO pMinMaxInfo = (LPMINMAXINFO)lParam;
pMinMaxInfo->ptMinTrackSize.x = m_sizeMinimumWindow.cx;
pMinMaxInfo->ptMinTrackSize.y = m_sizeMinimumWindow.cy;
return(0);
}
LRESULT CCameraAcquireDialog::OnDestroy( WPARAM, LPARAM )
{
//
// Get rid of all preview requests
//
CancelAllPreviewRequests( m_CameraItemList.Root() );
//
// Tell the background thread to destroy itself
//
m_pThreadMessageQueue->Enqueue( new CThreadMessage(TQ_DESTROY),CThreadMessageQueue::PriorityUrgent);
//
// Set the window icon to NULL
//
SendMessage( m_hWnd, WM_SETICON, ICON_BIG, 0 );
SendMessage( m_hWnd, WM_SETICON, ICON_SMALL, 0 );
//
// Clear the image list and list view. This should be unnecessary, but BoundsChecker
// complains if I don't do it.
//
HWND hwndList = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (hwndList)
{
ListView_DeleteAllItems(hwndList);
HIMAGELIST hImgList = ListView_SetImageList( hwndList, NULL, LVSIL_NORMAL );
if (hImgList)
{
ImageList_Destroy(hImgList);
}
}
//
// Delete resources
//
if (m_hBigFont)
{
DeleteObject(m_hBigFont);
m_hBigFont = NULL;
}
if (m_hImageList)
{
m_hImageList = NULL;
}
if (m_hAccelTable)
{
DestroyAcceleratorTable(m_hAccelTable);
m_hAccelTable = NULL;
}
if (s_hMessageHook)
{
UnhookWindowsHookEx(s_hMessageHook);
s_hMessageHook = NULL;
}
if (m_hIconLarge)
{
DestroyIcon(m_hIconLarge);
m_hIconLarge = NULL;
}
if (m_hIconSmall)
{
DestroyIcon(m_hIconSmall);
m_hIconSmall = NULL;
}
if (m_hBackgroundThread)
{
CloseHandle(m_hBackgroundThread);
m_hBackgroundThread = NULL;
}
return(0);
}
VOID CCameraAcquireDialog::OnPreviewMode( WPARAM, LPARAM )
{
m_bPreviewActive = true;
SendDlgItemMessage( m_hWnd, IDC_TOOLBAR, TB_SETSTATE, IDC_PREVIEWMODE, MAKELONG(TBSTATE_ENABLED|TBSTATE_CHECKED,0) );
SendDlgItemMessage( m_hWnd, IDC_TOOLBAR, TB_SETSTATE, IDC_ICONMODE, MAKELONG(TBSTATE_ENABLED,0) );
ResizeAll();
UpdatePreview();
}
VOID CCameraAcquireDialog::OnTakePicture( WPARAM, LPARAM )
{
//
// Tell the device to snap a picture
//
if (m_pDeviceDialogData->pIWiaItemRoot && m_bTakePictureIsSupported)
{
CWaitCursor wc;
CComPtr<IWiaItem> pNewWiaItem;
m_pDeviceDialogData->pIWiaItemRoot->DeviceCommand(0,&WIA_CMD_TAKE_PICTURE,&pNewWiaItem);
}
}
VOID CCameraAcquireDialog::OnIconMode( WPARAM, LPARAM )
{
m_bPreviewActive = false;
SendDlgItemMessage( m_hWnd, IDC_TOOLBAR, TB_SETSTATE, IDC_ICONMODE, MAKELONG(TBSTATE_ENABLED|TBSTATE_CHECKED,0) );
SendDlgItemMessage( m_hWnd, IDC_TOOLBAR, TB_SETSTATE, IDC_PREVIEWMODE, MAKELONG(TBSTATE_ENABLED,0) );
ResizeAll();
UpdatePreview();
}
LRESULT CCameraAcquireDialog::OnPostInit( WPARAM, LPARAM )
{
//
// Create the progress dialog
//
CComPtr<IWiaProgressDialog> pWiaProgressDialog;
HRESULT hr = CoCreateInstance( CLSID_WiaDefaultUi, NULL, CLSCTX_INPROC_SERVER, IID_IWiaProgressDialog, (void**)&pWiaProgressDialog );
if (SUCCEEDED(hr))
{
//
// Initialize the progress dialog
//
pWiaProgressDialog->Create( m_hWnd, WIA_PROGRESSDLG_ANIM_CAMERA_COMMUNICATE|WIA_PROGRESSDLG_NO_PROGRESS|WIA_PROGRESSDLG_NO_CANCEL|WIA_PROGRESSDLG_NO_TITLE );
pWiaProgressDialog->SetTitle( CSimpleStringConvert::WideString(CSimpleString(IDS_CAMDLG_PROGDLG_TITLE,g_hInstance)));
pWiaProgressDialog->SetMessage( CSimpleStringConvert::WideString(CSimpleString(IDS_CAMDLG_PROGDLG_MESSAGE,g_hInstance)));
//
// Show the progress dialog
//
pWiaProgressDialog->Show();
//
// Find all of the images in the camera
//
EnumerateAllCameraItems();
//
// Find the largest possible thumbnail
//
FindMaximumThumbnailSize();
//
// Initialize Thumbnail Listview control
//
HWND hwndList = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (hwndList)
{
//
// Get rid of the border and icon labels
//
ListView_SetExtendedListViewStyleEx( hwndList, LVS_EX_BORDERSELECT|LVS_EX_HIDELABELS|LVS_EX_DOUBLEBUFFER, LVS_EX_BORDERSELECT|LVS_EX_HIDELABELS|LVS_EX_DOUBLEBUFFER );
//
// Create the large image list
//
m_hImageList = ImageList_Create( m_sizeThumbnails.cx, m_sizeThumbnails.cy, ILC_COLOR24|ILC_MIRROR, 50, 50 );
if (m_hImageList)
{
//
// Set the image list
//
ListView_SetImageList( hwndList, m_hImageList, LVSIL_NORMAL );
}
//
// Set the icon spacing
//
ListView_SetIconSpacing( hwndList, m_sizeThumbnails.cx + c_nAdditionalMarginX, m_sizeThumbnails.cy + c_nAdditionalMarginY );
}
//
// Create all of the initial thumbnails
//
CreateThumbnails();
//
// This causes the list to be populated
//
ChangeFolder(NULL);
//
// Force a selection change
//
HandleSelectionChange();
//
// Download all of the thumbnails
//
RequestThumbnails( m_CameraItemList.Root() );
//
// Close the progress dialog
//
pWiaProgressDialog->Destroy();
}
return(0);
}
LRESULT CCameraAcquireDialog::OnChangeToParent( WPARAM, LPARAM )
{
if (m_pCurrentParentItem)
ChangeFolder(m_pCurrentParentItem->Parent());
return(0);
}
VOID CCameraAcquireDialog::OnParentDir( WPARAM, LPARAM )
{
if (m_pCurrentParentItem && m_pCurrentParentItem->Parent())
ChangeFolder(m_pCurrentParentItem->Parent());
else ChangeFolder(NULL);
}
void CCameraAcquireDialog::MarkItemDeletePending( int nIndex, bool bSet )
{
HWND hwndList = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (hwndList)
{
ListView_SetItemState( hwndList, nIndex, bSet ? LVIS_CUT : 0, LVIS_CUT );
}
}
// Recursively delete items
void CCameraAcquireDialog::DeleteItem( CCameraItem *pItemNode )
{
if (pItemNode)
{
CCameraItem *pChild = pItemNode->Children();
while (pChild)
{
DeleteItem(pChild);
pChild = pChild->Next();
}
if (pItemNode->DeleteState() == CCameraItem::Delete_Visible)
{
int nIndex = FindItemInList( pItemNode );
if (nIndex >= 0)
{
//
// Mark it pending in the UI
//
MarkItemDeletePending(nIndex,true);
}
//
// Mark it pending
//
pItemNode->DeleteState( CCameraItem::Delete_Pending );
//
// Fire off the request
//
m_pThreadMessageQueue->Enqueue( new CDeleteThreadMessage(m_hWnd, pItemNode->GlobalInterfaceTableCookie()), CThreadMessageQueue::PriorityHigh );
}
}
}
VOID CCameraAcquireDialog::OnDelete( WPARAM, LPARAM )
{
CSimpleDynamicArray<int> aSelIndices;
if (GetSelectionIndices( aSelIndices ))
{
//
// We only want to show the confirm dialog once
//
bool bShowConfirmDialog = true;
for (int i=0;i<aSelIndices.Size();i++)
{
CCameraItem *pItemNode = GetListItemNode(aSelIndices[i]);
//
// If we haven't already deleted this image, do so
//
if (pItemNode && pItemNode->DeleteState() == CCameraItem::Delete_Visible && pItemNode->ItemRights() & WIA_ITEM_CAN_BE_DELETED)
{
if (bShowConfirmDialog)
{
bShowConfirmDialog = false;
if (IDYES!=MessageBox( m_hWnd, CSimpleString( IDS_DELETE_CONFIRM, g_hInstance ), CSimpleString( IDS_DELETE_CONFIRM_TITLE, g_hInstance ), MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 ))
{
break;
}
}
DeleteItem( pItemNode );
}
}
}
}
int CCameraAcquireDialog::GetSelectionIndices( CSimpleDynamicArray<int> &aIndices )
{
HWND hwndList = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (!hwndList)
return(0);
int iCount = ListView_GetItemCount(hwndList);
for (int i=0;i<iCount;i++)
if (ListView_GetItemState(hwndList,i,LVIS_SELECTED) & LVIS_SELECTED)
aIndices.Append(i);
return(aIndices.Size());
}
bool CCameraAcquireDialog::SetSelectedListItem( int nIndex )
{
HWND hwndList = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (!hwndList)
return(false);
int iCount = ListView_GetItemCount(hwndList);
for (int i=0;i<iCount;i++)
ListView_SetItemState(hwndList,i,LVIS_SELECTED|LVIS_FOCUSED,0);
ListView_SetItemState(hwndList,nIndex,LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);
ListView_EnsureVisible(hwndList,nIndex,FALSE);
return(true);
}
CCameraItem *CCameraAcquireDialog::GetListItemNode( int nIndex )
{
HWND hwndList = GetDlgItem( m_hWnd, IDC_THUMBNAILLIST );
if (!hwndList)
return(NULL);
LV_ITEM lvItem;
::ZeroMemory(&lvItem,sizeof(LV_ITEM));
lvItem.mask = LVIF_PARAM;
lvItem.iItem = nIndex;
if (!ListView_GetItem( hwndList, &lvItem ))
return(NULL);
return((CCameraItem *)lvItem.lParam);
}
bool CCameraAcquireDialog::ChangeFolder( CCameraItem *pNode )
{
CCameraItem *pOldParent = m_pCurrentParentItem;
m_pCurrentParentItem = pNode;
return(PopulateList(pOldParent));
}
bool CCameraAcquireDialog::ChangeToSelectedFolder(void)
{
CSimpleDynamicArray<int> aSelIndices;
if (GetSelectionIndices(aSelIndices))
{
//
// Find out if only folders are selected
//
bool bOnlyFoldersSelected = true;
for (int i=0;i<aSelIndices.Size();i++)
{
CCameraItem *pItemNode = GetListItemNode(aSelIndices[i]);
if (pItemNode && !pItemNode->IsFolder())
{
bOnlyFoldersSelected = false;
break;
}
}
WIA_TRACE((TEXT("bOnlyFoldersSelected = %d"),bOnlyFoldersSelected));
//
// If only folders are selected, switch to the first selected folder
//
if (bOnlyFoldersSelected && aSelIndices.Size())
{
CCameraItem *pItemNode = GetListItemNode(aSelIndices[0]);
if (!pItemNode)
{
//
// NULL item node == parent folder
//
SendMessage( m_hWnd, PWM_CHANGETOPARENT, 0, 0 );
return(true);
}
if (pItemNode && pItemNode->IsFolder() && pItemNode->DeleteState() == CCameraItem::Delete_Visible)
{
if (ChangeFolder(pItemNode))
{
return(true);
}
}
}
}
return(false);
}
VOID CCameraAcquireDialog::OnOK( WPARAM, LPARAM )
{
if (!ChangeToSelectedFolder())
{
HRESULT hr = S_OK;
m_pDeviceDialogData->lItemCount = 0;
m_pDeviceDialogData->ppWiaItems = NULL;
CSimpleDynamicArray<int> aIndices;
GetSelectionIndices( aIndices );
if (aIndices.Size())
{
int nArraySizeInBytes = sizeof(IWiaItem*) * aIndices.Size();
m_pDeviceDialogData->ppWiaItems = (IWiaItem**)CoTaskMemAlloc(nArraySizeInBytes);
if (m_pDeviceDialogData->ppWiaItems)
{
ZeroMemory( m_pDeviceDialogData->ppWiaItems, nArraySizeInBytes );
int nCurrItem = 0;
for (int i=0;i<aIndices.Size();i++)
{
CCameraItem *pItem = GetListItemNode(aIndices[i]);
//
// Add the item to the list if it is both a valid picture item and it hasn't been deleted
//
if (pItem && pItem->Item() && pItem->IsImage() && pItem->DeleteState() == CCameraItem::Delete_Visible)
{
m_pDeviceDialogData->ppWiaItems[nCurrItem] = pItem->Item();
m_pDeviceDialogData->ppWiaItems[nCurrItem]->AddRef();
nCurrItem++;
}
}
m_pDeviceDialogData->lItemCount = nCurrItem;
}
else
{
// Unable to alloc mem
hr = E_OUTOFMEMORY;
}
}
else
{
return;
}
EndDialog( m_hWnd, hr );
}
}
VOID CCameraAcquireDialog::OnCancel( WPARAM, LPARAM )
{
EndDialog( m_hWnd, S_FALSE );
}
VOID CCameraAcquireDialog::OnSelectAll( WPARAM, LPARAM )
{
ListView_SetItemState( GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ), -1, LVIS_SELECTED, LVIS_SELECTED );
}
VOID CCameraAcquireDialog::OnProperties( WPARAM, LPARAM )
{
CSimpleDynamicArray<int> aSelIndices;
if (GetSelectionIndices( aSelIndices ))
{
if (aSelIndices.Size() == 1)
{
CCameraItem *pItemNode = GetListItemNode(aSelIndices[0]);
if (pItemNode && pItemNode->Item())
{
m_pThreadMessageQueue->Pause();
HRESULT hr = WiaUiUtil::SystemPropertySheet( g_hInstance, m_hWnd, pItemNode->Item(), CSimpleString( IDS_CAMDLG_PROPERTIES_TITLE, g_hInstance ) );
if (!SUCCEEDED(hr))
{
if (PROP_SHEET_ERROR_NO_PAGES == hr)
{
MessageBox( m_hWnd, CSimpleString( IDS_CAMDLG_PROPSHEETNOPAGES, g_hInstance ), CSimpleString( IDS_CAMDLG_ERROR_TITLE, g_hInstance ), MB_ICONINFORMATION );
}
else
{
MessageBox( m_hWnd, CSimpleString( IDS_CAMDLG_PROPSHEETERROR, g_hInstance ), CSimpleString( IDS_CAMDLG_ERROR_TITLE, g_hInstance ), MB_ICONINFORMATION );
}
WIA_PRINTHRESULT((hr,TEXT("SystemPropertySheet failed")));
}
m_pThreadMessageQueue->Resume();
}
}
}
}
LRESULT CCameraAcquireDialog::OnDblClkImageList( WPARAM, LPARAM )
{
SendMessage( m_hWnd, WM_COMMAND, MAKEWPARAM(IDOK,0), 0 );
return(0);
}
void CCameraAcquireDialog::CancelAllPreviewRequests( CCameraItem *pRoot )
{
CCameraItem *pCurr = pRoot;
while (pCurr)
{
if (pCurr->PreviewRequestPending())
pCurr->SetCancelEvent();
if (pCurr->Children())
CancelAllPreviewRequests( pCurr->Children() );
pCurr = pCurr->Next();
}
}
void CCameraAcquireDialog::UpdatePreview(void)
{
if (m_bPreviewActive)
{
CCameraItem *pCurrPreviewItem = GetCurrentPreviewItem();
if (pCurrPreviewItem && pCurrPreviewItem->IsImage())
{
// If we're not already downloading this preview image...
if (!pCurrPreviewItem->PreviewRequestPending())
{
// Cancel all other preview requests
CancelAllPreviewRequests( m_CameraItemList.Root() );
if (pCurrPreviewItem->PreviewFileName().Length())
{
// Set the preview if we've got it cached
SetCurrentPreviewImage( pCurrPreviewItem->PreviewFileName() );
}
else
{
CSimpleString strPct;
strPct.Format( IDS_DOWNLOADINGPREVIEW, g_hInstance, 0 );
// Clear the preview window
SetCurrentPreviewImage( TEXT(""), strPct );
// Create our cancel event
pCurrPreviewItem->CreateCancelEvent();
// Reset it, just in case
pCurrPreviewItem->ResetCancelEvent();
// Make the request
m_pThreadMessageQueue->Enqueue( new CPreviewThreadMessage( m_hWnd, pCurrPreviewItem->GlobalInterfaceTableCookie(), pCurrPreviewItem->CancelQueueEvent().Event() ), CThreadMessageQueue::PriorityHigh );
}
}
else
{
CSimpleString strPct;
strPct.Format( IDS_DOWNLOADINGPREVIEW, g_hInstance, pCurrPreviewItem->CurrentPreviewPercentage() );
SetCurrentPreviewImage( TEXT(""), strPct );
}
}
else
{
SetCurrentPreviewImage( TEXT("") );
CancelAllPreviewRequests( m_CameraItemList.Root() );
}
}
else
{
CancelAllPreviewRequests( m_CameraItemList.Root() );
SetCurrentPreviewImage( TEXT("") );
}
}
LRESULT CCameraAcquireDialog::OnTimer( WPARAM wParam, LPARAM )
{
switch (wParam)
{
case IDT_UPDATEPREVIEW:
{
KillTimer( m_hWnd, IDT_UPDATEPREVIEW );
UpdatePreview();
}
break;
}
return(0);
}
// Avoids unnecessary state changes
static inline void MyEnableWindow( HWND hWnd, BOOL bEnable )
{
if (bEnable && !IsWindowEnabled(hWnd))
EnableWindow(hWnd,TRUE);
else if (!bEnable && IsWindowEnabled(hWnd))
EnableWindow(hWnd,FALSE);
}
// Avoids unnecessary state changes
static inline void MyEnableToolbarButton( HWND hWnd, int nId, BOOL bEnable )
{
LRESULT nState = SendMessage( hWnd, TB_GETSTATE, nId, 0 );
if (nState < 0)
return;
if ((nState & TBSTATE_ENABLED) && !bEnable)
SendMessage( hWnd, TB_ENABLEBUTTON, nId, nState & ~TBSTATE_ENABLED);
else if (!(nState & TBSTATE_ENABLED) && bEnable)
SendMessage( hWnd, TB_ENABLEBUTTON, nId, nState | TBSTATE_ENABLED );
}
void CCameraAcquireDialog::HandleSelectionChange(void)
{
CWaitCursor wc;
int nSelCount = ListView_GetSelectedCount(GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ) );
int nItemCount = ListView_GetItemCount(GetDlgItem( m_hWnd, IDC_THUMBNAILLIST ) );
//
// Properties should be disabled for multiple items
// and parent folder icons
//
bool bDisableProperties = true;
if (nSelCount == 1)
{
CSimpleDynamicArray<int> aIndices;
if (CCameraAcquireDialog::GetSelectionIndices( aIndices ))
{
if (CCameraAcquireDialog::GetListItemNode( aIndices[0] ))
{
bDisableProperties = false;
}
}
}
MyEnableWindow( GetDlgItem(m_hWnd,IDC_CAMDLG_PROPERTIES), !bDisableProperties );
// OK should be disabled for 0 items
MyEnableWindow( GetDlgItem(m_hWnd,IDOK), nSelCount != 0 );
// Select all should be disabled for 0 items
MyEnableToolbarButton( GetDlgItem(m_hWnd,IDC_TOOLBAR), IDC_SELECTALL, nItemCount != 0 );
//
// Decide whether or not delete should be enabled
// If any of the selected items are deletable, then delete is enabled
//
bool bEnableDelete = false;
//
// Get the selected items
//
CSimpleDynamicArray<int> aSelIndices;
if (GetSelectionIndices( aSelIndices ))
{
//
// Loop through all of the selected items. Break out if we find a reason
// to enable delete.
//
for (int i=0;i<aSelIndices.Size() && !bEnableDelete;i++)
{
//
// Get the item
//
CCameraItem *pItemNode = GetListItemNode(aSelIndices[i]);
//
// If we don't have an item, it is a parent folder
//
if (pItemNode)
{
//
// If the access rights include the right to delete items,
// break out.
//
if (pItemNode->ItemRights() & WIA_ITEM_CAN_BE_DELETED)
{
//
// Found one, so we are done.
//
bEnableDelete = true;
break;
}
}
}
}
MyEnableToolbarButton( GetDlgItem(m_hWnd,IDC_TOOLBAR), IDC_DELETE, bEnableDelete );
KillTimer( m_hWnd, IDT_UPDATEPREVIEW );
SetTimer( m_hWnd, IDT_UPDATEPREVIEW, UPDATE_PREVIEW_DELAY, NULL );
}
LRESULT CCameraAcquireDialog::OnImageListItemChanged( WPARAM, LPARAM )
{
HandleSelectionChange();
return(0);
}
LRESULT CCameraAcquireDialog::OnImageListKeyDown( WPARAM, LPARAM lParam )
{
LPNMLVKEYDOWN pnkd = reinterpret_cast<LPNMLVKEYDOWN>(lParam);
if (pnkd)
{
bool bAlt = ((GetKeyState(VK_MENU) & 0x8000) != 0);
bool bControl = ((GetKeyState(VK_CONTROL) & 0x8000) != 0);
bool bShift = ((GetKeyState(VK_SHIFT) & 0x8000) != 0);
if (VK_LEFT == pnkd->wVKey && bAlt && !bControl && !bShift)
{
SendMessage( m_hWnd, PWM_CHANGETOPARENT, 0, 0 );
}
else if (VK_BACK == pnkd->wVKey && !bAlt && !bControl && !bShift)
{
SendMessage( m_hWnd, PWM_CHANGETOPARENT, 0, 0 );
}
else if (VK_DELETE == pnkd->wVKey)
{
SendMessage( m_hWnd, WM_COMMAND, IDC_DELETE, 0 );
}
}
return (0);
}
LRESULT CCameraAcquireDialog::OnHelp( WPARAM wParam, LPARAM lParam )
{
return WiaHelp::HandleWmHelp( wParam, lParam, g_HelpIDs );
}
LRESULT CCameraAcquireDialog::OnContextMenu( WPARAM wParam, LPARAM lParam )
{
return WiaHelp::HandleWmContextMenu( wParam, lParam, g_HelpIDs );
}
LRESULT CCameraAcquireDialog::OnSysColorChange( WPARAM wParam, LPARAM lParam )
{
WiaPreviewControl_SetBkColor( GetDlgItem( m_hWnd, IDC_PREVIEW ), TRUE, TRUE, GetSysColor(COLOR_WINDOW) );
WiaPreviewControl_SetBkColor( GetDlgItem( m_hWnd, IDC_PREVIEW ), TRUE, FALSE, GetSysColor(COLOR_WINDOW) );
SendDlgItemMessage( m_hWnd, IDC_THUMBNAILLIST, WM_SYSCOLORCHANGE, wParam, lParam );
SendDlgItemMessage( m_hWnd, IDC_TOOLBAR, WM_SYSCOLORCHANGE, wParam, lParam );
SendDlgItemMessage( m_hWnd, IDC_CAMDLG_PROPERTIES, WM_SYSCOLORCHANGE, wParam, lParam );
m_ToolbarBitmapInfo.ReloadAndReplaceBitmap();
return 0;
}
LRESULT CCameraAcquireDialog::OnNotify( WPARAM wParam, LPARAM lParam )
{
SC_BEGIN_NOTIFY_MESSAGE_HANDLERS()
{
SC_HANDLE_NOTIFY_MESSAGE_CONTROL( NM_DBLCLK, IDC_THUMBNAILLIST, OnDblClkImageList );
SC_HANDLE_NOTIFY_MESSAGE_CONTROL( LVN_ITEMCHANGED, IDC_THUMBNAILLIST, OnImageListItemChanged );
SC_HANDLE_NOTIFY_MESSAGE_CONTROL( LVN_KEYDOWN, IDC_THUMBNAILLIST, OnImageListKeyDown );
}
SC_END_NOTIFY_MESSAGE_HANDLERS();
}
// WM_COMMAND Handler
LRESULT CCameraAcquireDialog::OnCommand( WPARAM wParam, LPARAM lParam )
{
SC_BEGIN_COMMAND_HANDLERS()
{
SC_HANDLE_COMMAND(IDOK,OnOK);
SC_HANDLE_COMMAND(IDCANCEL,OnCancel);
SC_HANDLE_COMMAND(IDC_CAMDLG_PROPERTIES,OnProperties);
SC_HANDLE_COMMAND(IDC_PREVIEWMODE,OnPreviewMode);
SC_HANDLE_COMMAND(IDC_TAKEPICTURE,OnTakePicture);
SC_HANDLE_COMMAND(IDC_ICONMODE,OnIconMode);
SC_HANDLE_COMMAND(IDC_DELETE,OnDelete);
SC_HANDLE_COMMAND(IDC_SELECTALL,OnSelectAll);
}
SC_END_COMMAND_HANDLERS();
}
INT_PTR CALLBACK CCameraAcquireDialog::DialogProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
SC_BEGIN_DIALOG_MESSAGE_HANDLERS(CCameraAcquireDialog)
{
SC_HANDLE_DIALOG_MESSAGE( WM_INITDIALOG, OnInitDialog );
SC_HANDLE_DIALOG_MESSAGE( WM_SIZE, OnSize );
SC_HANDLE_DIALOG_MESSAGE( WM_SHOWWINDOW, OnShow );
SC_HANDLE_DIALOG_MESSAGE( WM_ENTERSIZEMOVE, OnEnterSizeMove );
SC_HANDLE_DIALOG_MESSAGE( WM_EXITSIZEMOVE, OnExitSizeMove );
SC_HANDLE_DIALOG_MESSAGE( WM_COMMAND, OnCommand );
SC_HANDLE_DIALOG_MESSAGE( WM_GETMINMAXINFO, OnGetMinMaxInfo );
SC_HANDLE_DIALOG_MESSAGE( WM_NOTIFY, OnNotify );
SC_HANDLE_DIALOG_MESSAGE( WM_DESTROY, OnDestroy );
SC_HANDLE_DIALOG_MESSAGE( PWM_POSTINIT, OnPostInit );
SC_HANDLE_DIALOG_MESSAGE( PWM_CHANGETOPARENT, OnChangeToParent );
SC_HANDLE_DIALOG_MESSAGE( PWM_THUMBNAILSTATUS, OnThumbnailStatus );
SC_HANDLE_DIALOG_MESSAGE( PWM_PREVIEWSTATUS, OnPreviewStatus );
SC_HANDLE_DIALOG_MESSAGE( PWM_PREVIEWPERCENT, OnPreviewPercent );
SC_HANDLE_DIALOG_MESSAGE( PWM_ITEMDELETED, OnItemDeleted );
SC_HANDLE_DIALOG_MESSAGE( PWM_WIAEVENT, OnWiaEvent );
SC_HANDLE_DIALOG_MESSAGE( WM_TIMER, OnTimer );
SC_HANDLE_DIALOG_MESSAGE( WM_HELP, OnHelp );
SC_HANDLE_DIALOG_MESSAGE( WM_CONTEXTMENU, OnContextMenu );
SC_HANDLE_DIALOG_MESSAGE( WM_SYSCOLORCHANGE, OnSysColorChange );
}
SC_END_DIALOG_MESSAGE_HANDLERS();
}
// Static hook-related data
HWND CCameraAcquireDialog::s_hWndDialog = NULL;
HHOOK CCameraAcquireDialog::s_hMessageHook = NULL;