|
|
/*++
Copyright (C) 1999- Microsoft Corporation
Module Name:
imgitem.cpp
Abstract:
This module implements image item related function of CWiaMiniDriver class
Author:
William Hsieh (williamh) created
Revision History:
--*/
#include "pch.h"
//
// Minimum data call back transfer buffer size
//
const LONG MIN_BUFFER_SIZE = 0x8000;
//
// Arrays used for setting up valid value lists for properties
//
LONG g_TymedArray[] = { TYMED_FILE, TYMED_CALLBACK };
//
// This function initializes the item's properties
// Input:
// pWiasContext -- wias service context
// lFlags -- misc flags
// plDevErrVal -- to return device error;
//
HRESULT CWiaMiniDriver::InitItemProperties(BYTE *pWiasContext) { DBG_FN("CWiaMiniDriver::InitItemProperties");
HRESULT hr = S_OK;
//
// Locals
//
LONG ItemType = 0; FORMAT_INFO *pFormatInfo = NULL; BSTR bstrFileExt = NULL; CLSID *pImageFormats = NULL;
hr = wiasGetItemType(pWiasContext, &ItemType); if (FAILED(hr)) { wiauDbgError("InitItemProperties", "wiasGetItemType failed"); return hr; }
BOOL bBitmap = FALSE; // Indicates that preferred format is bitmap
LONG lBytesPerLine = 0;
//
// There are no properties for storage items. In fact, there are no driver items created for
// stores.
//
if (ItemType & WiaItemTypeStorage) return hr;
DRVITEM_CONTEXT *pItemCtx; hr = WiasContextToItemContext(pWiasContext, &pItemCtx, NULL); if (FAILED(hr)) { wiauDbgError("InitItemProperties", "WiasContextToItemContext failed"); return hr; }
//
// Set up properties that are used for all item types
//
CWiauPropertyList ItemProps; CPtpObjectInfo *pObjectInfo = pItemCtx->pObjectInfo;
const INT NUM_ITEM_PROPS = 24; hr = ItemProps.Init(NUM_ITEM_PROPS); if (FAILED(hr)) { wiauDbgError("InitItemProperties", "Init failed"); return hr; }
INT index;
//
// WIA_IPA_ITEM_TIME
//
SYSTEMTIME SystemTime; hr = GetObjectTime(pObjectInfo, &SystemTime); if (FAILED(hr)) { wiauDbgError("InitItemProperties", "GetObjectTime failed"); return hr; }
hr = ItemProps.DefineProperty(&index, WIA_IPA_ITEM_TIME, WIA_IPA_ITEM_TIME_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure;
ItemProps.SetCurrentValue(index, &SystemTime);
//
// WIA_IPA_ACCESS_RIGHTS
//
LONG lProtection; hr = IsObjectProtected(pObjectInfo, lProtection); if (FAILED(hr)) { wiauDbgError("InitItemProperties", "IsObjectProtected failed"); return hr; }
hr = ItemProps.DefineProperty(&index, WIA_IPA_ACCESS_RIGHTS, WIA_IPA_ACCESS_RIGHTS_STR, WIA_PROP_READ, WIA_PROP_FLAG | WIA_PROP_NONE); if (FAILED(hr)) goto failure;
//
// If device does not support delete command, access rights are always Read-Only
//
if (m_DeviceInfo.m_SupportedOps.Find(PTP_OPCODE_DELETEOBJECT) < 0) { lProtection = WIA_PROP_READ; ItemProps.SetCurrentValue(index, lProtection); } else { //
// If device supports the SetObjectProtection command, item access rights is r/w
//
if (m_DeviceInfo.m_SupportedOps.Find(PTP_OPCODE_SETOBJECTPROTECTION) >= 0) { ItemProps.SetAccessSubType(index, WIA_PROP_RW, WIA_PROP_FLAG); ItemProps.SetValidValues(index, lProtection, lProtection, WIA_ITEM_RWD); } else { ItemProps.SetCurrentValue(index, lProtection); } }
pFormatInfo = FormatCodeToFormatInfo(pObjectInfo->m_FormatCode);
//
// WIA_IPA_FILENAME_EXTENSION
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_FILENAME_EXTENSION, WIA_IPA_FILENAME_EXTENSION_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; if(pFormatInfo->ExtString && pFormatInfo->ExtString[0]) { bstrFileExt = SysAllocString(pFormatInfo->ExtString); } else { if(pObjectInfo->m_cbstrExtension.Length()) { bstrFileExt = SysAllocString(pObjectInfo->m_cbstrExtension.String()); } } ItemProps.SetCurrentValue(index, bstrFileExt); //
// Set up properties common to files
//
if (ItemType & WiaItemTypeFile) { //
// WIA_IPA_PREFERRED_FORMAT
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_PREFERRED_FORMAT, WIA_IPA_PREFERRED_FORMAT_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, pFormatInfo->FormatGuid);
bBitmap = IsEqualGUID(WiaImgFmt_BMP, *pFormatInfo->FormatGuid) || IsEqualGUID(WiaImgFmt_MEMORYBMP, *pFormatInfo->FormatGuid);
//
// WIA_IPA_FORMAT
//
// For images, BMP may also be added below
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_FORMAT, WIA_IPA_FORMAT_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetAccessSubType(index, WIA_PROP_RW, WIA_PROP_LIST); ItemProps.SetCurrentValue(index, pFormatInfo->FormatGuid); ItemProps.SetValidValues(index, pFormatInfo->FormatGuid, pFormatInfo->FormatGuid, 1, &pFormatInfo->FormatGuid); //
// WIA_IPA_COMPRESSION
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_COMPRESSION, WIA_IPA_COMPRESSION_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (LONG) WIA_COMPRESSION_NONE);
//
// WIA_IPA_TYMED
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_TYMED, WIA_IPA_TYMED_STR, WIA_PROP_RW, WIA_PROP_LIST); if (FAILED(hr)) goto failure; ItemProps.SetValidValues(index, TYMED_FILE, TYMED_FILE, sizeof(g_TymedArray) / sizeof(g_TymedArray[0]), g_TymedArray);
//
// WIA_IPA_ITEM_SIZE
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_ITEM_SIZE, WIA_IPA_ITEM_SIZE_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure;
if (bBitmap) { lBytesPerLine = ((pObjectInfo->m_ImagePixWidth * pObjectInfo->m_ImageBitDepth + 31) & ~31) / 8; ItemProps.SetCurrentValue(index, (LONG) (lBytesPerLine * pObjectInfo->m_ImagePixHeight)); } else ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_CompressedSize);
//
// WIA_IPA_MIN_BUFFER_SIZE
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_MIN_BUFFER_SIZE, WIA_IPA_MIN_BUFFER_SIZE_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure;
LONG minBufSize; if (!bBitmap && pObjectInfo->m_CompressedSize > 0) minBufSize = min(MIN_BUFFER_SIZE, pObjectInfo->m_CompressedSize); else minBufSize = MIN_BUFFER_SIZE; ItemProps.SetCurrentValue(index, minBufSize); }
//
// Set up the image-only properties
//
if (ItemType & WiaItemTypeImage) { //
// WIA_IPA_DATATYPE
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_DATATYPE, WIA_IPA_DATATYPE_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; if(pObjectInfo->m_ImageBitDepth <= 8) { ItemProps.SetCurrentValue(index, (LONG) WIA_DATA_GRAYSCALE); } else { ItemProps.SetCurrentValue(index, (LONG) WIA_DATA_COLOR); }
//
// WIA_IPA_DEPTH
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_DEPTH, WIA_IPA_DEPTH_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_ImageBitDepth);
//
// WIA_IPA_FORMAT
//
// If the image format is something that can be converted, change the access to
// read/write and add BMP to the valid value list.
//
if (pFormatInfo->FormatGuid) { index = ItemProps.LookupPropId(WIA_IPA_FORMAT); ItemProps.SetAccessSubType(index, WIA_PROP_RW, WIA_PROP_LIST); pImageFormats = new CLSID[3]; if(!pImageFormats) { wiauDbgError("InitItemProperties", "failed to allocate 3 GUIDs"); hr = E_OUTOFMEMORY; goto failure; } pImageFormats[0] = *pFormatInfo->FormatGuid; pImageFormats[1] = WiaImgFmt_BMP; pImageFormats[2] = WiaImgFmt_MEMORYBMP; ItemProps.SetValidValues(index, pFormatInfo->FormatGuid, pFormatInfo->FormatGuid, 3, &pImageFormats); }
//
// WIA_IPA_CHANNELS_PER_PIXEL
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_CHANNELS_PER_PIXEL, WIA_IPA_CHANNELS_PER_PIXEL_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (LONG) (pObjectInfo->m_ImageBitDepth == 8 ? 1 : 3));
//
// WIA_IPA_BITS_PER_CHANNEL
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_BITS_PER_CHANNEL, WIA_IPA_BITS_PER_CHANNEL_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (LONG) 8);
//
// WIA_IPA_PLANAR
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_PLANAR, WIA_IPA_PLANAR_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (LONG) WIA_PACKED_PIXEL);
//
// WIA_IPA_PIXELS_PER_LINE
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_PIXELS_PER_LINE, WIA_IPA_PIXELS_PER_LINE_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_ImagePixWidth);
//
// WIA_IPA_BYTES_PER_LINE
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_BYTES_PER_LINE, WIA_IPA_BYTES_PER_LINE_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure;
if (bBitmap) lBytesPerLine; else ItemProps.SetCurrentValue(index, (LONG) 0);
//
// WIA_IPA_NUMBER_OF_LINES
//
hr = ItemProps.DefineProperty(&index, WIA_IPA_NUMBER_OF_LINES, WIA_IPA_NUMBER_OF_LINES_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_ImagePixHeight);
//
// WIA_IPC_SEQUENCE
//
if (pObjectInfo->m_SequenceNumber > 0) { hr = ItemProps.DefineProperty(&index, WIA_IPC_SEQUENCE, WIA_IPC_SEQUENCE_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_SequenceNumber); }
//
// WIA_IPC_TIMEDELAY
//
// This property needs to be populated from the AssociationDesc field in the parent's ObjectInfo
// structure, but only if the parent's AssociationType field is TimeSequence.
// WIAFIX-10/3/2000-davepar Implement this property
}
//
// Set up properties common to image and video items that have
// thumbnails
//
if (ItemType & (WiaItemTypeImage | WiaItemTypeVideo) && pObjectInfo->m_ThumbPixWidth) { //
// WIA_IPC_THUMBNAIL
//
hr = ItemProps.DefineProperty(&index, WIA_IPC_THUMBNAIL, WIA_IPC_THUMBNAIL_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (BYTE *) NULL, 0);
//
// WIA_IPC_THUMB_WIDTH
//
hr = ItemProps.DefineProperty(&index, WIA_IPC_THUMB_WIDTH, WIA_IPC_THUMB_WIDTH_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_ThumbPixWidth);
//
// WIA_IPC_THUMB_HEIGHT
//
hr = ItemProps.DefineProperty(&index, WIA_IPC_THUMB_HEIGHT, WIA_IPC_THUMB_HEIGHT_STR, WIA_PROP_READ, WIA_PROP_NONE); if (FAILED(hr)) goto failure; ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_ThumbPixHeight);
}
//
// Last step: send all the properties to WIA
//
hr = ItemProps.SendToWia(pWiasContext); if (FAILED(hr)) { wiauDbgErrorHr(hr, "InitItemProperties", "SendToWia failed"); goto failure; }
if (bstrFileExt) SysFreeString(bstrFileExt);
delete [] pImageFormats;
return hr;
//
// Any failures from DefineProperty will end up here
//
failure:
delete [] pImageFormats; if (bstrFileExt) SysFreeString(bstrFileExt);
wiauDbgErrorHr(hr, "InitItemProperties", "DefineProperty failed"); return hr; }
//
// This function determines the protection status (whether an object can be
// deleted or written to) of an object on the device.
//
// Input:
// pObjectInfo -- pointer to the ObjectInfo structure
// Output:
// bProtected -- indicates whether the object is protected
//
HRESULT CWiaMiniDriver::IsObjectProtected( CPtpObjectInfo *pObjectInfo, LONG &lProtection) { DBG_FN("CWiaMiniDriver::IsObjectProtected");
HRESULT hr = S_OK; lProtection = WIA_ITEM_READ;
if (!pObjectInfo) { wiauDbgError("ObjectProtected", "invalid arg"); return E_INVALIDARG; }
if (pObjectInfo->m_ProtectionStatus == PTP_PROTECTIONSTATUS_READONLY) return hr;
//
// Check the protection status of the store as well
//
INT storeIndex = m_StorageIds.Find(pObjectInfo->m_StorageId); if (storeIndex < 0) { wiauDbgWarning("ObjectProtected", "couldn't find the object's store"); return hr; }
switch (m_StorageInfos[storeIndex].m_AccessCapability) { case PTP_STORAGEACCESS_RWD: lProtection = WIA_ITEM_RWD; break;
case PTP_STORAGEACCESS_R: lProtection = WIA_ITEM_READ; break;
case PTP_STORAGEACCESS_RD: lProtection = WIA_ITEM_RD; break;
default: //
// Not a fatal error, but this is an unknown access capability. Use read-only.
//
wiauDbgError("ObjectProtected", "unknown storage access capability"); lProtection = WIA_ITEM_READ; break; }
return hr; }
//
// This function gets the object time and converts it to a system time
//
// Input:
// pObjNode -- the object
// pSystemTime -- to receive the object time
// Output:
// HRESULT
//
HRESULT CWiaMiniDriver::GetObjectTime( CPtpObjectInfo *pObjectInfo, SYSTEMTIME *pSystemTime ) { DBG_FN("CWiaMiniDriver::GetObjectTime");
HRESULT hr = S_OK;
CBstr *pTimeStr = NULL;
if (!pObjectInfo || !pSystemTime) { wiauDbgError("GetObjectTime", "invalid arg"); return E_INVALIDARG; }
//
// Try to use the modification date, then the capture date
//
if (pObjectInfo->m_cbstrModificationDate.Length() > 0) pTimeStr = &pObjectInfo->m_cbstrModificationDate;
else if (pObjectInfo->m_cbstrCaptureDate.Length() > 0) pTimeStr = &pObjectInfo->m_cbstrCaptureDate;
//
// See if a valid date/time was found, otherwise use system time
//
if (pTimeStr) { hr = PtpTime2SystemTime(pTimeStr, pSystemTime); if (FAILED(hr)) { wiauDbgError("GetObjectTime", "PtpTime2SystemTime failed"); return hr; } } else { GetLocalTime(pSystemTime); }
return hr; }
//
// This function reads item properties. In this situation, only the thumbnail
// properties are important.
//
// Input:
// pWiasContext -- wia service context
// NumPropSpecs -- number of properties to read
// pPropSpecs -- what properties to read
//
HRESULT CWiaMiniDriver::ReadItemProperties( BYTE *pWiasContext, LONG NumPropSpecs, const PROPSPEC *pPropSpecs ) { DBG_FN("CWiaMiniDriver::ReadItemProperties");
HRESULT hr = S_OK;
LONG ItemType = 0; hr = wiasGetItemType(pWiasContext, &ItemType); if (FAILED(hr)) { wiauDbgError("ReadItemProperties", "wiasGetItemType failed"); return hr; }
PDRVITEM_CONTEXT pItemCtx = NULL; hr = WiasContextToItemContext(pWiasContext, &pItemCtx); if (FAILED(hr)) { wiauDbgError("ReadItemProperties", "WiasContextToItemContext failed"); return hr; }
//
// For all items (except the root or stores), update the item time if requested. The time may
// have been updated by an ObjectInfoChanged event.
//
if (IsItemTypeFolder(ItemType) || ItemType & WiaItemTypeFile) { if (wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_IPA_ITEM_TIME)) { SYSTEMTIME SystemTime; hr = GetObjectTime(pItemCtx->pObjectInfo, &SystemTime); if (FAILED(hr)) { wiauDbgError("ReadItemProperties", "GetObjectTime failed"); return hr; }
PROPVARIANT propVar; PROPSPEC propSpec; propVar.vt = VT_VECTOR | VT_UI2; propVar.caui.cElems = sizeof(SystemTime) / sizeof(WORD); propVar.caui.pElems = (WORD *) &SystemTime; propSpec.ulKind = PRSPEC_PROPID; propSpec.propid = WIA_IPA_ITEM_TIME; hr = wiasWriteMultiple(pWiasContext, 1, &propSpec, &propVar ); if (FAILED(hr)) { wiauDbgError("ReadItemProperties", "wiasWriteMultiple failed"); return hr; } } }
if(ItemType & WiaItemTypeImage && pItemCtx->pObjectInfo->m_ImagePixWidth == 0) { // image geometry is missing -- see if this is what we are asked
PROPID propsToUpdate[] = { WIA_IPA_PIXELS_PER_LINE, WIA_IPA_NUMBER_OF_LINES }; if(wiauPropsInPropSpec(NumPropSpecs, pPropSpecs, sizeof(propsToUpdate) / sizeof(PROPID), propsToUpdate)) { // we can deal with any image as long as GDI+ understands it
UINT NativeImageSize = pItemCtx->pObjectInfo->m_CompressedSize; UINT width, height, depth;
wiauDbgWarning("ReadImageProperties", "Retrieving missing geometry! Expensive!"); //
// Allocate memory for the native image
//
BYTE *pNativeImage = new BYTE[NativeImageSize]; if(pNativeImage == NULL) { return E_OUTOFMEMORY; }
//
// Get the data from the camera
//
hr = m_pPTPCamera->GetObjectData(pItemCtx->pObjectInfo->m_ObjectHandle, pNativeImage, &NativeImageSize, (LPVOID) 0); if(hr == S_FALSE) { wiauDbgWarning("ReadItemProperties", "GetObjectData() cancelled"); delete [] pNativeImage; return S_FALSE; } if(FAILED(hr)) { wiauDbgError("ReadItemProperties", "GetObjectData() failed"); delete [] pNativeImage; return S_FALSE; }
//
// get image geometry, discard native image
//
if(pItemCtx->pObjectInfo->m_FormatCode == PTP_FORMATCODE_IMAGE_EXIF || pItemCtx->pObjectInfo->m_FormatCode == PTP_FORMATCODE_IMAGE_JFIF) { hr = GetJpegDimensions(pNativeImage, NativeImageSize, &width, &height, &depth); } else { hr = GetImageDimensions(pItemCtx->pObjectInfo->m_FormatCode, pNativeImage, NativeImageSize, &width, &height, &depth); } delete [] pNativeImage; if(FAILED(hr)) { wiauDbgError("ReadItemProperties", "failed to get image geometry from compressed image"); return hr; }
pItemCtx->pObjectInfo->m_ImagePixWidth = width; pItemCtx->pObjectInfo->m_ImagePixHeight = height; hr = wiasWritePropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, width); if(FAILED(hr)) { wiauDbgError("ReadItemProperties", "failed to write image width"); return hr; } hr = wiasWritePropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, height); if(FAILED(hr)) { wiauDbgError("ReadItemProperties", "failed to set image height"); return hr; } } }
//
// For images and video, update the thumbnail properties if requested
//
if (ItemType & (WiaItemTypeImage | WiaItemTypeVideo)) { //
// Get the thumbnail if requested to update any of the thumbnail properties and
// the thumbnail is not already cached.
//
PROPID propsToUpdate[] = { WIA_IPC_THUMB_WIDTH, WIA_IPC_THUMB_HEIGHT, WIA_IPC_THUMBNAIL };
if (wiauPropsInPropSpec(NumPropSpecs, pPropSpecs, sizeof(propsToUpdate) / sizeof(PROPID), propsToUpdate)) { if (!pItemCtx->pThumb) { hr = CacheThumbnail(pItemCtx); if (FAILED(hr)) { wiauDbgError("ReadItemProperties", "CacheThumbnail failed"); return hr; } }
//
// Update the related thumbnail properties. Update the thumb width and height in case
// the device didn't report them in the ObjectInfo structure (they are optional there).
//
PROPSPEC propSpecs[3]; PROPVARIANT propVars[3];
propSpecs[0].ulKind = PRSPEC_PROPID; propSpecs[0].propid = WIA_IPC_THUMB_WIDTH; propVars[0].vt = VT_I4; propVars[0].lVal = pItemCtx->pObjectInfo->m_ThumbPixWidth;
propSpecs[1].ulKind = PRSPEC_PROPID; propSpecs[1].propid = WIA_IPC_THUMB_HEIGHT; propVars[1].vt = VT_I4; propVars[1].lVal = pItemCtx->pObjectInfo->m_ThumbPixHeight;
propSpecs[2].ulKind = PRSPEC_PROPID; propSpecs[2].propid = WIA_IPC_THUMBNAIL; propVars[2].vt = VT_VECTOR | VT_UI1; propVars[2].caub.cElems = pItemCtx->ThumbSize; propVars[2].caub.pElems = pItemCtx->pThumb;
hr = wiasWriteMultiple(pWiasContext, 3, propSpecs, propVars); if (FAILED(hr)) { wiauDbgError("ReadItemProperties", "wiasWriteMultiple failed"); delete pItemCtx->pThumb; pItemCtx->pThumb = NULL; } } }
return hr; }
//
// This function caches the thumbnail into the given DRVITEM_CONTEXT
//
// Input:
// pItemCtx -- the designated DRVITEM_CONTEXT
//
HRESULT CWiaMiniDriver::CacheThumbnail(PDRVITEM_CONTEXT pItemCtx) { DBG_FN("CWiaMiniDriver::CacheThumbnail");
HRESULT hr = S_OK;
if (pItemCtx->pThumb) { wiauDbgError("CacheThumbnail", "thumbnail is already cached"); return E_FAIL; }
CPtpObjectInfo *pObjectInfo = pItemCtx->pObjectInfo; if (!pObjectInfo) { wiauDbgError("CacheThumbnail", "Object info pointer is null"); return E_FAIL; }
if (pObjectInfo->m_ThumbCompressedSize <= 0) { wiauDbgWarning("CacheThumbnail", "No thumbnail available for this item"); return hr; }
//
// We have to load the thumbnail in its native format
//
BYTE *pNativeThumb; pNativeThumb = new BYTE[pObjectInfo->m_ThumbCompressedSize]; if (!pNativeThumb) { wiauDbgError("CacheThumbnail", "memory allocation failed"); return E_OUTOFMEMORY; }
UINT size = pObjectInfo->m_ThumbCompressedSize; hr = m_pPTPCamera->GetThumb(pObjectInfo->m_ObjectHandle, pNativeThumb, &size); if (FAILED(hr)) { wiauDbgError("CacheThumbnail", "GetThumb failed"); delete []pNativeThumb; return hr; }
//
// Figure out what base image format the thumbnail is in. Note that BMP thumbnails
// are not allowed currently.
//
BOOL bTiff = FALSE; BOOL bJpeg = FALSE;
if (PTP_FORMATCODE_IMAGE_TIFF == pObjectInfo->m_ThumbFormat || PTP_FORMATCODE_IMAGE_TIFFEP == pObjectInfo->m_ThumbFormat || PTP_FORMATCODE_IMAGE_TIFFIT == pObjectInfo->m_ThumbFormat) bTiff = TRUE;
else if (PTP_FORMATCODE_IMAGE_EXIF == pObjectInfo->m_ThumbFormat || PTP_FORMATCODE_IMAGE_JFIF == pObjectInfo->m_ThumbFormat) bJpeg = TRUE;
else { wiauDbgWarning("CacheThumbnail", "unknown thumbnail format"); delete []pNativeThumb; return hr; }
//
// If the thumbnail format is JPEG or TIFF, get the real thumbnail
// width and height from the header information.
//
UINT BitDepth; UINT width, height; if (bTiff) { hr = GetTiffDimensions(pNativeThumb, pObjectInfo->m_ThumbCompressedSize, &width, &height, &BitDepth); }
else if (bJpeg) { hr = GetJpegDimensions(pNativeThumb, pObjectInfo->m_ThumbCompressedSize, &width, &height, &BitDepth); }
if (FAILED(hr)) { wiauDbgError("CacheThumbnail", "get image dimensions failed"); delete []pNativeThumb; return hr; }
pObjectInfo->m_ThumbPixWidth = width; pObjectInfo->m_ThumbPixHeight = height;
//
// Calculate the size of the headerless BMP and allocate space for it
//
ULONG LineSize; LineSize = GetDIBLineSize(pObjectInfo->m_ThumbPixWidth, 24); pItemCtx->ThumbSize = LineSize * pObjectInfo->m_ThumbPixHeight; pItemCtx->pThumb = new BYTE [pItemCtx->ThumbSize]; if (!pItemCtx->pThumb) { wiauDbgError("CacheThumbnail", "memory allocation failure"); delete []pNativeThumb; return E_OUTOFMEMORY; }
//
// Convert the thumbnail format to headerless BMP
//
if (bTiff) { hr = Tiff2DIBBitmap(pNativeThumb, pObjectInfo->m_ThumbCompressedSize, pItemCtx->pThumb + LineSize * (height - 1), pItemCtx->ThumbSize, LineSize, 0 ); } else if (bJpeg) { hr = Jpeg2DIBBitmap(pNativeThumb, pObjectInfo->m_ThumbCompressedSize, pItemCtx->pThumb + LineSize * (height - 1), pItemCtx->ThumbSize, LineSize, 0 ); }
if (FAILED(hr)) { wiauDbgError("CacheThumbnail", "conversion to bitmap failed"); delete []pNativeThumb; delete []pItemCtx->pThumb; pItemCtx->pThumb = NULL; return hr; }
delete []pNativeThumb;
return hr; }
//
// This function validates the given item properties.
//
// Input:
// pWiasContext -- wia service context
// NumPropSpecs -- number of properties to validate
// pPropSpecs -- the properties
//
HRESULT CWiaMiniDriver::ValidateItemProperties( BYTE *pWiasContext, LONG NumPropSpecs, const PROPSPEC *pPropSpecs, LONG ItemType ) { DBG_FN("CWiaMiniDriver::ValidateItemProperties");
HRESULT hr = S_OK;
//
// Locals
//
FORMAT_INFO *pFormatInfo = NULL;
DRVITEM_CONTEXT *pItemCtx; hr = WiasContextToItemContext(pWiasContext, &pItemCtx); if (FAILED(hr)) { wiauDbgError("ValidateItemProperties", "WiasContextToItemContext failed"); return hr; }
//
// If access rights are changed, send the new value to the camera
//
// WIAFIX-10/3/2000-davepar To be 100% correct, a change in the store protection should
// update the access rights for all of the items on the store. This could be done in response
// to a StoreInfoChanged event.
//
if (wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_IPA_ACCESS_RIGHTS)) { LONG rights; hr = wiasReadPropLong(pWiasContext, WIA_IPA_ACCESS_RIGHTS, &rights, NULL, TRUE); if (FAILED(hr)) { wiauDbgError("ValidateItemProperties", "wiasReadPropLong"); return hr; }
WORD objProt = (rights == WIA_ITEM_READ) ? PTP_PROTECTIONSTATUS_READONLY : PTP_PROTECTIONSTATUS_NONE; hr = m_pPTPCamera->SetObjectProtection(pItemCtx->pObjectInfo->m_ObjectHandle, objProt); if (FAILED(hr)) { wiauDbgError("ValidateItemProperties", "SetObjectProtection failed"); return hr; } }
//
// Update the valid formats by calling a WIA service function
//
BOOL bFormatChanged = FALSE;
if (wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_IPA_TYMED)) { WIA_PROPERTY_CONTEXT PropContext; hr = wiasCreatePropContext(NumPropSpecs, (PROPSPEC*) pPropSpecs, 0, NULL, &PropContext); if (FAILED(hr)) { wiauDbgError("ValidateItemProperties", "wiasCreatePropContext failed"); return hr; }
hr = wiasUpdateValidFormat(pWiasContext, &PropContext, (IWiaMiniDrv*) this); if (FAILED(hr)) { wiauDbgError("ValidateItemProperties", "wiasUpdateValidFormat failed"); return hr; }
hr = wiasFreePropContext(&PropContext); if (FAILED(hr)) { wiauDbgError("ValidateItemProperties", "wiasFreePropContext failed"); return hr; }
bFormatChanged = TRUE; }
//
// The only property change that needs to be validated is a change of format on an image
// item. In that case, the item's size and bytes per line, and file extension need to be updated.
//
if (ItemType & WiaItemTypeImage && (bFormatChanged || wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_IPA_FORMAT))) {
if(pItemCtx->pObjectInfo->m_ImagePixWidth == 0) { // one of those cameras
GUID fmt; hr = wiasReadPropGuid(pWiasContext, WIA_IPA_FORMAT, &fmt, NULL, false); if(FAILED(hr)) { wiauDbgError("ValidateItemProperies", "Failed to retrieve new format GUID"); } if(fmt == WiaImgFmt_BMP || fmt == WiaImgFmt_MEMORYBMP) { // for uncompressed transfers --
// tell service we don't know item size
wiasWritePropLong(pWiasContext, WIA_IPA_ITEM_SIZE, 0); } else { // for any other transfers -- tell serivce that
// compressed size is the item size
wiasWritePropLong(pWiasContext, WIA_IPA_ITEM_SIZE, pItemCtx->pObjectInfo->m_CompressedSize); } } else { pFormatInfo = FormatCodeToFormatInfo(pItemCtx->pObjectInfo->m_FormatCode);
hr = wiauSetImageItemSize(pWiasContext, pItemCtx->pObjectInfo->m_ImagePixWidth, pItemCtx->pObjectInfo->m_ImagePixHeight, pItemCtx->pObjectInfo->m_ImageBitDepth, pItemCtx->pObjectInfo->m_CompressedSize, pFormatInfo->ExtString); if (FAILED(hr)) { wiauDbgError("ValidateItemProperties", "SetImageItemSize failed"); return hr; } } }
//
// Call WIA service helper to check against valid values
//
hr = wiasValidateItemProperties(pWiasContext, NumPropSpecs, pPropSpecs); if (FAILED(hr)) { wiauDbgWarning("ValidateDeviceProperties", "wiasValidateItemProperties failed"); return hr; }
return hr; }
ULONG GetBitmapHeaderSize(PMINIDRV_TRANSFER_CONTEXT pmdtc) { UINT colormapsize = 0; UINT size = sizeof(BITMAPINFOHEADER); switch(pmdtc->lCompression) { case WIA_COMPRESSION_NONE: // BI_RGB
case WIA_COMPRESSION_BI_RLE4: case WIA_COMPRESSION_BI_RLE8: switch(pmdtc->lDepth) { case 1: colormapsize = 2; break; case 4: colormapsize = 16; break; case 8: colormapsize = 256; break; case 15: case 16: case 32: colormapsize = 3; break; case 24: colormapsize = 0; break; } }
size += colormapsize * sizeof(RGBQUAD); if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_BMP)) { size += sizeof(BITMAPFILEHEADER); }
return size; }
VOID VerticalFlip( PBYTE pImageTop, LONG iWidthInBytes, LONG iHeight) { //
// try to allocat a temp scan line buffer
//
PBYTE pBuffer = (PBYTE)LocalAlloc(LPTR,iWidthInBytes);
if (pBuffer != NULL) {
LONG index; PBYTE pImageBottom;
pImageBottom = pImageTop + (iHeight-1) * iWidthInBytes;
for (index = 0;index < (iHeight/2);index++) { memcpy(pBuffer,pImageTop,iWidthInBytes); memcpy(pImageTop,pImageBottom,iWidthInBytes); memcpy(pImageBottom,pBuffer,iWidthInBytes);
pImageTop += iWidthInBytes; pImageBottom -= iWidthInBytes; }
LocalFree(pBuffer); } }
HRESULT CWiaMiniDriver::AcquireAndTranslateAnyImage( BYTE *pWiasContext, DRVITEM_CONTEXT *pItemCtx, PMINIDRV_TRANSFER_CONTEXT pmdtc) { #define REQUIRE(x, y) if(!(x)) { wiauDbgError("AcquireAndTranslateAnyImage", y); goto Cleanup; }
DBG_FN("CWiaMiniDriver::AcquireAndTranslateAnyImage"); HRESULT hr = S_OK; BYTE *pNativeImage = NULL; BYTE *pRawImageBuffer = NULL; BOOL bPatchedMDTC = FALSE; UINT NativeImageSize = pItemCtx->pObjectInfo->m_CompressedSize; UINT width, height, depth, imagesize, headersize; BOOL bFileTransfer = (pmdtc->tymed & TYMED_FILE); LONG lMsg = (bFileTransfer ? IT_MSG_STATUS : IT_MSG_DATA); LONG percentComplete;
// we can deal with any image as long as GDIPlus can handle it
//
// Allocate memory for the native image
//
pNativeImage = new BYTE[NativeImageSize]; hr = E_OUTOFMEMORY; REQUIRE(pNativeImage, "memory allocation failed");
//
// Get the data from the camera
//
hr = m_pPTPCamera->GetObjectData(pItemCtx->pObjectInfo->m_ObjectHandle, pNativeImage, &NativeImageSize, (LPVOID) pmdtc); REQUIRE(hr != S_FALSE, "transfer cancelled"); REQUIRE(SUCCEEDED(hr), "GetObjectData failed");
//
// decompress image, retrieve its geometry
//
hr = ConvertAnyImageToBmp(pNativeImage, NativeImageSize, &width, &height, &depth, &pRawImageBuffer, &imagesize, &headersize); REQUIRE(hr == S_OK, "failed to convert image to bitmap format");
pmdtc->lWidthInPixels = pItemCtx->pObjectInfo->m_ImagePixWidth = width; pmdtc->cbWidthInBytes = (width * depth) / 8L; pmdtc->lLines = pItemCtx->pObjectInfo->m_ImagePixHeight = height; pmdtc->lDepth = pItemCtx->pObjectInfo->m_ImageBitDepth = depth; pmdtc->lImageSize = imagesize = ((width * depth) / 8L) * height; if(IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) { pmdtc->lHeaderSize = headersize - sizeof(BITMAPFILEHEADER); } else { pmdtc->lHeaderSize = headersize; } pmdtc->lItemSize = pmdtc->lImageSize + pmdtc->lHeaderSize;
hr = wiasWritePropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, width); REQUIRE(hr == S_OK, "failed to set image width");
hr = wiasWritePropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, height); REQUIRE(hr == S_OK, "failed to set image height");
hr = wiasWritePropLong(pWiasContext, WIA_IPA_ITEM_SIZE, 0); REQUIRE(hr == S_OK, "failed to set item size");
// setup buffer for uncompressed image
if(pmdtc->pTransferBuffer == NULL) { if(IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) { pmdtc->pTransferBuffer = pRawImageBuffer + sizeof(BITMAPFILEHEADER); } else { pmdtc->pTransferBuffer = pRawImageBuffer; } pmdtc->lBufferSize = pmdtc->lItemSize; bPatchedMDTC = TRUE; } else { if(IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) { memcpy(pmdtc->pTransferBuffer, pRawImageBuffer + sizeof(BITMAPFILEHEADER), pmdtc->lHeaderSize); } else { memcpy(pmdtc->pTransferBuffer, pRawImageBuffer, pmdtc->lHeaderSize); } } //
// Send the header to the app
//
percentComplete = 90 + (10 * pmdtc->lHeaderSize) / pmdtc->lItemSize;
hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT, percentComplete, 0, pmdtc->lHeaderSize, pmdtc, 0); REQUIRE(hr != S_FALSE, "transfer cancelled"); REQUIRE(SUCCEEDED(hr), "sending header to app failed");
if(bFileTransfer) { // write the whole image to file
ULONG ulWritten; BOOL bRet;
//
// NOTE: The mini driver transfer context should have the
// file handle as a pointer, not a fixed 32-bit long. This
// may not work on 64bit.
//
bRet = WriteFile((HANDLE)pmdtc->hFile, pRawImageBuffer, pmdtc->lItemSize, &ulWritten, NULL); if (!bRet) { hr = HRESULT_FROM_WIN32(::GetLastError()); wiauDbgError("AcquireAndTranslateAnyImage", "WriteFile failed (0x%X)", hr); } } else { LONG BytesToWrite, BytesLeft = pmdtc->lImageSize; BYTE *pCurrent = pRawImageBuffer + headersize; UINT offset = pmdtc->lHeaderSize;
while(BytesLeft) { BytesToWrite = min(pmdtc->lBufferSize, BytesLeft); memcpy(pmdtc->pTransferBuffer, pCurrent, BytesToWrite);
//
// Calculate the percentage done using 90 as a base. This makes a rough assumption that
// transferring the data from the device takes 90% of the time. If the this is the last
// transfer, set the percentage to 100, otherwise make sure it is never larger than 99.
//
if (BytesLeft == BytesToWrite) percentComplete = 100; else percentComplete = min(99, 90 + (10 * offset) / pmdtc->lItemSize);
hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT, percentComplete, offset, BytesToWrite, pmdtc, 0); REQUIRE(hr != S_FALSE, "transfer cancelled"); REQUIRE(SUCCEEDED(hr), "sending header to app failed");
pCurrent += BytesToWrite; offset += BytesToWrite; BytesLeft -= BytesToWrite; } }
Cleanup: delete [] pNativeImage; delete [] pRawImageBuffer;
// restore mdtc
pmdtc->lItemSize = 0;
if(bPatchedMDTC) { pmdtc->pTransferBuffer = 0; pmdtc->lBufferSize = 0; }
return hr; #undef REQUIRE
}
HRESULT CWiaMiniDriver::AcquireAndTranslateJpegWithoutGeometry( BYTE *pWiasContext, DRVITEM_CONTEXT *pItemCtx, PMINIDRV_TRANSFER_CONTEXT pmdtc) { #define REQUIRE(x, y) if(!(x)) { wiauDbgError("AcquireAndTranslateWithoutGeometry", y); goto Cleanup; }
DBG_FN("CWiaMiniDriver::AcquireAndTranslateWithoutGeometry"); HRESULT hr = E_FAIL; BYTE *pNativeImage = NULL; BYTE *pRawImageBuffer = NULL; BOOL bPatchedMDTC = FALSE; UINT NativeImageSize = pItemCtx->pObjectInfo->m_CompressedSize; UINT width, height, depth, imagesize, headersize; BOOL bFileTransfer = (pmdtc->tymed & TYMED_FILE); LONG lMsg = (bFileTransfer ? IT_MSG_STATUS : IT_MSG_DATA); LONG percentComplete;
// we can only deal with JPEG images
if(pItemCtx->pObjectInfo->m_FormatCode != PTP_FORMATCODE_IMAGE_JFIF && pItemCtx->pObjectInfo->m_FormatCode != PTP_FORMATCODE_IMAGE_EXIF) { hr = E_INVALIDARG; REQUIRE(0, "don't know how to get image geometry from non-JPEG image"); }
//
// Allocate memory for the native image
//
pNativeImage = new BYTE[NativeImageSize]; hr = E_OUTOFMEMORY; REQUIRE(pNativeImage, "memory allocation failed");
//
// Get the data from the camera
//
hr = m_pPTPCamera->GetObjectData(pItemCtx->pObjectInfo->m_ObjectHandle, pNativeImage, &NativeImageSize, (LPVOID) pmdtc); REQUIRE(hr != S_FALSE, "transfer cancelled"); REQUIRE(SUCCEEDED(hr), "GetObjectData failed");
//
// get image geometry
//
hr = GetJpegDimensions(pNativeImage, NativeImageSize, &width, &height, &depth); REQUIRE(hr == S_OK, "failed to get image geometry from JPEG file");
pmdtc->lWidthInPixels = pItemCtx->pObjectInfo->m_ImagePixWidth = width; pmdtc->lLines = pItemCtx->pObjectInfo->m_ImagePixHeight = height; pmdtc->lDepth = pItemCtx->pObjectInfo->m_ImageBitDepth = depth; pmdtc->lImageSize = imagesize = ((((width + 31) * depth) / 8L) & 0xFFFFFFFC) * height; pmdtc->lHeaderSize = headersize = GetBitmapHeaderSize(pmdtc); pmdtc->lItemSize = imagesize + headersize;
hr = wiasWritePropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, width); REQUIRE(hr == S_OK, "failed to set image width");
hr = wiasWritePropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, height); REQUIRE(hr == S_OK, "failed to set image height");
hr = wiasWritePropLong(pWiasContext, WIA_IPA_ITEM_SIZE, 0); REQUIRE(hr == S_OK, "failed to set item size");
// setup buffer for uncompressed image
pRawImageBuffer = new BYTE[pmdtc->lImageSize + pmdtc->lHeaderSize]; REQUIRE(pRawImageBuffer, "failed to allocate intermdiate buffer"); if(pmdtc->pTransferBuffer == NULL) { pmdtc->pTransferBuffer = pRawImageBuffer; pmdtc->lBufferSize = pmdtc->lItemSize; bPatchedMDTC = TRUE; }
hr = wiasGetImageInformation(pWiasContext, 0, pmdtc); REQUIRE(SUCCEEDED(hr), "wiasGetImageInformation failed");
percentComplete = 90 + (10 * pmdtc->lHeaderSize) / pmdtc->lItemSize; //
// Send the header to the app
//
if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) { UNALIGNED BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)pmdtc->pTransferBuffer; pbmih->biHeight = -pmdtc->lLines; }
hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT, percentComplete, 0, pmdtc->lHeaderSize, pmdtc, 0); REQUIRE(hr != S_FALSE, "transfer cancelled"); REQUIRE(SUCCEEDED(hr), "sending header to app failed");
//
// Convert the image to BMP
//
hr = Jpeg2DIBBitmap(pNativeImage, NativeImageSize, pRawImageBuffer + pmdtc->lHeaderSize + pmdtc->cbWidthInBytes * (pmdtc->lLines - 1), pmdtc->lImageSize, pmdtc->cbWidthInBytes, 1); REQUIRE(SUCCEEDED(hr), "image format conversion failed");
if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) { VerticalFlip(pRawImageBuffer + pmdtc->lHeaderSize, pmdtc->cbWidthInBytes, pmdtc->lLines); } if(bFileTransfer) { // write the whole image to file
#ifdef UNICODE
hr = wiasWriteBufToFile(0, pmdtc); #else
if (pmdtc->lItemSize <= pmdtc->lBufferSize) { ULONG ulWritten; BOOL bRet;
//
// NOTE: The mini driver transfer context should have the
// file handle as a pointer, not a fixed 32-bit long. This
// may not work on 64bit.
//
bRet = WriteFile((HANDLE)pmdtc->hFile, pmdtc->pTransferBuffer, pmdtc->lItemSize, &ulWritten, NULL);
if (!bRet) { hr = HRESULT_FROM_WIN32(::GetLastError()); wiauDbgError("AcquireDataAndTranslate", "WriteFile failed (0x%X)", hr); } } else { wiauDbgError("AcquireDataAndTranslate", "lItemSize is larger than buffer"); hr = E_FAIL; }
#endif
REQUIRE(SUCCEEDED(hr), "writing image body to file"); } else { LONG BytesToWrite, BytesLeft = pmdtc->lImageSize; BYTE *pCurrent = pRawImageBuffer + pmdtc->lHeaderSize; UINT offset = pmdtc->lHeaderSize; while(BytesLeft) { BytesToWrite = min(pmdtc->lBufferSize, BytesLeft); memcpy(pmdtc->pTransferBuffer, pCurrent, BytesToWrite);
//
// Calculate the percentage done using 90 as a base. This makes a rough assumption that
// transferring the data from the device takes 90% of the time. If the this is the last
// transfer, set the percentage to 100, otherwise make sure it is never larger than 99.
//
if (BytesLeft == BytesToWrite) percentComplete = 100; else percentComplete = min(99, 90 + (10 * offset) / pmdtc->lItemSize);
hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT, percentComplete, offset, BytesToWrite, pmdtc, 0); REQUIRE(hr != S_FALSE, "transfer cancelled"); REQUIRE(SUCCEEDED(hr), "sending header to app failed"); pCurrent += BytesToWrite; offset += BytesToWrite; BytesLeft -= BytesToWrite; } }
Cleanup: delete [] pNativeImage; delete [] pRawImageBuffer;
// restore mdtc
pmdtc->lItemSize = 0; if(bPatchedMDTC) { pmdtc->pTransferBuffer = 0; pmdtc->lBufferSize = 0; } return hr; }
//
// This function transfers image from the camera and translates it to BMP
// format.
//
// Input:
// pWiasContext -- wias context
// pItemCtx -- the mini driver item context
// pmdtc -- the transfer context
//
HRESULT CWiaMiniDriver::AcquireDataAndTranslate( BYTE *pWiasContext, DRVITEM_CONTEXT *pItemCtx, PMINIDRV_TRANSFER_CONTEXT pmdtc ) { DBG_FN("CWiaMiniDriver::AcquireDataAndTranslate"); HRESULT hr = S_OK;
// non-jpeg images are handled by GDI+ process
if(pItemCtx->pObjectInfo->m_FormatCode != PTP_FORMATCODE_IMAGE_JFIF && pItemCtx->pObjectInfo->m_FormatCode != PTP_FORMATCODE_IMAGE_EXIF) { return AcquireAndTranslateAnyImage(pWiasContext, pItemCtx, pmdtc); }
if(pItemCtx->pObjectInfo->m_ImagePixWidth == 0) { return AcquireAndTranslateJpegWithoutGeometry(pWiasContext, pItemCtx, pmdtc); }
//
// Allocate memory for the native image
//
UINT NativeImageSize = pItemCtx->pObjectInfo->m_CompressedSize; BYTE *pNativeImage = new BYTE[NativeImageSize]; if (!pNativeImage) { wiauDbgError("AcquireDataAndTranslate", "memory allocation failed"); return E_OUTOFMEMORY; }
//
// Get the data from the camera
//
hr = m_pPTPCamera->GetObjectData(pItemCtx->pObjectInfo->m_ObjectHandle, pNativeImage, &NativeImageSize, (LPVOID) pmdtc); if (FAILED(hr)) { wiauDbgError("AcquireDataAndTranslate", "GetObjectData failed"); delete []pNativeImage; return hr; } if (hr == S_FALSE) { wiauDbgWarning("AcquireDataAndTranslate", "transfer cancelled"); delete []pNativeImage; return hr; }
//
// Call the WIA service helper to fill in the BMP header
//
hr = wiasGetImageInformation(pWiasContext, 0, pmdtc); if (FAILED(hr)) { wiauDbgErrorHr(hr, "AcquireDataAndTranslate", "wiasGetImageInformation failed"); return hr; }
if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) { UNALIGNED BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)pmdtc->pTransferBuffer; pbmih->biHeight = -pmdtc->lLines; }
//
// Send the header to the app
//
BOOL bFileTransfer = (pmdtc->tymed & TYMED_FILE); LONG lMsg = (bFileTransfer ? IT_MSG_STATUS : IT_MSG_DATA);
LONG percentComplete = 90 + (10 * pmdtc->lHeaderSize) / pmdtc->lItemSize;
hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT, percentComplete, 0, pmdtc->lHeaderSize, pmdtc, 0); if (FAILED(hr)) { wiauDbgError("AcquireDataAndTranslate", "sending header to app failed"); return hr; } if (hr == S_FALSE) { wiauDbgWarning("AcquireDataAndTranslate", "transfer cancelled"); delete []pNativeImage; return S_FALSE; }
//
// Set up the buffer for the rest of the transfer
//
BYTE *pTranslateBuffer = pmdtc->pTransferBuffer; LONG BytesLeft = pmdtc->lBufferSize;
if (bFileTransfer) { pTranslateBuffer += pmdtc->lHeaderSize; BytesLeft -= pmdtc->lHeaderSize; }
//
// If the buffer is too small, allocate a new, bigger one
//
BOOL bIntermediateBuffer = FALSE; if (BytesLeft < pmdtc->lImageSize) { pTranslateBuffer = new BYTE[pmdtc->lImageSize]; BytesLeft = pmdtc->lImageSize; bIntermediateBuffer = TRUE; }
//
// Convert the image to BMP
//
hr = Jpeg2DIBBitmap(pNativeImage, NativeImageSize, pTranslateBuffer + pmdtc->cbWidthInBytes * (pmdtc->lLines - 1), BytesLeft, pmdtc->cbWidthInBytes, 1); //
// Free the native image buffer
//
delete []pNativeImage; pNativeImage = NULL;
if (FAILED(hr)) { wiauDbgError("AcquireDataAndTranslate", "image format conversion failed"); if (bIntermediateBuffer) delete []pTranslateBuffer; return hr; }
if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) { VerticalFlip(pTranslateBuffer, pmdtc->cbWidthInBytes, pmdtc->lLines); } LONG lOffset = pmdtc->lHeaderSize; if (bIntermediateBuffer) { //
// Send the data back a chunk at a time. This assumes that it is a callback transfer, e.g. the
// buffer pointer is not being incremented.
//
LONG BytesToCopy = 0; BYTE *pCurrent = pTranslateBuffer; BytesLeft = pmdtc->lImageSize;
while (BytesLeft > 0) { BytesToCopy = min(BytesLeft, pmdtc->lBufferSize); memcpy(pmdtc->pTransferBuffer, pCurrent, BytesToCopy);
//
// Calculate the percentage done using 90 as a base. This makes a rough assumption that
// transferring the data from the device takes 90% of the time. If the this is the last
// transfer, set the percentage to 100, otherwise make sure it is never larger than 99.
//
if (BytesLeft == BytesToCopy) percentComplete = 100; else percentComplete = min(99, 90 + (10 * lOffset) / pmdtc->lItemSize);
hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT, percentComplete, lOffset, BytesToCopy, pmdtc, 0); if (FAILED(hr)) { wiauDbgError("AcquireDataAndTranslate", "sending header to app failed"); if (bIntermediateBuffer) delete []pTranslateBuffer; return hr; } if (hr == S_FALSE) { wiauDbgWarning("AcquireDataAndTranslate", "transfer cancelled"); if (bIntermediateBuffer) delete []pTranslateBuffer; return S_FALSE; }
pCurrent += BytesToCopy; lOffset += BytesToCopy; BytesLeft -= BytesToCopy; } } else { //
// Send the data to the app in one big chunk
//
hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT, 100, lOffset, pmdtc->lImageSize, pmdtc, 0); if (FAILED(hr)) { wiauDbgError("AcquireDataAndTranslate", "sending header to app failed"); if (bIntermediateBuffer) delete []pTranslateBuffer; return hr; } }
//
// Free the translate buffer
//
if (bIntermediateBuffer) delete []pTranslateBuffer;
return hr; }
//
// This function transfers native data to the application without translating it.
//
// Input:
// pItemCtx -- driver item context
// pmdtc -- transfer context
//
HRESULT CWiaMiniDriver::AcquireData( DRVITEM_CONTEXT *pItemCtx, PMINIDRV_TRANSFER_CONTEXT pmdtc ) { DBG_FN("CWiaMiniDriver::AcquireData");
HRESULT hr = S_OK;
//
// If the class driver does not allocate the transfer buffer,
// we have to allocate a temporary one
//
if (!pmdtc->bClassDrvAllocBuf) { pmdtc->pTransferBuffer = new BYTE[pItemCtx->pObjectInfo->m_CompressedSize]; if (!pmdtc->pTransferBuffer) { wiauDbgError("AcquireData", "memory allocation failed"); return E_OUTOFMEMORY; } pmdtc->pBaseBuffer = pmdtc->pTransferBuffer; pmdtc->lBufferSize = pItemCtx->pObjectInfo->m_CompressedSize; }
//
// Get the data from the camera
//
UINT size = pmdtc->lBufferSize; hr = m_pPTPCamera->GetObjectData(pItemCtx->pObjectInfo->m_ObjectHandle, pmdtc->pTransferBuffer, &size, (LPVOID) pmdtc); //
// Check the return code, but keep going so that the buffer gets freed
//
if (FAILED(hr)) wiauDbgError("AcquireData", "GetObjectData failed"); else if (hr == S_FALSE) wiauDbgWarning("AcquireData", "data transfer cancelled");
//
// Free the temporary buffer, if needed
//
if (!pmdtc->bClassDrvAllocBuf) { if (pmdtc->pTransferBuffer) { delete []pmdtc->pTransferBuffer; pmdtc->pBaseBuffer = NULL; pmdtc->pTransferBuffer = NULL; pmdtc->lBufferSize = 0;
} else { wiauDbgWarning("AcquireData", "transfer buffer is NULL"); } }
return hr; }
//
// This function passes the data transfer callback through to the
// IWiaMiniDrvCallBack interface using the appropriate
// parameters.
//
// Input:
// pCallbackParam -- should hold a pointer to the transfer context
// lPercentComplete -- percent of transfer completed
// lOffset -- offset into the buffer where the data is located
// lLength -- amount of data transferred
//
HRESULT DataCallback( LPVOID pCallbackParam, LONG lPercentComplete, LONG lOffset, LONG lLength, BYTE **ppBuffer, LONG *plBufferSize ) { DBG_FN("DataCallback");
HRESULT hr = S_OK;
if (!pCallbackParam || !ppBuffer || !*ppBuffer || !plBufferSize) { wiauDbgError("DataCallback", "invalid argument"); return E_INVALIDARG; }
PMINIDRV_TRANSFER_CONTEXT pmdtc = (PMINIDRV_TRANSFER_CONTEXT) pCallbackParam;
//
// If app is asking for BMP, most likely it's being converted. Thus just give the app
// status messages. Calculate percent done so that the transfer takes 90% of the time
// and the conversion takes the last 10%.
//
if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_BMP) || IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) { hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_STATUS, IT_STATUS_TRANSFER_FROM_DEVICE, lPercentComplete * 9 / 10, lOffset, lLength, pmdtc, 0); *ppBuffer += lLength; }
//
// Otherwise, see if it's a file transfer
//
else if (pmdtc->tymed & TYMED_FILE) { if (pmdtc->bClassDrvAllocBuf && lPercentComplete == 100) { //
// Call WIA to write the data to the file. There is a small a bug that causes
// TIFF headers to be changed, so temporarily change the format GUID to null.
//
GUID tempFormat; tempFormat = pmdtc->guidFormatID; pmdtc->guidFormatID = GUID_NULL;
hr = wiasWritePageBufToFile(pmdtc); pmdtc->guidFormatID = tempFormat;
if (FAILED(hr)) { wiauDbgError("DataCallback", "wiasWritePageBufToFile failed"); return hr; } }
hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_STATUS, IT_STATUS_TRANSFER_TO_CLIENT, lPercentComplete, lOffset, lLength, pmdtc, 0); *ppBuffer += lLength; }
//
// Otherwise, it's a callback transfer
//
else { hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_DATA, IT_STATUS_TRANSFER_TO_CLIENT, lPercentComplete, lOffset, lLength, pmdtc, 0); //
// Update the buffer pointer and size in case the app is using double buffering
//
*ppBuffer = pmdtc->pTransferBuffer; *plBufferSize = pmdtc->lBufferSize; }
if (FAILED(hr)) { wiauDbgError("DataCallback", "MiniDrvCallback failed"); } else if (hr == S_FALSE) { wiauDbgWarning("DataCallback", "data transfer was cancelled by MiniDrvCallback"); }
return hr; }
|