You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1870 lines
60 KiB
1870 lines
60 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|