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.
1955 lines
63 KiB
1955 lines
63 KiB
/*++
|
|
|
|
Copyright (C) 1999- Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
devitem.cpp
|
|
|
|
Abstract:
|
|
|
|
This module implements device related function of CWiaMiniDriver class
|
|
|
|
Author:
|
|
|
|
William Hsieh (williamh) created
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
#include <atlbase.h>
|
|
#include <atlconv.h>
|
|
|
|
//
|
|
// Locations for holding resource strings
|
|
//
|
|
extern WCHAR UnknownString[];
|
|
extern WCHAR FolderString[];
|
|
extern WCHAR ScriptString[];
|
|
extern WCHAR ExecString[];
|
|
extern WCHAR TextString[];
|
|
extern WCHAR HtmlString[];
|
|
extern WCHAR DpofString[];
|
|
extern WCHAR AudioString[];
|
|
extern WCHAR VideoString[];
|
|
extern WCHAR UnknownImgString[];
|
|
extern WCHAR ImageString[];
|
|
extern WCHAR AlbumString[];
|
|
extern WCHAR BurstString[];
|
|
extern WCHAR PanoramaString[];
|
|
|
|
|
|
//
|
|
// Mapping of non-image PTP formats to format info structures. Index is the
|
|
// lower 16 bits of the format code. The fields going across are WIA format GUID,
|
|
// string, and item type.
|
|
// Note: For associations, these fields depend on the type (e.g. burst, panorama)
|
|
//
|
|
|
|
FORMAT_INFO g_NonImageFormatInfo[] =
|
|
{
|
|
{ (GUID *)&WiaImgFmt_UNDEFINED, UnknownString, ITEMTYPE_FILE, L"" }, // Undefined
|
|
{ NULL, FolderString, ITEMTYPE_FOLDER, L"" }, // Association
|
|
{ (GUID *)&WiaImgFmt_SCRIPT, ScriptString, ITEMTYPE_FILE, L"" }, // Script
|
|
{ (GUID *)&WiaImgFmt_EXEC, ExecString, ITEMTYPE_FILE, L"EXE" }, // Executable
|
|
{ (GUID *)&WiaImgFmt_UNICODE16, TextString, ITEMTYPE_FILE, L"TXT" }, // Text
|
|
{ (GUID *)&WiaImgFmt_HTML, HtmlString, ITEMTYPE_FILE, L"HTM" }, // HTML
|
|
{ (GUID *)&WiaImgFmt_DPOF, DpofString, ITEMTYPE_FILE, L"" }, // DPOF
|
|
{ (GUID *)&WiaAudFmt_AIFF, AudioString, ITEMTYPE_AUDIO, L"AIF" }, // AIFF
|
|
{ (GUID *)&WiaAudFmt_WAV, AudioString, ITEMTYPE_AUDIO, L"WAV" }, // WAV
|
|
{ (GUID *)&WiaAudFmt_MP3, AudioString, ITEMTYPE_AUDIO, L"MP3" }, // MP3
|
|
{ (GUID *)&WiaImgFmt_AVI, VideoString, ITEMTYPE_VIDEO, L"AVI" }, // AVI
|
|
{ (GUID *)&WiaImgFmt_MPG, VideoString, ITEMTYPE_VIDEO, L"MPG" }, // MPEG
|
|
{ (GUID *)&WiaImgFmt_ASF, VideoString, ITEMTYPE_VIDEO, L"ASF" } // ASF
|
|
};
|
|
const UINT g_NumNonImageFormatInfo = sizeof(g_NonImageFormatInfo) / sizeof(g_NonImageFormatInfo[0]);
|
|
|
|
//
|
|
// Mapping of image PTP formats to format info structures. Index is the
|
|
// lower 16 bits of the format code.
|
|
//
|
|
FORMAT_INFO g_ImageFormatInfo[] =
|
|
{
|
|
{ NULL, UnknownImgString, ITEMTYPE_IMAGE, L"" }, // Undefined image
|
|
{ (GUID *)&WiaImgFmt_JPEG, ImageString, ITEMTYPE_IMAGE, L"JPG" }, // EXIF/JPEG
|
|
{ (GUID *)&WiaImgFmt_TIFF, ImageString, ITEMTYPE_IMAGE, L"TIF" }, // TIFF/EP
|
|
{ (GUID *)&WiaImgFmt_FLASHPIX, ImageString, ITEMTYPE_IMAGE, L"FPX" }, // FlashPix
|
|
{ (GUID *)&WiaImgFmt_BMP, ImageString, ITEMTYPE_IMAGE, L"BMP" }, // BMP
|
|
{ (GUID *)&WiaImgFmt_CIFF, ImageString, ITEMTYPE_IMAGE, L"TIF" }, // CIFF
|
|
{ NULL, UnknownString, ITEMTYPE_IMAGE, L"" }, // Undefined (Reserved)
|
|
{ (GUID *)&WiaImgFmt_GIF, ImageString, ITEMTYPE_IMAGE, L"GIF" }, // GIF
|
|
{ (GUID *)&WiaImgFmt_JPEG, ImageString, ITEMTYPE_IMAGE, L"JPG" }, // JFIF
|
|
{ (GUID *)&WiaImgFmt_PHOTOCD, ImageString, ITEMTYPE_IMAGE, L"PCD" }, // PCD (PhotoCD Image Pac)
|
|
{ (GUID *)&WiaImgFmt_PICT, ImageString, ITEMTYPE_IMAGE, L"" }, // PICT
|
|
{ (GUID *)&WiaImgFmt_PNG, ImageString, ITEMTYPE_IMAGE, L"PNG" }, // PNG
|
|
{ NULL, UnknownString, ITEMTYPE_IMAGE, L"" }, // Undefined (Reserved)
|
|
{ (GUID *)&WiaImgFmt_TIFF, ImageString, ITEMTYPE_IMAGE, L"TIF" }, // TIFF
|
|
{ (GUID *)&WiaImgFmt_TIFF, ImageString, ITEMTYPE_IMAGE, L"TIF" }, // TIFF/IT
|
|
{ (GUID *)&WiaImgFmt_JPEG2K, ImageString, ITEMTYPE_IMAGE, L"" }, // JPEG2000 Baseline
|
|
{ (GUID *)&WiaImgFmt_JPEG2KX, ImageString, ITEMTYPE_IMAGE, L"" } // JPEG2000 Extended
|
|
};
|
|
const UINT g_NumImageFormatInfo = sizeof(g_ImageFormatInfo) / sizeof(g_ImageFormatInfo[0]);
|
|
|
|
//
|
|
// Mapping of association types to format info structures.
|
|
//
|
|
FORMAT_INFO g_AssocFormatInfo[] =
|
|
{
|
|
{ NULL, UnknownString, ITEMTYPE_FOLDER }, // Undefined
|
|
{ NULL, FolderString, ITEMTYPE_FOLDER }, // Generic folder
|
|
{ NULL, AlbumString, ITEMTYPE_FOLDER }, // Album
|
|
{ NULL, BurstString, ITEMTYPE_BURST }, // Time burst
|
|
{ NULL, PanoramaString, ITEMTYPE_HPAN }, // Horizontal panorama
|
|
{ NULL, PanoramaString, ITEMTYPE_VPAN }, // Vertical panorama
|
|
{ NULL, PanoramaString, ITEMTYPE_FOLDER }, // 2D panorama
|
|
{ NULL, FolderString, ITEMTYPE_FOLDER } // Ancillary data
|
|
};
|
|
const UINT g_NumAssocFormatInfo = sizeof(g_AssocFormatInfo) / sizeof(g_AssocFormatInfo[0]);
|
|
|
|
//
|
|
// Mapping of property codes to property info structures. Index is the lower 12 bites of the
|
|
// prop code. The fields going across are WIA property ID, and WIA property string.
|
|
//
|
|
PROP_INFO g_PropInfo[] =
|
|
{
|
|
{ 0, NULL }, // Undefined property code
|
|
{ WIA_DPC_BATTERY_STATUS, WIA_DPC_BATTERY_STATUS_STR },
|
|
{ 0, NULL }, // Functional mode, not used
|
|
{ 0, NULL }, // Image capture dimensions (needs special processing)
|
|
{ WIA_DPC_COMPRESSION_SETTING, WIA_DPC_COMPRESSION_SETTING_STR },
|
|
{ WIA_DPC_WHITE_BALANCE, WIA_DPC_WHITE_BALANCE_STR },
|
|
{ WIA_DPC_RGB_GAIN, WIA_DPC_RGB_GAIN_STR },
|
|
{ WIA_DPC_FNUMBER, WIA_DPC_FNUMBER_STR },
|
|
{ WIA_DPC_FOCAL_LENGTH, WIA_DPC_FOCAL_LENGTH_STR },
|
|
{ WIA_DPC_FOCUS_DISTANCE, WIA_DPC_FOCUS_DISTANCE_STR },
|
|
{ WIA_DPC_FOCUS_MODE, WIA_DPC_FOCUS_MODE_STR },
|
|
{ WIA_DPC_EXPOSURE_METERING_MODE, WIA_DPC_EXPOSURE_METERING_MODE_STR },
|
|
{ WIA_DPC_FLASH_MODE, WIA_DPC_FLASH_MODE_STR },
|
|
{ WIA_DPC_EXPOSURE_TIME, WIA_DPC_EXPOSURE_TIME_STR },
|
|
{ WIA_DPC_EXPOSURE_MODE, WIA_DPC_EXPOSURE_MODE_STR },
|
|
{ WIA_DPC_EXPOSURE_INDEX, WIA_DPC_EXPOSURE_INDEX_STR },
|
|
{ WIA_DPC_EXPOSURE_COMP, WIA_DPC_EXPOSURE_COMP_STR },
|
|
{ WIA_DPA_DEVICE_TIME, WIA_DPA_DEVICE_TIME_STR },
|
|
{ WIA_DPC_CAPTURE_DELAY, WIA_DPC_CAPTURE_DELAY_STR },
|
|
{ WIA_DPC_CAPTURE_MODE, WIA_DPC_CAPTURE_MODE_STR },
|
|
{ WIA_DPC_CONTRAST, WIA_DPC_CONTRAST_STR },
|
|
{ WIA_DPC_SHARPNESS, WIA_DPC_SHARPNESS_STR },
|
|
{ WIA_DPC_DIGITAL_ZOOM, WIA_DPC_DIGITAL_ZOOM_STR },
|
|
{ WIA_DPC_EFFECT_MODE, WIA_DPC_EFFECT_MODE_STR },
|
|
{ WIA_DPC_BURST_NUMBER, WIA_DPC_BURST_NUMBER_STR },
|
|
{ WIA_DPC_BURST_INTERVAL, WIA_DPC_BURST_INTERVAL_STR },
|
|
{ WIA_DPC_TIMELAPSE_NUMBER, WIA_DPC_TIMELAPSE_NUMBER_STR },
|
|
{ WIA_DPC_TIMELAPSE_INTERVAL, WIA_DPC_TIMELAPSE_INTERVAL_STR },
|
|
{ WIA_DPC_FOCUS_METERING_MODE, WIA_DPC_FOCUS_METERING_MODE_STR },
|
|
{ WIA_DPC_UPLOAD_URL, WIA_DPC_UPLOAD_URL_STR },
|
|
{ WIA_DPC_ARTIST, WIA_DPC_ARTIST_STR },
|
|
{ WIA_DPC_COPYRIGHT_INFO, WIA_DPC_COPYRIGHT_INFO_STR }
|
|
};
|
|
|
|
const UINT g_NumPropInfo = sizeof(g_PropInfo) / sizeof(g_PropInfo[0]);
|
|
|
|
//
|
|
// Helper function - returns number of logical storages (those which have
|
|
// StorageId & PTP_STORAGEID_LOGICAL > 0)
|
|
//
|
|
int CWiaMiniDriver::NumLogicalStorages()
|
|
{
|
|
DBG_FN("CWiaMiniDriver::NumLogicalStorages");
|
|
|
|
int nResult = 0;
|
|
for (int i = 0; i < m_StorageIds.GetSize(); i++)
|
|
{
|
|
if (m_StorageIds[i] & PTP_STORAGEID_LOGICAL)
|
|
{
|
|
nResult++;
|
|
}
|
|
}
|
|
return nResult;
|
|
}
|
|
|
|
//
|
|
// This function creates the driver item tree
|
|
//
|
|
// Input:
|
|
// RootItemFullName -- the root item full name
|
|
// ppRoot -- to receive the root driver item
|
|
//
|
|
HRESULT
|
|
CWiaMiniDriver::CreateDrvItemTree(IWiaDrvItem **ppRoot)
|
|
{
|
|
DBG_FN("CWiaMiniDriver::CreateDrvItemTree");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
DRVITEM_CONTEXT *pDrvItemContext;
|
|
|
|
if (!ppRoot)
|
|
{
|
|
wiauDbgError("CreateDrvItemTree", "invalid arg");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Create the root item name
|
|
//
|
|
BSTR bstrRoot = SysAllocString(L"Root");
|
|
if (!bstrRoot)
|
|
{
|
|
wiauDbgError("CreateDrvItemTree", "memory allocation failed");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Create the root item.
|
|
//
|
|
*ppRoot = NULL;
|
|
pDrvItemContext = NULL;
|
|
hr = wiasCreateDrvItem(WiaItemTypeDevice | WiaItemTypeRoot | WiaItemTypeFolder,
|
|
bstrRoot,
|
|
m_bstrRootItemFullName,
|
|
(IWiaMiniDrv *)this,
|
|
sizeof(DRVITEM_CONTEXT),
|
|
(BYTE **) &pDrvItemContext,
|
|
ppRoot
|
|
);
|
|
|
|
SysFreeString(bstrRoot);
|
|
|
|
if (FAILED(hr) || !*ppRoot || !pDrvItemContext)
|
|
{
|
|
wiauDbgError("CreateDrvItemTree", "wiasCreateDrvItem failed");
|
|
return hr;
|
|
}
|
|
|
|
pDrvItemContext->pObjectInfo = NULL;
|
|
pDrvItemContext->NumFormatInfos = 0;
|
|
pDrvItemContext->pFormatInfos = NULL;
|
|
|
|
pDrvItemContext->ThumbSize = 0;
|
|
pDrvItemContext->pThumb = NULL;
|
|
|
|
//
|
|
// Clear the handle/driver item mapping (it might be non-empty if camera was reset, see bug #685926)
|
|
//
|
|
m_HandleItem.RemoveAll();
|
|
|
|
//
|
|
// Add an entry in the object handle/driver item association mapping for the root
|
|
//
|
|
if (!m_HandleItem.Add(0, *ppRoot))
|
|
{
|
|
wiauDbgError("CreateDrvItemTree", "memory allocation failed");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Now create all the other items by looping through the list of all of the object
|
|
// handles on the device
|
|
//
|
|
CArray32 ObjectHandleList;
|
|
|
|
if (NumLogicalStorages() > 0)
|
|
{
|
|
hr = m_pPTPCamera->GetObjectHandles(PTP_STORAGEID_ALL, PTP_FORMATCODE_ALL, PTP_OBJECTHANDLE_ALL,
|
|
&ObjectHandleList);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("CreateDrvItemTree", "GetObjectHandles failed");
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// In order to fill drv items tree correctly, get information for all objects, and add them
|
|
// in order of depth (closest to the root first)
|
|
//
|
|
CWiaMap<DWORD, CPtpObjectInfo*> HandleToInfoMap;
|
|
UINT nItems = ObjectHandleList.GetSize();
|
|
|
|
CPtpObjectInfo *ObjectInfoList = new CPtpObjectInfo[nItems];
|
|
BYTE *DepthList = new BYTE[nItems];
|
|
if (ObjectInfoList == NULL || DepthList == NULL)
|
|
{
|
|
wiauDbgError("CreateDrvItemTree", "memory allocation failed");
|
|
hr = E_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Get the ObjectInfo for all objects
|
|
//
|
|
for (UINT i = 0; i < nItems; i++)
|
|
{
|
|
hr = m_pPTPCamera->GetObjectInfo(ObjectHandleList[i], &ObjectInfoList[i]);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("CreateDrvItemTree", "GetObjectInfo failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!HandleToInfoMap.Add(ObjectHandleList[i], &ObjectInfoList[i]))
|
|
{
|
|
wiauDbgError("CreateDrvItemTree", "failed to item to Handle-ObjectInfo map");
|
|
hr = E_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find depth of every object
|
|
//
|
|
for (i = 0; i < nItems; i++)
|
|
{
|
|
DepthList[i] = 0;
|
|
DWORD CurHandle = ObjectHandleList[i];
|
|
while (CurHandle = HandleToInfoMap.Lookup(CurHandle)->m_ParentHandle)
|
|
{
|
|
DepthList[i]++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add objects in order of depth (closest to the root first)
|
|
//
|
|
UINT nItemsAdded = 0;
|
|
UINT CurDepth = 0;
|
|
while (nItemsAdded < nItems)
|
|
{
|
|
for (i = 0; i < nItems; i++)
|
|
{
|
|
if (DepthList[i] == CurDepth)
|
|
{
|
|
hr = AddObject(ObjectHandleList[i], FALSE, &ObjectInfoList[i]);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("CreateDrvItemTree", "AddObject failed");
|
|
goto cleanup;
|
|
}
|
|
nItemsAdded++;
|
|
}
|
|
}
|
|
CurDepth++;
|
|
}
|
|
|
|
cleanup:
|
|
if (ObjectInfoList)
|
|
{
|
|
delete[] ObjectInfoList;
|
|
}
|
|
|
|
if (DepthList)
|
|
{
|
|
delete[] DepthList;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// This function adds an object to the driver item tree
|
|
//
|
|
// Input:
|
|
// ObjectHandle -- PTP handle for the object
|
|
// bQueueEvent -- TRUE if WIA event should be queued
|
|
// pObjectInfo -- optional ObjectInfo for this object. If NULL, info will be queried from camera
|
|
//
|
|
HRESULT
|
|
CWiaMiniDriver::AddObject(
|
|
DWORD ObjectHandle,
|
|
BOOL bQueueEvent,
|
|
CPtpObjectInfo *pProvidedObjectInfo
|
|
)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
DBG_FN("CWiaMiniDriver::AddObject");
|
|
|
|
HRESULT hr = S_OK;
|
|
CPtpObjectInfo *pObjectInfo = NULL;
|
|
BSTR bstrItemFullName = NULL;
|
|
BSTR bstrParentName = NULL;
|
|
IWiaDrvItem *pItem = NULL;
|
|
|
|
//
|
|
// flag to indicate if pObjecInfo pointer has been copied to WiaDrvItem
|
|
// if TRUE, it should not be deleted in Cleanup
|
|
//
|
|
BOOL fObjectInfoUsed = FALSE;
|
|
|
|
//
|
|
// Get the ObjectInfo from camera or use provided info if it's given
|
|
//
|
|
if (pProvidedObjectInfo == NULL)
|
|
{
|
|
pObjectInfo = new CPtpObjectInfo;
|
|
if (!pObjectInfo)
|
|
{
|
|
wiauDbgError("AddObject", "memory allocation failed");
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = m_pPTPCamera->GetObjectInfo(ObjectHandle, pObjectInfo);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("AddObject", "GetObjectInfo failed");
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pObjectInfo = new CPtpObjectInfo(*pProvidedObjectInfo); // default copying constructor
|
|
if (!pObjectInfo)
|
|
{
|
|
wiauDbgError("AddObject", "memory allocation failed");
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
int storeIdx = m_StorageIds.Find(pObjectInfo->m_StorageId);
|
|
|
|
//
|
|
// Look for objects to hide if this is a DCF store
|
|
//
|
|
if (m_StorageInfos[storeIdx].m_FileSystemType == PTP_FILESYSTEMTYPE_DCF)
|
|
{
|
|
BOOL bHideObject = FALSE;
|
|
|
|
//
|
|
// If the DCIM folder has been identified and this is a folder under DCIM, hide it
|
|
//
|
|
if (m_DcimHandle[storeIdx])
|
|
{
|
|
if (pObjectInfo->m_ParentHandle == m_DcimHandle[storeIdx])
|
|
bHideObject = TRUE;
|
|
}
|
|
|
|
//
|
|
// Otherwise see if this is the DCIM folder
|
|
//
|
|
else if (wcscmp(pObjectInfo->m_cbstrFileName.String(), L"DCIM") == 0)
|
|
{
|
|
bHideObject = TRUE;
|
|
m_DcimHandle[storeIdx] = ObjectHandle;
|
|
}
|
|
|
|
if (bHideObject)
|
|
{
|
|
//
|
|
// Create a dummy entry in the handle/item map so that objects under this
|
|
// folder will be put under the root
|
|
//
|
|
if (!m_HandleItem.Add(ObjectHandle, m_pDrvItemRoot))
|
|
{
|
|
wiauDbgError("AddObject", "add handle item failed");
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
wiauDbgTrace("AddObject", "hiding DCIM folder 0x%08x", ObjectHandle);
|
|
hr = S_OK;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If this is an "ancillary data" association, don't create an item but put the handle
|
|
// in the ancillary association array
|
|
//
|
|
if (pObjectInfo->m_AssociationType == PTP_ASSOCIATIONTYPE_ANCILLARYDATA)
|
|
{
|
|
if (!m_AncAssocParent.Add(ObjectHandle, m_HandleItem.Lookup(pObjectInfo->m_ParentHandle)))
|
|
{
|
|
wiauDbgError("AddObject", "add ancillary assoc handle failed");
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = S_OK;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Keep count of the number of images
|
|
//
|
|
UINT16 FormatCode = pObjectInfo->m_FormatCode;
|
|
if (FormatCode & PTP_FORMATMASK_IMAGE)
|
|
{
|
|
m_NumImages++;
|
|
|
|
//
|
|
// Also make sure that the bit depth is non-zero.
|
|
//
|
|
if (pObjectInfo->m_ImageBitDepth == 0) {
|
|
switch(pObjectInfo->m_FormatCode) {
|
|
case PTP_FORMATCODE_IMAGE_GIF:
|
|
pObjectInfo->m_ImageBitDepth = 8;
|
|
break;
|
|
default:
|
|
pObjectInfo->m_ImageBitDepth = 24;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update Storage Info (we are especially interested in Free Space info)
|
|
//
|
|
hr = UpdateStorageInfo(pObjectInfo->m_StorageId);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("AddObject", "UpdateStorageInfo failed");
|
|
// we can proceed, even if storage info can't be updated
|
|
hr = S_OK;
|
|
}
|
|
|
|
//
|
|
// For images, check to see if the parent is an ancillary association
|
|
//
|
|
IWiaDrvItem *pParent = NULL;
|
|
LONG ExtraItemFlags = 0;
|
|
int ancIdx = m_AncAssocParent.FindKey(pObjectInfo->m_ParentHandle);
|
|
if ((FormatCode & PTP_FORMATMASK_IMAGE) &&
|
|
(ancIdx >= 0))
|
|
{
|
|
ExtraItemFlags |= WiaItemTypeHasAttachments;
|
|
pParent = m_AncAssocParent.GetValueAt(ancIdx);
|
|
}
|
|
|
|
//
|
|
// For normal images, just look up the parent item in the map
|
|
//
|
|
else
|
|
{
|
|
pParent = m_HandleItem.Lookup(pObjectInfo->m_ParentHandle);
|
|
}
|
|
|
|
//
|
|
// If a parent wasn't found, just use the root as the parent
|
|
//
|
|
if (!pParent)
|
|
{
|
|
pParent = m_pDrvItemRoot;
|
|
}
|
|
|
|
//
|
|
// Look up info about the object's format
|
|
//
|
|
FORMAT_INFO *pFormatInfo = FormatCodeToFormatInfo(FormatCode, pObjectInfo->m_AssociationType);
|
|
|
|
//
|
|
// Get the item's name, generating it if necessary
|
|
//
|
|
CBstr *pFileName = &(pObjectInfo->m_cbstrFileName);
|
|
TCHAR tcsName[MAX_PATH];
|
|
TCHAR *ptcsDot;
|
|
|
|
if (pFileName->Length() == 0)
|
|
{
|
|
hr = StringCchPrintf(tcsName, ARRAYSIZE(tcsName), W2T(pFormatInfo->FormatString), ObjectHandle);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgErrorHr(hr, "AddObject", "StringCchPrintf failed");
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = pFileName->Copy(T2W(tcsName));
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("AddObject", "CBstr::Copy failed");
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// For images Chop off the filename extension, if it exists
|
|
//
|
|
WCHAR *pDot = wcsrchr(pFileName->String(), L'.');
|
|
if (pDot)
|
|
{
|
|
// Copy extension first
|
|
hr = pObjectInfo->m_cbstrExtension.Copy(pDot + 1);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("AddObject", "copy string failed");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// then remove the extension from the item name
|
|
hr = StringCchCopy(tcsName, ARRAYSIZE(tcsName), W2T(pFileName->String()));
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgErrorHr(hr, "AddObject", "StringCchCopy failed");
|
|
goto Cleanup;
|
|
}
|
|
|
|
ptcsDot = _tcsrchr(tcsName, TEXT('.'));
|
|
*ptcsDot = TEXT('\0');
|
|
|
|
hr = pFileName->Copy(T2W(tcsName));
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("AddObject", "copy string failed");
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
if(pObjectInfo->m_cbstrExtension.Length()) {
|
|
// this is special-case handling of .MOV files for which we
|
|
// don't have GUID, but which need to be treated as video
|
|
// elsewhere
|
|
if(_wcsicmp(pObjectInfo->m_cbstrExtension.String(), L"MOV") == 0) {
|
|
pFormatInfo->ItemType = ITEMTYPE_VIDEO;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create the item's full name
|
|
//
|
|
hr = pParent->GetFullItemName(&bstrParentName);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("AddObject", "GetFullItemName failed");
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = StringCchPrintf(tcsName, ARRAYSIZE(tcsName), TEXT("%s\\%s"), W2T(bstrParentName), W2T(pFileName->String()));
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgErrorHr(hr, "AddObject", "StringCchPrintf failed");
|
|
goto Cleanup;
|
|
}
|
|
|
|
bstrItemFullName = SysAllocString(T2W(tcsName));
|
|
if (!bstrItemFullName)
|
|
{
|
|
wiauDbgError("AddObject", "memory allocation failed");
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Create the driver item
|
|
//
|
|
DRVITEM_CONTEXT *pDrvItemContext = NULL;
|
|
hr = wiasCreateDrvItem(pFormatInfo->ItemType | ExtraItemFlags,
|
|
pFileName->String(),
|
|
bstrItemFullName,
|
|
(IWiaMiniDrv *)this,
|
|
sizeof(DRVITEM_CONTEXT),
|
|
(BYTE **) &pDrvItemContext,
|
|
&pItem);
|
|
|
|
if (FAILED(hr) || !pItem || !pDrvItemContext)
|
|
{
|
|
wiauDbgError("AddObject", "wiasCreateDriverItem failed");
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Fill in the driver item context. Wait until the thumbnail is requested before
|
|
// reading it in.
|
|
//
|
|
pDrvItemContext->pObjectInfo = pObjectInfo;
|
|
fObjectInfoUsed = TRUE; // indicate that pObjectInfo pointer has been copied and should not be freed
|
|
pDrvItemContext->NumFormatInfos = 0;
|
|
pDrvItemContext->pFormatInfos = NULL;
|
|
|
|
pDrvItemContext->ThumbSize = 0;
|
|
pDrvItemContext->pThumb = NULL;
|
|
|
|
//
|
|
// Place the new item under it's parent
|
|
//
|
|
hr = pItem->AddItemToFolder(pParent);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("AddObject", "AddItemToFolder failed");
|
|
pItem->Release();
|
|
pItem = NULL;
|
|
fObjectInfoUsed = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Add the object handle/driver item association to the list
|
|
//
|
|
if (!m_HandleItem.Add(ObjectHandle, pItem))
|
|
{
|
|
wiauDbgError("AddObject", "memory allocation failed");
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If this image is replacing an ancillary association folder, put another entry
|
|
// in the object handle/item map for that folder
|
|
//
|
|
if (ancIdx >= 0)
|
|
{
|
|
if (!m_HandleItem.Add(pObjectInfo->m_ParentHandle, pItem))
|
|
{
|
|
wiauDbgError("AddObject", "memory allocation failed");
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Post an item added event, if requested
|
|
//
|
|
if (bQueueEvent)
|
|
{
|
|
hr = wiasQueueEvent(m_bstrDeviceId, &WIA_EVENT_ITEM_CREATED, bstrItemFullName);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("AddObject", "wiasQueueEvent failed");
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
//
|
|
// Delete pObjectInfo only if the pointer was not copied to WiaDrvItem
|
|
//
|
|
if (pObjectInfo && !fObjectInfoUsed)
|
|
{
|
|
delete pObjectInfo;
|
|
pObjectInfo = NULL;
|
|
}
|
|
|
|
if (bstrParentName)
|
|
{
|
|
SysFreeString(bstrParentName);
|
|
bstrParentName = NULL;
|
|
}
|
|
|
|
if (bstrItemFullName)
|
|
{
|
|
SysFreeString(bstrItemFullName);
|
|
bstrItemFullName = NULL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// This function initializes device properties
|
|
//
|
|
// Input:
|
|
// pWiasContext -- wias context
|
|
//
|
|
HRESULT
|
|
CWiaMiniDriver::InitDeviceProperties(BYTE *pWiasContext)
|
|
{
|
|
DBG_FN("CWiaMiniDriver::InitDeviceProperties");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
const INT NUM_ROOT_PROPS = 12;
|
|
|
|
//
|
|
// Define things here that need to live until SendToWia() is called
|
|
//
|
|
CArray32 widthList, heightList; // Used by code that split image width and height
|
|
SYSTEMTIME SystemTime; // Used for device time
|
|
int NumFormats = 0; // Used by format setting code
|
|
LPGUID *pFormatGuids = NULL; // Used by format setting code
|
|
FORMAT_INFO *pFormatInfo = NULL; // Used by format setting code
|
|
int FormatCount = 0; // Used by format setting code
|
|
|
|
//
|
|
// Create the property list for the device
|
|
//
|
|
CWiauPropertyList RootProps;
|
|
CArray16 *pSupportedProps = &m_DeviceInfo.m_SupportedProps;
|
|
|
|
hr = RootProps.Init(pSupportedProps->GetSize() + NUM_ROOT_PROPS);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("InitDeviceProperties", "Init failed");
|
|
return hr;
|
|
}
|
|
|
|
INT index;
|
|
int count;
|
|
|
|
//
|
|
// WIA_IPA_ACCESS_RIGHTS
|
|
//
|
|
hr = RootProps.DefineProperty(&index, WIA_IPA_ACCESS_RIGHTS, WIA_IPA_ACCESS_RIGHTS_STR,
|
|
WIA_PROP_READ, WIA_PROP_NONE);
|
|
if (FAILED(hr)) goto failure;
|
|
RootProps.SetCurrentValue(index, (LONG) WIA_ITEM_READ|WIA_ITEM_WRITE);
|
|
|
|
//
|
|
// WIA_DPA_FIRMWARE_VERSION
|
|
//
|
|
hr = RootProps.DefineProperty(&index, WIA_DPA_FIRMWARE_VERSION, WIA_DPA_FIRMWARE_VERSION_STR,
|
|
WIA_PROP_READ, WIA_PROP_NONE);
|
|
if (FAILED(hr)) goto failure;
|
|
RootProps.SetCurrentValue(index, m_DeviceInfo.m_cbstrDeviceVersion.String());
|
|
|
|
//
|
|
// WIA_DPC_PICTURES_TAKEN
|
|
//
|
|
hr = RootProps.DefineProperty(&index, WIA_DPC_PICTURES_TAKEN, WIA_DPC_PICTURES_TAKEN_STR,
|
|
WIA_PROP_READ, WIA_PROP_NONE);
|
|
if (FAILED(hr)) goto failure;
|
|
RootProps.SetCurrentValue(index, m_NumImages);
|
|
|
|
//
|
|
// WIA_DPC_PICTURES_REMAINING
|
|
//
|
|
hr = RootProps.DefineProperty(&index, WIA_DPC_PICTURES_REMAINING, WIA_DPC_PICTURES_REMAINING_STR,
|
|
WIA_PROP_READ, WIA_PROP_NONE);
|
|
if (FAILED(hr)) goto failure;
|
|
RootProps.SetCurrentValue(index, GetTotalFreeImageSpace());
|
|
|
|
//
|
|
// WIA_IPA_FORMAT -- Translate from the CaptureFormats field of DeviceInfo
|
|
//
|
|
hr = RootProps.DefineProperty(&index, WIA_IPA_FORMAT, WIA_IPA_FORMAT_STR,
|
|
WIA_PROP_READ, WIA_PROP_NONE);
|
|
if (FAILED(hr)) goto failure;
|
|
|
|
NumFormats = m_DeviceInfo.m_SupportedCaptureFmts.GetSize();
|
|
pFormatGuids = new LPGUID[NumFormats];
|
|
FormatCount = 0;
|
|
|
|
if (!pFormatGuids)
|
|
{
|
|
wiauDbgError("InitDeviceProperties", "memory allocation failed");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
for (count = 0; count < NumFormats; count++)
|
|
{
|
|
pFormatInfo = FormatCodeToFormatInfo(m_DeviceInfo.m_SupportedCaptureFmts[count]);
|
|
if (pFormatInfo->FormatGuid != NULL)
|
|
pFormatGuids[FormatCount++] = pFormatInfo->FormatGuid;
|
|
}
|
|
|
|
//
|
|
// Kodak DC4800 needs to have WIA_IPA_FORMAT set to JPEG. This hack can be removed
|
|
// only if support of DC4800 is removed
|
|
//
|
|
if (m_pPTPCamera && m_pPTPCamera->GetHackModel() == HACK_MODEL_DC4800)
|
|
{
|
|
RootProps.SetCurrentValue(index, (CLSID *) &WiaImgFmt_JPEG);
|
|
}
|
|
|
|
else if (FormatCount == 1)
|
|
{
|
|
RootProps.SetCurrentValue(index, pFormatGuids[0]);
|
|
}
|
|
|
|
else if (FormatCount > 1)
|
|
{
|
|
RootProps.SetAccessSubType(index, WIA_PROP_RW, WIA_PROP_NONE);
|
|
RootProps.SetValidValues(index, pFormatGuids[0], pFormatGuids[0], FormatCount, pFormatGuids);
|
|
}
|
|
|
|
else
|
|
wiauDbgWarning("InitDeviceProperties", "Device has no valid formats");
|
|
|
|
delete []pFormatGuids;
|
|
|
|
//
|
|
// Loop through PTP property description structures, translating them to WIA properties
|
|
//
|
|
PPROP_INFO pPropInfo;
|
|
ULONG Access;
|
|
ULONG SubType;
|
|
|
|
for (count = 0; count < m_PropDescs.GetSize(); count++)
|
|
{
|
|
CPtpPropDesc *pCurrentPD = &m_PropDescs[count];
|
|
WORD PropCode = pCurrentPD->m_PropCode;
|
|
|
|
//
|
|
// Set the property access and subtype
|
|
//
|
|
if (pCurrentPD->m_GetSet == PTP_PROPGETSET_GETSET)
|
|
{
|
|
Access = WIA_PROP_RW;
|
|
|
|
if (pCurrentPD->m_FormFlag == PTP_FORMFLAGS_NONE)
|
|
{
|
|
//
|
|
// If property is writeable and valid values are not a list or a range, set subtype to
|
|
// WIA_PROP_NONE now
|
|
//
|
|
SubType = WIA_PROP_NONE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If property is writable and valid values are a list or a range, valid subtype will
|
|
// be set during a call to overloaded SetCurrentValue.
|
|
//
|
|
SubType = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If property is read-only, it's subtype is always WIA_PROP_NONE
|
|
//
|
|
Access = WIA_PROP_READ;
|
|
SubType = WIA_PROP_NONE;
|
|
}
|
|
|
|
//
|
|
// Process image capture dimensions separately, since they are in a string
|
|
//
|
|
if (PropCode == PTP_PROPERTYCODE_IMAGESIZE)
|
|
{
|
|
//
|
|
// Define separate properties for image width and height
|
|
//
|
|
hr = RootProps.DefineProperty(&index, WIA_DPC_PICT_WIDTH, WIA_DPC_PICT_WIDTH_STR, Access, SubType);
|
|
if (FAILED(hr)) goto failure;
|
|
|
|
hr = RootProps.DefineProperty(&index, WIA_DPC_PICT_HEIGHT, WIA_DPC_PICT_HEIGHT_STR, Access, SubType);
|
|
if (FAILED(hr)) goto failure;
|
|
|
|
LONG curWidth, curHeight;
|
|
SplitImageSize(pCurrentPD->m_cbstrCurrent, &curWidth, &curHeight);
|
|
|
|
//
|
|
// If the image capture size property is read-only, just set the current values
|
|
//
|
|
if (Access == WIA_PROP_READ)
|
|
{
|
|
RootProps.SetCurrentValue(index-1, curWidth);
|
|
RootProps.SetCurrentValue(index, curHeight);
|
|
}
|
|
|
|
//
|
|
// Otherwise, set the valid values too
|
|
//
|
|
else
|
|
{
|
|
//
|
|
// Convert default values
|
|
//
|
|
LONG defWidth, defHeight;
|
|
SplitImageSize(pCurrentPD->m_cbstrDefault, &defWidth, &defHeight);
|
|
|
|
if (pCurrentPD->m_FormFlag == PTP_FORMFLAGS_RANGE)
|
|
{
|
|
//
|
|
// Convert max, min, and step
|
|
//
|
|
LONG minWidth, minHeight, maxWidth, maxHeight, stepWidth, stepHeight;
|
|
SplitImageSize(pCurrentPD->m_cbstrRangeMin, &minWidth, &minHeight);
|
|
SplitImageSize(pCurrentPD->m_cbstrRangeMax, &maxWidth, &maxHeight);
|
|
SplitImageSize(pCurrentPD->m_cbstrRangeStep, &stepWidth, &stepHeight);
|
|
|
|
RootProps.SetValidValues(index-1, defWidth, curWidth, minWidth, maxWidth, stepWidth);
|
|
RootProps.SetValidValues(index, defHeight, curHeight, minHeight, maxHeight, stepHeight);
|
|
}
|
|
else if (pCurrentPD->m_FormFlag == PTP_FORMFLAGS_ENUM)
|
|
{
|
|
//
|
|
// Convert list of strings
|
|
//
|
|
ULONG width, height;
|
|
|
|
int numElem = pCurrentPD->m_NumValues;
|
|
|
|
if (!widthList.GrowTo(numElem) ||
|
|
!heightList.GrowTo(numElem))
|
|
{
|
|
wiauDbgError("InitDeviceProperties", "memory allocation failed");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
for (int countVals = 0; countVals < numElem; countVals++)
|
|
{
|
|
SplitImageSize(pCurrentPD->m_cbstrValues[countVals], (LONG*) &width, (LONG*) &height);
|
|
|
|
if (!widthList.Add(width) ||
|
|
!heightList.Add(height))
|
|
{
|
|
wiauDbgError("InitDeviceProperties", "error adding width or height");
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
RootProps.SetValidValues(index-1, defWidth, curWidth, numElem, (LONG *) widthList.GetData());
|
|
RootProps.SetValidValues(index, defHeight, curHeight, numElem, (LONG *) heightList.GetData());
|
|
}
|
|
}
|
|
|
|
continue;
|
|
|
|
} // if (PropCode == PTP_PROPERTYCODE_IMAGESIZE)
|
|
|
|
//
|
|
// Look up the property info structure, which contains the WIA prop id and string
|
|
//
|
|
pPropInfo = PropCodeToPropInfo(PropCode);
|
|
if (!pPropInfo->PropId)
|
|
{
|
|
wiauDbgError("InitDeviceProperties", "property code not found in array, 0x%04x", PropCode);
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Define the property based on the fields in the property info structure
|
|
//
|
|
hr = RootProps.DefineProperty(&index, pPropInfo->PropId, pPropInfo->PropName, Access, SubType);
|
|
if (FAILED(hr)) goto failure;
|
|
|
|
//
|
|
// Handle the device date/time. Convert it to SYSTEMTIME and create the property, skipping the rest.
|
|
//
|
|
if (PropCode == PTP_PROPERTYCODE_DATETIME)
|
|
{
|
|
hr = PtpTime2SystemTime(&(pCurrentPD->m_cbstrCurrent), &SystemTime);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("InitDeviceProperties", "invalid date/time string");
|
|
continue;
|
|
}
|
|
|
|
RootProps.SetCurrentValue(index, &SystemTime);
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Handle all other properties
|
|
//
|
|
if (Access == WIA_PROP_RW)
|
|
{
|
|
//
|
|
// Set the valid values for ranges
|
|
//
|
|
if (pCurrentPD->m_FormFlag == PTP_FORMFLAGS_RANGE)
|
|
{
|
|
//
|
|
// WIA can't handle string ranges, so handle just integers
|
|
//
|
|
if (pCurrentPD->m_DataType != PTP_DATATYPE_STRING)
|
|
RootProps.SetValidValues(index, (LONG) pCurrentPD->m_lDefault,
|
|
(LONG) pCurrentPD->m_lCurrent,
|
|
(LONG) pCurrentPD->m_lRangeMin,
|
|
(LONG) pCurrentPD->m_lRangeMax,
|
|
(LONG) pCurrentPD->m_lRangeStep);
|
|
}
|
|
|
|
//
|
|
// Set the valid values for lists
|
|
//
|
|
else if (pCurrentPD->m_FormFlag == PTP_FORMFLAGS_ENUM)
|
|
{
|
|
if (pCurrentPD->m_DataType == PTP_DATATYPE_STRING)
|
|
RootProps.SetValidValues(index, pCurrentPD->m_cbstrDefault.String(),
|
|
pCurrentPD->m_cbstrCurrent.String(),
|
|
pCurrentPD->m_NumValues,
|
|
(BSTR *) (pCurrentPD->m_cbstrValues.GetData()));
|
|
else
|
|
RootProps.SetValidValues(index, (LONG) pCurrentPD->m_lDefault,
|
|
(LONG) pCurrentPD->m_lCurrent,
|
|
pCurrentPD->m_NumValues,
|
|
(LONG *) (pCurrentPD->m_lValues.GetData()));
|
|
}
|
|
|
|
//
|
|
// Unrecognized form. Just set the current values
|
|
//
|
|
if (pCurrentPD->m_DataType == PTP_DATATYPE_STRING)
|
|
RootProps.SetCurrentValue(index, pCurrentPD->m_cbstrCurrent.String());
|
|
else
|
|
RootProps.SetCurrentValue(index, (LONG) pCurrentPD->m_lCurrent);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// For read-only properties, just set the current value
|
|
//
|
|
if (pCurrentPD->m_DataType == PTP_DATATYPE_STRING)
|
|
RootProps.SetCurrentValue(index, pCurrentPD->m_cbstrCurrent.String());
|
|
else
|
|
RootProps.SetCurrentValue(index, (LONG) pCurrentPD->m_lCurrent);
|
|
}
|
|
|
|
}
|
|
|
|
// Last step: send all the properties to WIA
|
|
|
|
hr = RootProps.SendToWia(pWiasContext);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgErrorHr(hr, "InitDeviceProperties", "SendToWia failed");
|
|
return hr;
|
|
}
|
|
|
|
return hr;
|
|
|
|
//
|
|
// Any failures from DefineProperty will end up here
|
|
//
|
|
|
|
failure:
|
|
wiauDbgErrorHr(hr, "InitDeviceProperties", "DefineProperty failed");
|
|
return hr;
|
|
}
|
|
|
|
// This function reads the device properties
|
|
//
|
|
// Input:
|
|
// pWiasContext -- wias context
|
|
// NumPropSpecs -- number of properties to be read
|
|
// pPropSpecs -- list of PROPSPEC that designates what properties to read
|
|
//
|
|
HRESULT
|
|
CWiaMiniDriver::ReadDeviceProperties(
|
|
BYTE *pWiasContext,
|
|
LONG NumPropSpecs,
|
|
const PROPSPEC *pPropSpecs
|
|
)
|
|
{
|
|
DBG_FN("CWiaMiniDriver::ReadDeviceProperties");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!NumPropSpecs || !pPropSpecs)
|
|
{
|
|
wiauDbgError("ReadDeviceProperties", "invalid arg");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Update the device properties
|
|
//
|
|
if (m_PropDescs.GetSize() > 0)
|
|
{
|
|
//
|
|
// Loop through all of the PropSpecs
|
|
//
|
|
for (int count = 0; count < NumPropSpecs; count++)
|
|
{
|
|
PROPID propId = pPropSpecs[count].propid;
|
|
|
|
//
|
|
// Update free image space, if requested
|
|
//
|
|
if (propId == WIA_DPC_PICTURES_REMAINING)
|
|
{
|
|
hr = wiasWritePropLong(pWiasContext, WIA_DPC_PICTURES_REMAINING, GetTotalFreeImageSpace());
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ReadDeviceProperties", "wiasWritePropLong failed");
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update pictures taken, if requested
|
|
//
|
|
else if (propId == WIA_DPC_PICTURES_TAKEN)
|
|
{
|
|
hr = wiasWritePropLong(pWiasContext, WIA_DPC_PICTURES_TAKEN, m_NumImages);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ReadDeviceProperties", "wiasWritePropLong failed");
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Image size is a special case property, which we handle here
|
|
//
|
|
else if (propId == WIA_DPC_PICT_WIDTH ||
|
|
propId == WIA_DPC_PICT_HEIGHT)
|
|
{
|
|
int propDescIdx = m_DeviceInfo.m_SupportedProps.Find(PTP_PROPERTYCODE_IMAGESIZE);
|
|
if (propDescIdx < 0)
|
|
continue;
|
|
|
|
LONG width, height;
|
|
SplitImageSize(m_PropDescs[propDescIdx].m_cbstrCurrent, &width, &height);
|
|
|
|
if (propId == WIA_DPC_PICT_WIDTH)
|
|
hr = wiasWritePropLong(pWiasContext, propId, width);
|
|
else
|
|
hr = wiasWritePropLong(pWiasContext, propId, height);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ReadDeviceProperties", "wiasWritePropLong failed");
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if the property is one that is contained in the PropSpec array
|
|
//
|
|
else
|
|
{
|
|
//
|
|
// Try to convert the WIA prop id to a PTP prop code
|
|
//
|
|
WORD propCode = PropIdToPropCode(propId);
|
|
if (propCode == 0)
|
|
continue;
|
|
|
|
//
|
|
// Try to find the prop code (and thus the prop desc structure) in the member array
|
|
//
|
|
int propDescIdx = m_DeviceInfo.m_SupportedProps.Find(propCode);
|
|
if (propDescIdx < 0)
|
|
continue;
|
|
|
|
//
|
|
// If it's the device time property, convert to SYSTEMTIME and write to WIA
|
|
//
|
|
if (propId == WIA_DPA_DEVICE_TIME)
|
|
{
|
|
hr = m_pPTPCamera->GetDevicePropValue(propCode, &m_PropDescs[propDescIdx]);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ReadDeviceProperties", "GetDevicePropValue failed");
|
|
return hr;
|
|
}
|
|
|
|
SYSTEMTIME st;
|
|
hr = PtpTime2SystemTime(&m_PropDescs[propDescIdx].m_cbstrCurrent, &st);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ReadDeviceProperties", "PtpTime2SystemTime failed");
|
|
return hr;
|
|
}
|
|
|
|
PROPVARIANT pv;
|
|
pv.vt = VT_UI2 | VT_VECTOR;
|
|
pv.caui.cElems = sizeof(SYSTEMTIME)/sizeof(WORD);
|
|
pv.caui.pElems = (USHORT *) &st;
|
|
|
|
PROPSPEC ps;
|
|
ps.ulKind = PRSPEC_PROPID;
|
|
ps.propid = propId;
|
|
|
|
hr = wiasWriteMultiple(pWiasContext, 1, &ps, &pv);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ReadDeviceProperties", "wiasWriteMultiple failed");
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it's a string property, write the updated value to WIA
|
|
//
|
|
else if (m_PropDescs[propDescIdx].m_DataType == PTP_DATATYPE_STRING)
|
|
{
|
|
hr = wiasWritePropStr(pWiasContext, propId,
|
|
m_PropDescs[propDescIdx].m_cbstrCurrent.String());
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ReadDeviceProperties", "wiasWritePropLong failed");
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it's an integer property, write the updated value to WIA
|
|
//
|
|
else
|
|
{
|
|
hr = wiasWritePropLong(pWiasContext, propId,
|
|
m_PropDescs[propDescIdx].m_lCurrent);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ReadDeviceProperties", "wiasWritePropLong failed");
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// This function does nothing, since the values were already sent to the device in ValidateDeviceProp
|
|
//
|
|
// Input:
|
|
// pWiasContext -- the WIA item context
|
|
// pmdtc -- the transfer context
|
|
//
|
|
HRESULT
|
|
CWiaMiniDriver::WriteDeviceProperties(
|
|
BYTE *pWiasContext
|
|
)
|
|
{
|
|
DBG_FN("CWiaMiniDriver::WriteDeviceProperties");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// This function validates device property current settings and writes them to the device. The
|
|
// settings need to be written here vs. WriteDeviceProperties in case the user unplugs the camera.
|
|
//
|
|
// Input:
|
|
// pWiasContext -- the item's context
|
|
// NumPropSpecs -- number of properties to be validated
|
|
// pPropSpecs -- properties to be validated
|
|
//
|
|
HRESULT
|
|
CWiaMiniDriver::ValidateDeviceProperties(
|
|
BYTE *pWiasContext,
|
|
LONG NumPropSpecs,
|
|
const PROPSPEC *pPropSpecs
|
|
)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
DBG_FN("CWiaMiniDriver::ValidateDeviceProperties");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Call WIA service helper to check against valid values
|
|
//
|
|
hr = wiasValidateItemProperties(pWiasContext, NumPropSpecs, pPropSpecs);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgWarning("ValidateDeviceProperties", "wiasValidateItemProperties failed");
|
|
return hr;
|
|
}
|
|
|
|
{
|
|
//
|
|
// Ensure exclusive access
|
|
//
|
|
CPtpMutex cpm(m_hPtpMutex);
|
|
|
|
PROPVARIANT *pPropVar = new PROPVARIANT[NumPropSpecs];
|
|
if (pPropVar == NULL)
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "memory allocation failed");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Read all of the new property values
|
|
//
|
|
hr = wiasReadMultiple(pWiasContext, NumPropSpecs, pPropSpecs, pPropVar, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "wiasReadMultiple failed");
|
|
delete []pPropVar;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// First do validation
|
|
//
|
|
LONG width = 0;
|
|
LONG height = 0;
|
|
|
|
for (int count = 0; count < NumPropSpecs; count++)
|
|
{
|
|
//
|
|
// Handle changes to the picture width
|
|
//
|
|
if (pPropSpecs[count].propid == WIA_DPC_PICT_WIDTH)
|
|
{
|
|
width = pPropVar[count].lVal;
|
|
height = 0;
|
|
|
|
//
|
|
// Look through the valid values and find the corresponding height
|
|
//
|
|
hr = FindCorrDimension(pWiasContext, &width, &height);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "FindCorrDimension failed");
|
|
delete []pPropVar;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// If the app is trying to set height, make sure it's correct
|
|
//
|
|
int idx;
|
|
if (wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_DPC_PICT_HEIGHT, &idx))
|
|
{
|
|
if (height != pPropVar[idx].lVal)
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "app attempting to set incorrect height");
|
|
delete []pPropVar;
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
hr = wiasWritePropLong(pWiasContext, WIA_DPC_PICT_HEIGHT, height);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "wiasWritePropLong failed");
|
|
delete []pPropVar;
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
} // if (pPropSpecs[count].propid == WIA_DPC_PICT_WIDTH)
|
|
|
|
|
|
//
|
|
// Handle changes to the picture height
|
|
//
|
|
else if (pPropSpecs[count].propid == WIA_DPC_PICT_HEIGHT)
|
|
{
|
|
//
|
|
// See if the app is trying to set width also. If so, the height has
|
|
// already been set, so don't set it again.
|
|
//
|
|
if (!wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_DPC_PICT_WIDTH))
|
|
{
|
|
width = 0;
|
|
height = pPropVar[count].lVal;
|
|
|
|
//
|
|
// Look through the valid values and find the corresponding width
|
|
//
|
|
hr = FindCorrDimension(pWiasContext, &width, &height);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "FindCorrDimension failed");
|
|
delete []pPropVar;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Set the width
|
|
//
|
|
hr = wiasWritePropLong(pWiasContext, WIA_DPC_PICT_WIDTH, width);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "wiasWritePropLong failed");
|
|
delete []pPropVar;
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
} // else if (pPropSpecs[count].propid == WIA_DPC_PICT_HEIGHT)
|
|
|
|
//
|
|
// Handle device time
|
|
//
|
|
else if (pPropSpecs[count].propid == WIA_DPA_DEVICE_TIME)
|
|
{
|
|
int propIndex = m_DeviceInfo.m_SupportedProps.Find(PTP_PROPERTYCODE_DATETIME);
|
|
CPtpPropDesc *pCurrentPD = &m_PropDescs[propIndex];
|
|
|
|
//
|
|
// Convert the date/time to a string
|
|
//
|
|
SYSTEMTIME *pSystemTime = (SYSTEMTIME *) pPropVar[count].caui.pElems;
|
|
hr = SystemTime2PtpTime(pSystemTime, &pCurrentPD->m_cbstrCurrent, m_bTwoDigitsMillisecondsOutput);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "invalid date/time string");
|
|
delete []pPropVar;
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Write the new date/time to the device
|
|
//
|
|
hr = m_pPTPCamera->SetDevicePropValue(PTP_PROPERTYCODE_DATETIME, pCurrentPD);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "SetDevicePropValue failed");
|
|
delete []pPropVar;
|
|
return hr;
|
|
}
|
|
} // else if (pPropSpecs[count].propid == WIA_DPA_DEVICE_TIME)
|
|
} // for (count...
|
|
|
|
//
|
|
// Now write the new values to the camera
|
|
//
|
|
PROPSPEC propSpec;
|
|
BOOL bWroteWidthHeight = FALSE;
|
|
WORD propCode = 0;
|
|
int pdIdx = 0;
|
|
CPtpPropDesc *pCurrentPD = NULL;
|
|
|
|
for (int count = 0; count < NumPropSpecs; count++)
|
|
{
|
|
//
|
|
// Skip date/time since it was already written above
|
|
//
|
|
if (pPropSpecs[count].propid == WIA_DPA_DEVICE_TIME)
|
|
continue;
|
|
|
|
//
|
|
// Handle changes to the picture width or height
|
|
//
|
|
if ((pPropSpecs[count].propid == WIA_DPC_PICT_WIDTH) ||
|
|
(pPropSpecs[count].propid == WIA_DPC_PICT_HEIGHT))
|
|
{
|
|
//
|
|
// If width and height were already written, don't do it again
|
|
//
|
|
if (bWroteWidthHeight)
|
|
continue;
|
|
|
|
TCHAR ptcsImageSize[MAX_PATH];
|
|
hr = StringCchPrintfW(ptcsImageSize, ARRAYSIZE(ptcsImageSize), TEXT("%dx%d"), width, height);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "StringCchPrintfW failed");
|
|
delete []pPropVar;
|
|
return E_FAIL;
|
|
}
|
|
|
|
propCode = PTP_PROPERTYCODE_IMAGESIZE;
|
|
pdIdx = m_DeviceInfo.m_SupportedProps.Find(propCode);
|
|
if (pdIdx < 0)
|
|
{
|
|
wiauDbgWarning("ValidateDeviceProperties", "Width/height not supported by camera");
|
|
continue;
|
|
}
|
|
pCurrentPD = &m_PropDescs[pdIdx];
|
|
|
|
hr = pCurrentPD->m_cbstrCurrent.Copy(T2W(ptcsImageSize));
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "Copy bstr failed");
|
|
delete []pPropVar;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Write the new value to the device
|
|
//
|
|
hr = m_pPTPCamera->SetDevicePropValue(propCode, pCurrentPD);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "SetDevicePropValue failed");
|
|
delete []pPropVar;
|
|
return hr;
|
|
}
|
|
|
|
bWroteWidthHeight = TRUE;
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// Find the prop code and prop desc structure
|
|
//
|
|
propCode = PropIdToPropCode(pPropSpecs[count].propid);
|
|
pdIdx = m_DeviceInfo.m_SupportedProps.Find(propCode);
|
|
if (pdIdx < 0)
|
|
{
|
|
wiauDbgWarning("ValidateDeviceProperties", "Property not supported by camera");
|
|
continue;
|
|
}
|
|
pCurrentPD = &m_PropDescs[pdIdx];
|
|
|
|
//
|
|
// Put the new value into the PropSpec structure
|
|
//
|
|
if (pPropVar[count].vt == VT_BSTR)
|
|
{
|
|
hr = pCurrentPD->m_cbstrCurrent.Copy(pPropVar[count].bstrVal);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "Copy bstr failed");
|
|
delete []pPropVar;
|
|
return hr;
|
|
}
|
|
}
|
|
else if (pPropVar[count].vt == VT_I4)
|
|
{
|
|
pCurrentPD->m_lCurrent = pPropVar[count].lVal;
|
|
}
|
|
else
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "unsupported variant type");
|
|
delete []pPropVar;
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Write the new value to the device
|
|
//
|
|
hr = m_pPTPCamera->SetDevicePropValue(propCode, pCurrentPD);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("ValidateDeviceProperties", "SetDevicePropValue failed");
|
|
delete []pPropVar;
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
delete []pPropVar;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// This function finds the corresponding height for a width value, or vice versa. Set the
|
|
// value to find to zero.
|
|
//
|
|
// Input:
|
|
// pWidth -- pointer to the width value
|
|
// pHeight -- pointer to the height value
|
|
//
|
|
HRESULT
|
|
CWiaMiniDriver::FindCorrDimension(BYTE *pWiasContext, LONG *pWidth, LONG *pHeight)
|
|
{
|
|
DBG_FN("CWiaMiniDriver::FindCorrDimensions");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!pWiasContext ||
|
|
(*pWidth == 0 && *pHeight == 0))
|
|
{
|
|
wiauDbgError("FindCorrDimension", "invalid args");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
PROPSPEC ps[2];
|
|
ULONG af[2];
|
|
PROPVARIANT pv[2];
|
|
|
|
ps[0].ulKind = PRSPEC_PROPID;
|
|
ps[0].propid = WIA_DPC_PICT_WIDTH;
|
|
ps[1].ulKind = PRSPEC_PROPID;
|
|
ps[1].propid = WIA_DPC_PICT_HEIGHT;
|
|
|
|
hr = wiasGetPropertyAttributes(pWiasContext, 2, ps, af, pv);
|
|
if (FAILED(hr))
|
|
{
|
|
wiauDbgError("FindCorrDimension", "wiasGetPropertyAttributes failed");
|
|
return E_FAIL;
|
|
}
|
|
|
|
int count = 0 ;
|
|
|
|
if (af[0] & WIA_PROP_LIST)
|
|
{
|
|
LONG numValues = pv[0].cal.pElems[WIA_LIST_COUNT];
|
|
LONG *pValidWidths = &pv[0].cal.pElems[WIA_LIST_VALUES];
|
|
LONG *pValidHeights = &pv[1].cal.pElems[WIA_LIST_VALUES];
|
|
|
|
if (*pWidth == 0)
|
|
{
|
|
//
|
|
// Find the height in the valid values array
|
|
//
|
|
for (count = 0; count < numValues; count++)
|
|
{
|
|
if (pValidHeights[count] == *pHeight)
|
|
{
|
|
//
|
|
// Set the width and exit
|
|
//
|
|
*pWidth = pValidWidths[count];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// Find the width in the valid values array
|
|
//
|
|
for (count = 0; count < numValues; count++)
|
|
{
|
|
if (pValidWidths[count] == *pWidth)
|
|
{
|
|
//
|
|
// Set the height and exit
|
|
//
|
|
*pHeight = pValidHeights[count];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (af[0] & WIA_PROP_RANGE)
|
|
{
|
|
LONG minWidth = pv[0].cal.pElems[WIA_RANGE_MIN];
|
|
LONG maxWidth = pv[0].cal.pElems[WIA_RANGE_MAX];
|
|
LONG stepWidth = pv[0].cal.pElems[WIA_RANGE_STEP];
|
|
LONG minHeight = pv[1].cal.pElems[WIA_RANGE_MIN];
|
|
LONG maxHeight = pv[1].cal.pElems[WIA_RANGE_MAX];
|
|
LONG stepHeight = pv[1].cal.pElems[WIA_RANGE_STEP];
|
|
|
|
if (*pWidth == 0)
|
|
{
|
|
//
|
|
// Set the width to the proportionally correct value, clipping to the step value
|
|
//
|
|
*pWidth = FindProportionalValue(*pHeight, minHeight, maxHeight, minWidth, maxWidth, stepWidth);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set the height to the proportionally correct value, clipping to the step value
|
|
//
|
|
*pHeight = FindProportionalValue(*pWidth, minWidth, maxWidth, minHeight, maxHeight, stepHeight);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// This function takes the proportion of valueX between minX and maxX and uses that to
|
|
// find a value of the same proportion between minY and maxY. It then clips that value
|
|
// to the step value
|
|
//
|
|
int CWiaMiniDriver::FindProportionalValue(int valueX, int minX, int maxX, int minY, int maxY, int stepY)
|
|
{
|
|
int valueY;
|
|
|
|
//
|
|
// Find proportional value
|
|
//
|
|
valueY = (valueX - minX) * (maxY - minY) / (maxX - minX) + minY;
|
|
|
|
//
|
|
// Clip the value to the step
|
|
//
|
|
valueY = ((valueY + ((stepY - 1) / 2)) - minY) / stepY * stepY + minY;
|
|
|
|
return valueY;
|
|
}
|
|
|
|
|
|
//
|
|
// This helper function returns a pointer to the property info structure
|
|
// based on the property code
|
|
//
|
|
// Input:
|
|
// PropCode -- the format code
|
|
//
|
|
// Output:
|
|
// Returns pointer to the property info structure
|
|
//
|
|
PPROP_INFO
|
|
CWiaMiniDriver::PropCodeToPropInfo(WORD PropCode)
|
|
{
|
|
DBG_FN("CWiaMiniDriver::PropCodeToPropInfo");
|
|
|
|
PPROP_INFO pPropInfo = NULL;
|
|
UINT index = 0;
|
|
const WORD PROPCODE_MASK = 0x0fff;
|
|
|
|
if (PropCode & PTP_DATACODE_VENDORMASK)
|
|
{
|
|
//
|
|
// Look up vendor extended PropCode
|
|
//
|
|
pPropInfo = m_VendorPropMap.Lookup(PropCode);
|
|
if (!pPropInfo)
|
|
{
|
|
pPropInfo = &g_PropInfo[0];
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// Look up the prop code in the prop info array
|
|
//
|
|
index = PropCode & PROPCODE_MASK;
|
|
|
|
if (index >= g_NumPropInfo)
|
|
{
|
|
index = 0;
|
|
}
|
|
|
|
pPropInfo = &g_PropInfo[index];
|
|
}
|
|
|
|
return pPropInfo;
|
|
}
|
|
|
|
//
|
|
// This helper function returns a pointer to the format info structure
|
|
// based on the format code
|
|
//
|
|
// Input:
|
|
// FormatCode -- the format code
|
|
// AssocType -- association type (for associations)
|
|
//
|
|
// Output:
|
|
// Returns pointer to the format info structure
|
|
//
|
|
PFORMAT_INFO
|
|
FormatCodeToFormatInfo(WORD FormatCode, WORD AssocType)
|
|
{
|
|
DBG_FN("FormatCodeToFormatString");
|
|
|
|
PFORMAT_INFO pFormatInfo = NULL;
|
|
UINT index = 0;
|
|
const WORD FORMATCODE_MASK = 0x07ff;
|
|
|
|
if (FormatCode & PTP_DATACODE_VENDORMASK)
|
|
{
|
|
//
|
|
// WIAFIX-9/6/2000-davepar This should ideally query GDI+ somehow for a filter
|
|
// which the vendor could register
|
|
//
|
|
pFormatInfo = &g_NonImageFormatInfo[0];
|
|
}
|
|
|
|
else if (FormatCode == PTP_FORMATCODE_ASSOCIATION)
|
|
{
|
|
//
|
|
// Look up the association type
|
|
//
|
|
index = AssocType;
|
|
|
|
if (index > g_NumAssocFormatInfo)
|
|
{
|
|
index = 0;
|
|
}
|
|
pFormatInfo = &g_AssocFormatInfo[index];
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// Look up the format code in either the image or non-image format info array
|
|
//
|
|
index = FormatCode & FORMATCODE_MASK;
|
|
|
|
if (FormatCode & PTP_FORMATMASK_IMAGE)
|
|
{
|
|
if (index > g_NumImageFormatInfo)
|
|
{
|
|
index = 0;
|
|
}
|
|
pFormatInfo = &g_ImageFormatInfo[index];
|
|
}
|
|
else
|
|
{
|
|
if (index >= g_NumNonImageFormatInfo)
|
|
{
|
|
index = 0;
|
|
}
|
|
pFormatInfo = &g_NonImageFormatInfo[index];
|
|
}
|
|
}
|
|
|
|
return pFormatInfo;
|
|
}
|
|
|
|
//
|
|
// This function converts a WIA format GUID into a PTP format code
|
|
//
|
|
WORD
|
|
FormatGuidToFormatCode(GUID *pFormatGuid)
|
|
{
|
|
WORD count = 0;
|
|
|
|
//
|
|
// Look through the image formats first
|
|
//
|
|
for (count = 0; count < g_NumImageFormatInfo; count++)
|
|
{
|
|
if (g_ImageFormatInfo[count].FormatGuid &&
|
|
IsEqualGUID(*pFormatGuid, *(g_ImageFormatInfo[count].FormatGuid)))
|
|
{
|
|
return count | PTP_FORMATCODE_IMAGE_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Then look through the non image formats
|
|
//
|
|
for (count = 0; count < g_NumNonImageFormatInfo; count++)
|
|
{
|
|
if (g_NonImageFormatInfo[count].FormatGuid &&
|
|
IsEqualGUID(*pFormatGuid, *(g_NonImageFormatInfo[count].FormatGuid)))
|
|
{
|
|
return count | PTP_FORMATCODE_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The GUID wasn't found in either array
|
|
//
|
|
return PTP_FORMATCODE_UNDEFINED;
|
|
}
|
|
|
|
//
|
|
// This function looks up a prop id in the property info array and returns a
|
|
// property code for it.
|
|
//
|
|
WORD
|
|
PropIdToPropCode(PROPID PropId)
|
|
{
|
|
WORD PropCode;
|
|
for (PropCode = 0; PropCode < g_NumPropInfo; PropCode++)
|
|
{
|
|
if (g_PropInfo[PropCode].PropId == PropId)
|
|
{
|
|
return PropCode | PTP_PROPERTYCODE_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Not found
|
|
//
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// This function splits a PTP image size string (WXH) into two separate longs
|
|
//
|
|
VOID
|
|
SplitImageSize(
|
|
CBstr cbstr,
|
|
LONG *pWidth,
|
|
LONG *pHeight
|
|
)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
int num = _stscanf(W2T(cbstr.String()), TEXT("%dx%d"), pWidth, pHeight);
|
|
|
|
//
|
|
// The spec mentions "x" as divider, but let's be paranoid and check "X" as well
|
|
//
|
|
if (num != 2)
|
|
{
|
|
num = _stscanf(W2T(cbstr.String()), TEXT("%dX%d"), pWidth, pHeight);
|
|
}
|
|
|
|
if (num != 2)
|
|
{
|
|
wiauDbgError("SplitImageSize", "invalid current image dimensions");
|
|
*pWidth = 0;
|
|
*pHeight = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|