1081 lines
31 KiB
C++
1081 lines
31 KiB
C++
#ifndef __WIAITEM_H_INCLUDED
|
|
#define __WIAITEM_H_INCLUDED
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <wia.h>
|
|
#include <uicommon.h>
|
|
#include <itranhlp.h>
|
|
#include "pshelper.h"
|
|
#include "propstrm.h"
|
|
#include "resource.h"
|
|
#include "gphelper.h"
|
|
#include "wiaffmt.h"
|
|
|
|
class CWiaItem
|
|
{
|
|
public:
|
|
//
|
|
// Used to store the region for the scanner
|
|
//
|
|
struct CScanRegionSettings
|
|
{
|
|
SIZE sizeResolution;
|
|
POINT ptOrigin;
|
|
SIZE sizeExtent;
|
|
};
|
|
|
|
|
|
private:
|
|
CComPtr<IWiaItem> m_pWiaItem;
|
|
DWORD m_dwGlobalInterfaceTableCookie;
|
|
bool m_bSelectedForDownload;
|
|
HBITMAP m_hBitmapImage;
|
|
PBYTE m_pBitmapData;
|
|
LONG m_nWidth;
|
|
LONG m_nHeight;
|
|
LONG m_nBitmapDataLength;
|
|
CScanRegionSettings m_ScanRegionSettings;
|
|
CPropertyStream m_SavedPropertyStream;
|
|
CPropertyStream m_CustomPropertyStream;
|
|
bool m_bDeleted;
|
|
bool m_bAttemptedThumbnailDownload;
|
|
mutable LONG m_nItemType;
|
|
|
|
CWiaItem *m_pParent;
|
|
CWiaItem *m_pChildren;
|
|
CWiaItem *m_pNext;
|
|
|
|
GUID m_guidDefaultFormat;
|
|
LONG m_nAccessRights;
|
|
LONG m_nImageWidth;
|
|
LONG m_nImageHeight;
|
|
int m_nRotationAngle;
|
|
|
|
CSimpleStringWide m_strwFullItemName;
|
|
CSimpleStringWide m_strwItemName;
|
|
|
|
CAnnotationType m_AnnotationType;
|
|
|
|
CSimpleString m_strDefExt;
|
|
|
|
private:
|
|
// No implementation
|
|
CWiaItem(void);
|
|
CWiaItem( const CWiaItem & );
|
|
CWiaItem &operator=( const CWiaItem & );
|
|
|
|
public:
|
|
explicit CWiaItem( IWiaItem *pWiaItem )
|
|
: m_pWiaItem(pWiaItem),
|
|
m_dwGlobalInterfaceTableCookie(0),
|
|
m_bSelectedForDownload(false),
|
|
m_hBitmapImage(NULL),
|
|
m_pBitmapData(NULL),
|
|
m_nWidth(0),
|
|
m_nHeight(0),
|
|
m_nBitmapDataLength(0),
|
|
m_pParent(NULL),
|
|
m_pChildren(NULL),
|
|
m_pNext(NULL),
|
|
m_guidDefaultFormat(IID_NULL),
|
|
m_nRotationAngle(0),
|
|
m_nAccessRights(0),
|
|
m_nItemType(0),
|
|
m_nImageWidth(0),
|
|
m_nImageHeight(0),
|
|
m_AnnotationType(AnnotationNone),
|
|
m_bAttemptedThumbnailDownload(false)
|
|
{
|
|
WIA_PUSH_FUNCTION((TEXT("CWiaItem::CWiaItem")));
|
|
if (m_pWiaItem)
|
|
{
|
|
CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
|
|
HRESULT hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (VOID**)&pGlobalInterfaceTable );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pGlobalInterfaceTable->RegisterInterfaceInGlobal( pWiaItem, IID_IWiaItem, &m_dwGlobalInterfaceTableCookie );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WIA_TRACE((TEXT("IGlobalInterfaceTable::RegisterInterfaceInGlobal gave us a cookie of %d"), m_dwGlobalInterfaceTableCookie ));
|
|
}
|
|
}
|
|
//
|
|
// NOTE: This is a here to get the item name so we can delete it later
|
|
// in response to a delete event, because there is no other way to find an item
|
|
// since ReadMultiple will fail after the item is deleted. This is the only item
|
|
// property I read on the foreground thread during initialization, unfortunately.
|
|
// but i need it immediately. One other awful alternative would be to just walk
|
|
// the item tree and call ReadMultiple on each item and prune the ones that return
|
|
// WIA_ERROR_ITEM_DELETED in response to delete item event.
|
|
//
|
|
PropStorageHelpers::GetProperty( m_pWiaItem, WIA_IPA_FULL_ITEM_NAME, m_strwFullItemName );
|
|
PropStorageHelpers::GetProperty( m_pWiaItem, WIA_IPA_ITEM_NAME, m_strwItemName );
|
|
}
|
|
}
|
|
~CWiaItem(void)
|
|
{
|
|
WIA_PUSH_FUNCTION((TEXT("CWiaItem::~CWiaItem")));
|
|
//
|
|
// Remove the item from the GIT
|
|
//
|
|
if (m_pWiaItem)
|
|
{
|
|
CComPtr<IGlobalInterfaceTable> pGlobalInterfaceTable;
|
|
HRESULT hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (VOID**)&pGlobalInterfaceTable );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pGlobalInterfaceTable->RevokeInterfaceFromGlobal( m_dwGlobalInterfaceTableCookie );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WIA_TRACE((TEXT("IGlobalInterfaceTable::RevokeInterfaceFromGlobal succeeded on %d"), m_dwGlobalInterfaceTableCookie ));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Delete the item's Thumbnail
|
|
if (m_hBitmapImage)
|
|
{
|
|
DeleteObject(m_hBitmapImage);
|
|
m_hBitmapImage = NULL;
|
|
}
|
|
|
|
//
|
|
// Delete the thumbnail data
|
|
//
|
|
if (m_pBitmapData)
|
|
{
|
|
LocalFree(m_pBitmapData);
|
|
m_pBitmapData = NULL;
|
|
}
|
|
|
|
//
|
|
// NULL out all the other members
|
|
//
|
|
m_pWiaItem = NULL;
|
|
m_dwGlobalInterfaceTableCookie = 0;
|
|
m_nWidth = m_nHeight = m_nImageWidth = m_nImageHeight = m_nBitmapDataLength = 0;
|
|
m_pParent = m_pChildren = m_pNext = NULL;
|
|
}
|
|
|
|
LONG ItemType(void) const
|
|
{
|
|
//
|
|
// If we've already read the item type, don't read it again
|
|
//
|
|
if (!m_nItemType && m_pWiaItem)
|
|
{
|
|
(void)m_pWiaItem->GetItemType(&m_nItemType);
|
|
}
|
|
|
|
//
|
|
// Return m_nItemType even if IWiaItem::GetItemType fails, because it will still be 0, which
|
|
// also works as an error result
|
|
//
|
|
return m_nItemType;
|
|
}
|
|
|
|
bool Deleted(void) const
|
|
{
|
|
return m_bDeleted;
|
|
}
|
|
|
|
void MarkDeleted(void)
|
|
{
|
|
m_bDeleted = true;
|
|
m_bSelectedForDownload = false;
|
|
}
|
|
|
|
bool RotationEnabled( bool bAllowUninitializedRotation=false ) const
|
|
{
|
|
WIA_PUSH_FUNCTION((TEXT("CWiaItem::RotationEnabled(%d)"),bAllowUninitializedRotation));
|
|
|
|
//
|
|
// If this image doesn't have a thumbnail AND we tried to get the thumbnail, don't allow
|
|
// rotation even if the caller says it is OK. This image doesn't have a thumbnail
|
|
// because it didn't provide one, not because we don't have one yet
|
|
//
|
|
if (m_bAttemptedThumbnailDownload && !HasThumbnail())
|
|
{
|
|
return false;
|
|
}
|
|
//
|
|
// If this is an uninitialized image and we are told to allow uninitialized rotation,
|
|
// we will allow rotation, which we will discard when the image is initialized.
|
|
//
|
|
if (bAllowUninitializedRotation && m_guidDefaultFormat==IID_NULL && m_nImageWidth==0 && m_nImageHeight==0)
|
|
{
|
|
WIA_TRACE((TEXT("Uninitialized image: returning true")));
|
|
return true;
|
|
}
|
|
return WiaUiUtil::CanWiaImageBeSafelyRotated( m_guidDefaultFormat, m_nImageWidth, m_nImageHeight );
|
|
}
|
|
|
|
bool AttemptedThumbnailDownload( bool bAttemptedThumbnailDownload )
|
|
{
|
|
return (m_bAttemptedThumbnailDownload = bAttemptedThumbnailDownload);
|
|
}
|
|
|
|
bool AttemptedThumbnailDownload() const
|
|
{
|
|
return m_bAttemptedThumbnailDownload;
|
|
}
|
|
|
|
void DiscardRotationIfNecessary(void)
|
|
{
|
|
WIA_PUSHFUNCTION(TEXT("CWiaItem::DiscardRotationIfNecessary"));
|
|
//
|
|
// After the image is initialized, we will discard the rotation angle if it turns out the
|
|
// image cannot be rotated
|
|
//
|
|
if (!RotationEnabled())
|
|
{
|
|
WIA_TRACE((TEXT("Discarding rotation")));
|
|
m_nRotationAngle = 0;
|
|
}
|
|
}
|
|
|
|
bool IsValid(void) const
|
|
{
|
|
return(m_pWiaItem && m_dwGlobalInterfaceTableCookie);
|
|
}
|
|
|
|
CSimpleStringWide FullItemName(void) const
|
|
{
|
|
return m_strwFullItemName;
|
|
}
|
|
CSimpleStringWide ItemName(void) const
|
|
{
|
|
return m_strwItemName;
|
|
}
|
|
|
|
GUID DefaultFormat(void)
|
|
{
|
|
return m_guidDefaultFormat;
|
|
}
|
|
void DefaultFormat( const GUID &guidDefaultFormat )
|
|
{
|
|
m_guidDefaultFormat = guidDefaultFormat;
|
|
}
|
|
|
|
LONG AccessRights(void) const
|
|
{
|
|
return m_nAccessRights;
|
|
}
|
|
void AccessRights( LONG nAccessRights )
|
|
{
|
|
m_nAccessRights = nAccessRights;
|
|
}
|
|
|
|
void Rotate( bool bRight )
|
|
{
|
|
switch (m_nRotationAngle)
|
|
{
|
|
case 0:
|
|
m_nRotationAngle = bRight ? 90 : 270;
|
|
break;
|
|
case 90:
|
|
m_nRotationAngle = bRight ? 180 : 0;
|
|
break;
|
|
case 180:
|
|
m_nRotationAngle = bRight ? 270 : 90;
|
|
break;
|
|
case 270:
|
|
m_nRotationAngle = bRight ? 0 : 180;
|
|
break;
|
|
}
|
|
}
|
|
int Rotation(void) const
|
|
{
|
|
return m_nRotationAngle;
|
|
}
|
|
|
|
CSimpleString DefExt() const
|
|
{
|
|
return m_strDefExt;
|
|
}
|
|
const CSimpleString &DefExt( const CSimpleString &strDefExt )
|
|
{
|
|
return (m_strDefExt = strDefExt );
|
|
}
|
|
|
|
CScanRegionSettings &ScanRegionSettings(void)
|
|
{
|
|
return m_ScanRegionSettings;
|
|
}
|
|
const CScanRegionSettings &ScanRegionSettings(void) const
|
|
{
|
|
return m_ScanRegionSettings;
|
|
}
|
|
|
|
CPropertyStream &SavedPropertyStream(void)
|
|
{
|
|
return m_SavedPropertyStream;
|
|
}
|
|
const CPropertyStream &SavedPropertyStream(void) const
|
|
{
|
|
return m_SavedPropertyStream;
|
|
}
|
|
|
|
CPropertyStream &CustomPropertyStream(void)
|
|
{
|
|
return m_CustomPropertyStream;
|
|
}
|
|
const CPropertyStream &CustomPropertyStream(void) const
|
|
{
|
|
return m_CustomPropertyStream;
|
|
}
|
|
bool SelectedForDownload(void) const
|
|
{
|
|
return m_bSelectedForDownload;
|
|
}
|
|
bool SelectedForDownload( bool bSelectedForDownload )
|
|
{
|
|
return(m_bSelectedForDownload = bSelectedForDownload);
|
|
}
|
|
|
|
HBITMAP BitmapImage(void) const
|
|
{
|
|
return m_hBitmapImage;
|
|
}
|
|
HBITMAP BitmapImage( HBITMAP hBitmapImage )
|
|
{
|
|
if (m_hBitmapImage)
|
|
{
|
|
DeleteObject(m_hBitmapImage);
|
|
}
|
|
return(m_hBitmapImage = hBitmapImage);
|
|
}
|
|
|
|
PBYTE BitmapData(void) const
|
|
{
|
|
return m_pBitmapData;
|
|
}
|
|
PBYTE BitmapData( PBYTE pBitmapData )
|
|
{
|
|
if (m_pBitmapData)
|
|
{
|
|
LocalFree(m_pBitmapData);
|
|
}
|
|
return(m_pBitmapData = pBitmapData);
|
|
}
|
|
|
|
LONG Width(void) const
|
|
{
|
|
return m_nWidth;
|
|
}
|
|
LONG Width( LONG nWidth )
|
|
{
|
|
return (m_nWidth = nWidth);
|
|
}
|
|
|
|
LONG Height(void) const
|
|
{
|
|
return m_nHeight;
|
|
}
|
|
LONG Height( LONG nHeight )
|
|
{
|
|
return (m_nHeight = nHeight);
|
|
}
|
|
|
|
LONG BitmapDataLength(void) const
|
|
{
|
|
return m_nBitmapDataLength;
|
|
}
|
|
LONG BitmapDataLength( LONG nBitmapDataLength )
|
|
{
|
|
return (m_nBitmapDataLength = nBitmapDataLength);
|
|
}
|
|
|
|
LONG ImageWidth(void) const
|
|
{
|
|
return m_nImageWidth;
|
|
}
|
|
LONG ImageWidth( LONG nImageWidth )
|
|
{
|
|
return (m_nImageWidth = nImageWidth);
|
|
}
|
|
|
|
LONG ImageHeight(void) const
|
|
{
|
|
return m_nImageHeight;
|
|
}
|
|
LONG ImageHeight( LONG nImageHeight )
|
|
{
|
|
return (m_nImageHeight = nImageHeight);
|
|
}
|
|
|
|
bool HasThumbnail() const
|
|
{
|
|
return (m_pBitmapData && m_nWidth && m_nHeight);
|
|
}
|
|
|
|
HBITMAP CreateThumbnailFromBitmapData( HDC hDC )
|
|
{
|
|
//
|
|
// Assume failure
|
|
//
|
|
HBITMAP hbmpResult = NULL;
|
|
|
|
//
|
|
// If we've already attempted to download this image
|
|
//
|
|
if (m_bAttemptedThumbnailDownload)
|
|
{
|
|
//
|
|
// Make sure we have good data
|
|
//
|
|
if (m_pBitmapData && m_nWidth && m_nHeight)
|
|
{
|
|
//
|
|
// Initialize the bitmap info
|
|
//
|
|
BITMAPINFO BitmapInfo = {0};
|
|
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
BitmapInfo.bmiHeader.biWidth = m_nWidth;
|
|
BitmapInfo.bmiHeader.biHeight = m_nHeight;
|
|
BitmapInfo.bmiHeader.biPlanes = 1;
|
|
BitmapInfo.bmiHeader.biBitCount = 24;
|
|
BitmapInfo.bmiHeader.biCompression = BI_RGB;
|
|
|
|
//
|
|
// Create the bitmap
|
|
//
|
|
PBYTE pBits = NULL;
|
|
hbmpResult = CreateDIBSection( hDC, &BitmapInfo, DIB_RGB_COLORS, (void**)&pBits, NULL, 0 );
|
|
if (hbmpResult)
|
|
{
|
|
//
|
|
// Calculate the size of the bitmap data
|
|
//
|
|
LONG nSizeOfBitmapData = WiaUiUtil::Align( m_nWidth * 3, sizeof(DWORD) ) * m_nHeight;
|
|
|
|
//
|
|
// Copy the bitmap data to the bitmap. Make sure we use the minimum of the calculated
|
|
// and actual length
|
|
//
|
|
CopyMemory( pBits, m_pBitmapData, WiaUiUtil::Min(nSizeOfBitmapData,m_nBitmapDataLength) );
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((HRESULT_FROM_WIN32(GetLastError()),TEXT("CreateDIBSection failed!")));
|
|
}
|
|
}
|
|
}
|
|
|
|
return hbmpResult;
|
|
}
|
|
|
|
HBITMAP CreateThumbnailBitmap( HWND hWnd, CGdiPlusHelper &GdiPlusHelper, int nSizeX, int nSizeY )
|
|
{
|
|
//
|
|
// Initialize the return value. Assume failure.
|
|
//
|
|
HBITMAP hThumbnail = NULL;
|
|
|
|
//
|
|
// Only return a bitmap if we've already attempted to download one
|
|
//
|
|
if (m_bAttemptedThumbnailDownload)
|
|
{
|
|
//
|
|
// Make sure this is a real thumbnail. If not, we will create a fake one below.
|
|
//
|
|
if (HasThumbnail())
|
|
{
|
|
//
|
|
// Get the client DC
|
|
//
|
|
HDC hDC = GetDC( hWnd );
|
|
if (hDC)
|
|
{
|
|
//
|
|
// Create the bitmap from the raw bitmap data
|
|
//
|
|
HBITMAP hRawBitmap = CreateThumbnailFromBitmapData( hDC );
|
|
if (hRawBitmap)
|
|
{
|
|
//
|
|
// Rotate the thumbnail
|
|
//
|
|
HBITMAP hRotatedThumbnail = NULL;
|
|
if (SUCCEEDED(GdiPlusHelper.Rotate( hRawBitmap, hRotatedThumbnail, Rotation())))
|
|
{
|
|
//
|
|
// Make sure we got a valid rotated thumbnail
|
|
//
|
|
if (hRotatedThumbnail)
|
|
{
|
|
//
|
|
// Try to scale the image
|
|
//
|
|
SIZE sizeScaled = {nSizeX,nSizeY};
|
|
ScaleImage( hDC, hRotatedThumbnail, hThumbnail, sizeScaled );
|
|
|
|
//
|
|
// Nuke the rotated bitmap
|
|
//
|
|
DeleteBitmap(hRotatedThumbnail);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Nuke the raw bitmap
|
|
//
|
|
DeleteBitmap(hRawBitmap);
|
|
}
|
|
|
|
//
|
|
// Release the client DC
|
|
//
|
|
ReleaseDC( hWnd, hDC );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTGUID((m_guidDefaultFormat,TEXT("m_guidDefaultFormat")));
|
|
|
|
//
|
|
// Create a file format object and load the type icon
|
|
//
|
|
CWiaFileFormat WiaFileFormat;
|
|
WiaFileFormat.Format( m_guidDefaultFormat );
|
|
WiaFileFormat.Extension( m_strDefExt );
|
|
HICON hIcon = WiaFileFormat.AcquireIcon( NULL, false );
|
|
|
|
//
|
|
// Make sure we have an icon
|
|
//
|
|
if (hIcon)
|
|
{
|
|
//
|
|
// Create the icon thumbnail with the type icon and the name of the file
|
|
//
|
|
hThumbnail = WiaUiUtil::CreateIconThumbnail( hWnd, nSizeX, nSizeY, hIcon, CSimpleStringConvert::NaturalString(m_strwItemName) );
|
|
WIA_TRACE((TEXT("hThumbnail: %p"),hThumbnail));
|
|
|
|
//
|
|
// Destroy the icon to prevent leaks
|
|
//
|
|
DestroyIcon(hIcon);
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("Unable to get the icon")));
|
|
}
|
|
}
|
|
}
|
|
|
|
return hThumbnail;
|
|
}
|
|
|
|
|
|
HBITMAP CreateThumbnailBitmap( HDC hDC )
|
|
{
|
|
//
|
|
// Assume failure
|
|
//
|
|
HBITMAP hbmpResult = NULL;
|
|
|
|
//
|
|
// Make sure we have good data
|
|
//
|
|
WIA_TRACE((TEXT("m_pBitmapData: %08X, m_nWidth: %d, m_nWidth: %d"), m_pBitmapData, m_nWidth, m_nHeight ));
|
|
if (m_pBitmapData && m_nWidth && m_nHeight)
|
|
{
|
|
//
|
|
// Initialize the bitmap info
|
|
//
|
|
BITMAPINFO BitmapInfo = {0};
|
|
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
BitmapInfo.bmiHeader.biWidth = m_nWidth;
|
|
BitmapInfo.bmiHeader.biHeight = m_nHeight;
|
|
BitmapInfo.bmiHeader.biPlanes = 1;
|
|
BitmapInfo.bmiHeader.biBitCount = 24;
|
|
BitmapInfo.bmiHeader.biCompression = BI_RGB;
|
|
|
|
//
|
|
// Create the bitmap
|
|
//
|
|
PBYTE pBits = NULL;
|
|
hbmpResult = CreateDIBSection( hDC, &BitmapInfo, DIB_RGB_COLORS, (void**)&pBits, NULL, 0 );
|
|
if (hbmpResult)
|
|
{
|
|
LONG nSizeOfBitmapData = WiaUiUtil::Align( m_nWidth * 3, sizeof(DWORD) ) * m_nHeight;
|
|
CopyMemory( pBits, m_pBitmapData, WiaUiUtil::Min(nSizeOfBitmapData,m_nBitmapDataLength) );
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((HRESULT_FROM_WIN32(GetLastError()),TEXT("CreateDIBSection failed!")));
|
|
}
|
|
}
|
|
return hbmpResult;
|
|
}
|
|
|
|
IWiaItem *WiaItem(void) const
|
|
{
|
|
return m_pWiaItem.p;
|
|
}
|
|
IWiaItem *WiaItem(void)
|
|
{
|
|
return m_pWiaItem.p;
|
|
}
|
|
|
|
const CWiaItem *Next(void) const
|
|
{
|
|
return(m_pNext);
|
|
}
|
|
CWiaItem *Next(void)
|
|
{
|
|
return(m_pNext);
|
|
}
|
|
CWiaItem *Next( CWiaItem *pNext )
|
|
{
|
|
return(m_pNext = pNext);
|
|
}
|
|
|
|
const CWiaItem *Children(void) const
|
|
{
|
|
return(m_pChildren);
|
|
}
|
|
CWiaItem *Children(void)
|
|
{
|
|
return(m_pChildren);
|
|
}
|
|
CWiaItem *Children( CWiaItem *pChildren )
|
|
{
|
|
return(m_pChildren = pChildren);
|
|
}
|
|
|
|
const CWiaItem *Parent(void) const
|
|
{
|
|
return(m_pParent);
|
|
}
|
|
CWiaItem *Parent(void)
|
|
{
|
|
return(m_pParent);
|
|
}
|
|
CWiaItem *Parent( CWiaItem *pParent )
|
|
{
|
|
return(m_pParent = pParent);
|
|
}
|
|
|
|
DWORD GlobalInterfaceTableCookie(void) const
|
|
{
|
|
return m_dwGlobalInterfaceTableCookie;
|
|
}
|
|
bool operator==( const CWiaItem &WiaItem )
|
|
{
|
|
return(WiaItem.WiaItem() == m_pWiaItem.p);
|
|
}
|
|
bool operator==( DWORD dwGlobalInterfaceTableCookie )
|
|
{
|
|
return(dwGlobalInterfaceTableCookie == GlobalInterfaceTableCookie());
|
|
}
|
|
|
|
bool IsDownloadableItemType(void) const
|
|
{
|
|
LONG nItemType = ItemType();
|
|
return ((nItemType & WiaItemTypeImage) || (nItemType & WiaItemTypeVideo));
|
|
}
|
|
|
|
CAnnotationType AnnotationType(void) const
|
|
{
|
|
return m_AnnotationType;
|
|
}
|
|
void AnnotationType( CAnnotationType AnnotationType )
|
|
{
|
|
m_AnnotationType = AnnotationType;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
class CWiaItemList
|
|
{
|
|
public:
|
|
enum CEnumEvent
|
|
{
|
|
CountingItems, // Recursing tree, counting items. nData == current count
|
|
ReadingItemInfo // Recursing tree, reading info. nData == current item
|
|
};
|
|
|
|
typedef bool (*WiaItemEnumerationCallbackFunction)( CEnumEvent EnumEvent, UINT nData, LPARAM lParam, bool bForceUpdate );
|
|
|
|
|
|
private:
|
|
CWiaItem *m_pRoot;
|
|
|
|
private:
|
|
// No implementation
|
|
CWiaItemList( const CWiaItemList & );
|
|
CWiaItemList &operator=( const CWiaItemList & );
|
|
|
|
public:
|
|
CWiaItemList(void)
|
|
: m_pRoot(NULL)
|
|
{
|
|
}
|
|
|
|
~CWiaItemList(void)
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
void Destroy( CWiaItem *pRoot )
|
|
{
|
|
while (pRoot)
|
|
{
|
|
Destroy(pRoot->Children());
|
|
CWiaItem *pCurr = pRoot;
|
|
pRoot = pRoot->Next();
|
|
delete pCurr;
|
|
}
|
|
}
|
|
|
|
void Destroy(void)
|
|
{
|
|
Destroy(m_pRoot);
|
|
m_pRoot = NULL;
|
|
}
|
|
|
|
const CWiaItem *Root(void) const
|
|
{
|
|
return(m_pRoot);
|
|
}
|
|
CWiaItem *Root(void)
|
|
{
|
|
return(m_pRoot);
|
|
}
|
|
CWiaItem *Root( CWiaItem *pRoot )
|
|
{
|
|
return(m_pRoot = pRoot);
|
|
}
|
|
|
|
int Count( CWiaItem *pFirst )
|
|
{
|
|
int nCount = 0;
|
|
for (CWiaItem *pCurr = pFirst;pCurr;pCurr = pCurr->Next())
|
|
{
|
|
if (pCurr->IsDownloadableItemType() && !pCurr->Deleted())
|
|
nCount++;
|
|
nCount += Count(pCurr->Children());
|
|
}
|
|
return nCount;
|
|
}
|
|
int Count(void)
|
|
{
|
|
return Count(m_pRoot);
|
|
}
|
|
|
|
int SelectedForDownloadCount( CWiaItem *pFirst )
|
|
{
|
|
int nCount = 0;
|
|
for (CWiaItem *pCurr = pFirst;pCurr;pCurr = pCurr->Next())
|
|
{
|
|
if (pCurr->IsDownloadableItemType() && pCurr->SelectedForDownload())
|
|
nCount++;
|
|
nCount += SelectedForDownloadCount(pCurr->Children());
|
|
}
|
|
return nCount;
|
|
}
|
|
|
|
int SelectedForDownloadCount(void)
|
|
{
|
|
return SelectedForDownloadCount(Root());
|
|
}
|
|
|
|
static CWiaItem *Find( CWiaItem *pRoot, const CWiaItem *pNode )
|
|
{
|
|
for (CWiaItem *pCurr = pRoot;pCurr;pCurr = pCurr->Next())
|
|
{
|
|
if (*pCurr == *pNode)
|
|
{
|
|
if (!pCurr->Deleted())
|
|
{
|
|
return pCurr;
|
|
}
|
|
}
|
|
if (pCurr->Children())
|
|
{
|
|
CWiaItem *pFind = Find( pCurr->Children(), pNode );
|
|
if (pFind)
|
|
{
|
|
return pFind;
|
|
}
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
CWiaItem *Find( CWiaItem *pNode )
|
|
{
|
|
return(Find( m_pRoot, pNode ));
|
|
}
|
|
static CWiaItem *Find( CWiaItem *pRoot, IWiaItem *pItem )
|
|
{
|
|
for (CWiaItem *pCurr = pRoot;pCurr;pCurr = pCurr->Next())
|
|
{
|
|
if (pCurr->WiaItem() == pItem)
|
|
{
|
|
if (!pCurr->Deleted())
|
|
{
|
|
return pCurr;
|
|
}
|
|
}
|
|
if (pCurr->Children())
|
|
{
|
|
CWiaItem *pFind = Find( pCurr->Children(), pItem );
|
|
if (pFind)
|
|
{
|
|
return pFind;
|
|
}
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
CWiaItem *Find( IWiaItem *pItem )
|
|
{
|
|
return(Find( m_pRoot, pItem ));
|
|
}
|
|
static CWiaItem *Find( CWiaItem *pRoot, LPCWSTR pwszFindName )
|
|
{
|
|
for (CWiaItem *pCurr = pRoot;pCurr;pCurr = pCurr->Next())
|
|
{
|
|
if (CSimpleStringConvert::NaturalString(CSimpleStringWide(pwszFindName)) == CSimpleStringConvert::NaturalString(pCurr->FullItemName()))
|
|
{
|
|
if (!pCurr->Deleted())
|
|
{
|
|
return pCurr;
|
|
}
|
|
}
|
|
if (pCurr->Children())
|
|
{
|
|
CWiaItem *pFind = Find( pCurr->Children(), pwszFindName );
|
|
if (pFind)
|
|
{
|
|
return pFind;
|
|
}
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
CWiaItem *Find( LPCWSTR pwszFindName )
|
|
{
|
|
return(Find( m_pRoot, pwszFindName ));
|
|
}
|
|
static CWiaItem *Find( CWiaItem *pRoot, DWORD dwGlobalInterfaceTableCookie )
|
|
{
|
|
for (CWiaItem *pCurr = pRoot;pCurr;pCurr = pCurr->Next())
|
|
{
|
|
if (pCurr->GlobalInterfaceTableCookie() == dwGlobalInterfaceTableCookie)
|
|
{
|
|
if (!pCurr->Deleted())
|
|
{
|
|
return pCurr;
|
|
}
|
|
}
|
|
if (pCurr->Children())
|
|
{
|
|
CWiaItem *pFind = Find( pCurr->Children(), dwGlobalInterfaceTableCookie );
|
|
if (pFind)
|
|
{
|
|
return pFind;
|
|
}
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
CWiaItem *Find( DWORD dwGlobalInterfaceTableCookie )
|
|
{
|
|
return(Find( m_pRoot, dwGlobalInterfaceTableCookie ));
|
|
}
|
|
HRESULT Add( CWiaItem *pParent, CWiaItem *pNewWiaItemNode )
|
|
{
|
|
WIA_PUSHFUNCTION(TEXT("CWiaItemList::Add"));
|
|
WIA_TRACE((TEXT("Root(): 0x%08X"), Root()));
|
|
if (pNewWiaItemNode)
|
|
{
|
|
if (!Root())
|
|
{
|
|
Root(pNewWiaItemNode);
|
|
pNewWiaItemNode->Parent(NULL);
|
|
pNewWiaItemNode->Children(NULL);
|
|
pNewWiaItemNode->Next(NULL);
|
|
}
|
|
else
|
|
{
|
|
if (!pParent)
|
|
{
|
|
CWiaItem *pCurr=Root();
|
|
while (pCurr && pCurr->Next())
|
|
{
|
|
pCurr=pCurr->Next();
|
|
}
|
|
pCurr->Next(pNewWiaItemNode);
|
|
pNewWiaItemNode->Next(NULL);
|
|
pNewWiaItemNode->Children(NULL);
|
|
pNewWiaItemNode->Parent(NULL);
|
|
}
|
|
else if (!pParent->Children())
|
|
{
|
|
pParent->Children(pNewWiaItemNode);
|
|
pNewWiaItemNode->Next(NULL);
|
|
pNewWiaItemNode->Children(NULL);
|
|
pNewWiaItemNode->Parent(pParent);
|
|
}
|
|
else
|
|
{
|
|
CWiaItem *pCurr=pParent->Children();
|
|
while (pCurr && pCurr->Next())
|
|
{
|
|
pCurr=pCurr->Next();
|
|
}
|
|
pCurr->Next(pNewWiaItemNode);
|
|
pNewWiaItemNode->Next(NULL);
|
|
pNewWiaItemNode->Children(NULL);
|
|
pNewWiaItemNode->Parent(pParent);
|
|
}
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT EnumerateItems( CWiaItem *pCurrentParent, IEnumWiaItem *pEnumWiaItem, int &nCurrentItem, WiaItemEnumerationCallbackFunction pfnWiaItemEnumerationCallback = NULL, LPARAM lParam = 0 )
|
|
{
|
|
WIA_PUSHFUNCTION(TEXT("CWiaItemList::EnumerateItems"));
|
|
|
|
//
|
|
// Assume failure
|
|
//
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Make sure we have a valid enumerator
|
|
//
|
|
if (pEnumWiaItem != NULL)
|
|
{
|
|
//
|
|
// Start at the beginning
|
|
//
|
|
hr = pEnumWiaItem->Reset();
|
|
while (hr == S_OK)
|
|
{
|
|
//
|
|
// Get the next item
|
|
//
|
|
CComPtr<IWiaItem> pWiaItem;
|
|
hr = pEnumWiaItem->Next(1, &pWiaItem, NULL);
|
|
if (S_OK == hr)
|
|
{
|
|
if (pfnWiaItemEnumerationCallback)
|
|
{
|
|
bool bContinue = pfnWiaItemEnumerationCallback( ReadingItemInfo, nCurrentItem, lParam, false );
|
|
if (!bContinue)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// Create a CWiaItem wrapper
|
|
//
|
|
CWiaItem *pNewWiaItem = new CWiaItem( pWiaItem );
|
|
if (pNewWiaItem && pNewWiaItem->WiaItem())
|
|
{
|
|
//
|
|
// Get the item type
|
|
//
|
|
LONG nItemType = pNewWiaItem->ItemType();
|
|
if (nItemType)
|
|
{
|
|
//
|
|
// Add it to the list
|
|
//
|
|
Add( pCurrentParent, pNewWiaItem );
|
|
|
|
//
|
|
// If it is an image, mark it as downloadeable
|
|
//
|
|
if (pNewWiaItem->IsDownloadableItemType())
|
|
{
|
|
pNewWiaItem->SelectedForDownload(true);
|
|
nCurrentItem++;
|
|
WIA_TRACE((TEXT("Found an image")));
|
|
}
|
|
//
|
|
// If it is not an image, mark it as downloadeable
|
|
//
|
|
else
|
|
{
|
|
pNewWiaItem->SelectedForDownload(false);
|
|
WIA_TRACE((TEXT("Found something that is NOT an image")));
|
|
}
|
|
|
|
//
|
|
// If it is a folder, enumerate its child items and recurse
|
|
//
|
|
if (nItemType & WiaItemTypeFolder)
|
|
{
|
|
CComPtr <IEnumWiaItem> pIEnumChildItem;
|
|
if (S_OK == pWiaItem->EnumChildItems(&pIEnumChildItem))
|
|
{
|
|
EnumerateItems( pNewWiaItem, pIEnumChildItem, nCurrentItem, pfnWiaItemEnumerationCallback, lParam );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Since we are using S_FALSE for cancel, we need to break out of this loop and set hr to S_OK
|
|
//
|
|
else if (S_FALSE == hr)
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Call the callback function one more time, and force the update
|
|
//
|
|
if (pfnWiaItemEnumerationCallback)
|
|
{
|
|
bool bContinue = pfnWiaItemEnumerationCallback( ReadingItemInfo, nCurrentItem, lParam, true );
|
|
if (!bContinue)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT EnumerateAllWiaItems( IWiaItem *pWiaRootItem, WiaItemEnumerationCallbackFunction pfnWiaItemEnumerationCallback = NULL, LPARAM lParam = 0 )
|
|
{
|
|
//
|
|
// Make sure we have a valid root item
|
|
//
|
|
if (!pWiaRootItem)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Enumerate the child items
|
|
//
|
|
CComPtr<IEnumWiaItem> pEnumItem;
|
|
HRESULT hr = pWiaRootItem->EnumChildItems(&pEnumItem);
|
|
if (hr == S_OK)
|
|
{
|
|
int nItemCount = 0;
|
|
//
|
|
// Entry point to the recursive enumeration routine
|
|
//
|
|
hr = EnumerateItems( NULL, pEnumItem, nItemCount, pfnWiaItemEnumerationCallback, lParam );
|
|
}
|
|
return hr;
|
|
}
|
|
};
|
|
|
|
|
|
#endif // __WIAITEM_H_INCLUDED
|