/*++ 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 #include // // 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 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; }