Leaked source code of windows server 2003
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

  1. /*++
  2. Copyright (C) 1999- Microsoft Corporation
  3. Module Name:
  4. devitem.cpp
  5. Abstract:
  6. This module implements device related function of CWiaMiniDriver class
  7. Author:
  8. William Hsieh (williamh) created
  9. Revision History:
  10. --*/
  11. #include "pch.h"
  12. #include <atlbase.h>
  13. #include <atlconv.h>
  14. //
  15. // Locations for holding resource strings
  16. //
  17. extern WCHAR UnknownString[];
  18. extern WCHAR FolderString[];
  19. extern WCHAR ScriptString[];
  20. extern WCHAR ExecString[];
  21. extern WCHAR TextString[];
  22. extern WCHAR HtmlString[];
  23. extern WCHAR DpofString[];
  24. extern WCHAR AudioString[];
  25. extern WCHAR VideoString[];
  26. extern WCHAR UnknownImgString[];
  27. extern WCHAR ImageString[];
  28. extern WCHAR AlbumString[];
  29. extern WCHAR BurstString[];
  30. extern WCHAR PanoramaString[];
  31. //
  32. // Mapping of non-image PTP formats to format info structures. Index is the
  33. // lower 16 bits of the format code. The fields going across are WIA format GUID,
  34. // string, and item type.
  35. // Note: For associations, these fields depend on the type (e.g. burst, panorama)
  36. //
  37. FORMAT_INFO g_NonImageFormatInfo[] =
  38. {
  39. { (GUID *)&WiaImgFmt_UNDEFINED, UnknownString, ITEMTYPE_FILE, L"" }, // Undefined
  40. { NULL, FolderString, ITEMTYPE_FOLDER, L"" }, // Association
  41. { (GUID *)&WiaImgFmt_SCRIPT, ScriptString, ITEMTYPE_FILE, L"" }, // Script
  42. { (GUID *)&WiaImgFmt_EXEC, ExecString, ITEMTYPE_FILE, L"EXE" }, // Executable
  43. { (GUID *)&WiaImgFmt_UNICODE16, TextString, ITEMTYPE_FILE, L"TXT" }, // Text
  44. { (GUID *)&WiaImgFmt_HTML, HtmlString, ITEMTYPE_FILE, L"HTM" }, // HTML
  45. { (GUID *)&WiaImgFmt_DPOF, DpofString, ITEMTYPE_FILE, L"" }, // DPOF
  46. { (GUID *)&WiaAudFmt_AIFF, AudioString, ITEMTYPE_AUDIO, L"AIF" }, // AIFF
  47. { (GUID *)&WiaAudFmt_WAV, AudioString, ITEMTYPE_AUDIO, L"WAV" }, // WAV
  48. { (GUID *)&WiaAudFmt_MP3, AudioString, ITEMTYPE_AUDIO, L"MP3" }, // MP3
  49. { (GUID *)&WiaImgFmt_AVI, VideoString, ITEMTYPE_VIDEO, L"AVI" }, // AVI
  50. { (GUID *)&WiaImgFmt_MPG, VideoString, ITEMTYPE_VIDEO, L"MPG" }, // MPEG
  51. { (GUID *)&WiaImgFmt_ASF, VideoString, ITEMTYPE_VIDEO, L"ASF" } // ASF
  52. };
  53. const UINT g_NumNonImageFormatInfo = sizeof(g_NonImageFormatInfo) / sizeof(g_NonImageFormatInfo[0]);
  54. //
  55. // Mapping of image PTP formats to format info structures. Index is the
  56. // lower 16 bits of the format code.
  57. //
  58. FORMAT_INFO g_ImageFormatInfo[] =
  59. {
  60. { NULL, UnknownImgString, ITEMTYPE_IMAGE, L"" }, // Undefined image
  61. { (GUID *)&WiaImgFmt_JPEG, ImageString, ITEMTYPE_IMAGE, L"JPG" }, // EXIF/JPEG
  62. { (GUID *)&WiaImgFmt_TIFF, ImageString, ITEMTYPE_IMAGE, L"TIF" }, // TIFF/EP
  63. { (GUID *)&WiaImgFmt_FLASHPIX, ImageString, ITEMTYPE_IMAGE, L"FPX" }, // FlashPix
  64. { (GUID *)&WiaImgFmt_BMP, ImageString, ITEMTYPE_IMAGE, L"BMP" }, // BMP
  65. { (GUID *)&WiaImgFmt_CIFF, ImageString, ITEMTYPE_IMAGE, L"TIF" }, // CIFF
  66. { NULL, UnknownString, ITEMTYPE_IMAGE, L"" }, // Undefined (Reserved)
  67. { (GUID *)&WiaImgFmt_GIF, ImageString, ITEMTYPE_IMAGE, L"GIF" }, // GIF
  68. { (GUID *)&WiaImgFmt_JPEG, ImageString, ITEMTYPE_IMAGE, L"JPG" }, // JFIF
  69. { (GUID *)&WiaImgFmt_PHOTOCD, ImageString, ITEMTYPE_IMAGE, L"PCD" }, // PCD (PhotoCD Image Pac)
  70. { (GUID *)&WiaImgFmt_PICT, ImageString, ITEMTYPE_IMAGE, L"" }, // PICT
  71. { (GUID *)&WiaImgFmt_PNG, ImageString, ITEMTYPE_IMAGE, L"PNG" }, // PNG
  72. { NULL, UnknownString, ITEMTYPE_IMAGE, L"" }, // Undefined (Reserved)
  73. { (GUID *)&WiaImgFmt_TIFF, ImageString, ITEMTYPE_IMAGE, L"TIF" }, // TIFF
  74. { (GUID *)&WiaImgFmt_TIFF, ImageString, ITEMTYPE_IMAGE, L"TIF" }, // TIFF/IT
  75. { (GUID *)&WiaImgFmt_JPEG2K, ImageString, ITEMTYPE_IMAGE, L"" }, // JPEG2000 Baseline
  76. { (GUID *)&WiaImgFmt_JPEG2KX, ImageString, ITEMTYPE_IMAGE, L"" } // JPEG2000 Extended
  77. };
  78. const UINT g_NumImageFormatInfo = sizeof(g_ImageFormatInfo) / sizeof(g_ImageFormatInfo[0]);
  79. //
  80. // Mapping of association types to format info structures.
  81. //
  82. FORMAT_INFO g_AssocFormatInfo[] =
  83. {
  84. { NULL, UnknownString, ITEMTYPE_FOLDER }, // Undefined
  85. { NULL, FolderString, ITEMTYPE_FOLDER }, // Generic folder
  86. { NULL, AlbumString, ITEMTYPE_FOLDER }, // Album
  87. { NULL, BurstString, ITEMTYPE_BURST }, // Time burst
  88. { NULL, PanoramaString, ITEMTYPE_HPAN }, // Horizontal panorama
  89. { NULL, PanoramaString, ITEMTYPE_VPAN }, // Vertical panorama
  90. { NULL, PanoramaString, ITEMTYPE_FOLDER }, // 2D panorama
  91. { NULL, FolderString, ITEMTYPE_FOLDER } // Ancillary data
  92. };
  93. const UINT g_NumAssocFormatInfo = sizeof(g_AssocFormatInfo) / sizeof(g_AssocFormatInfo[0]);
  94. //
  95. // Mapping of property codes to property info structures. Index is the lower 12 bites of the
  96. // prop code. The fields going across are WIA property ID, and WIA property string.
  97. //
  98. PROP_INFO g_PropInfo[] =
  99. {
  100. { 0, NULL }, // Undefined property code
  101. { WIA_DPC_BATTERY_STATUS, WIA_DPC_BATTERY_STATUS_STR },
  102. { 0, NULL }, // Functional mode, not used
  103. { 0, NULL }, // Image capture dimensions (needs special processing)
  104. { WIA_DPC_COMPRESSION_SETTING, WIA_DPC_COMPRESSION_SETTING_STR },
  105. { WIA_DPC_WHITE_BALANCE, WIA_DPC_WHITE_BALANCE_STR },
  106. { WIA_DPC_RGB_GAIN, WIA_DPC_RGB_GAIN_STR },
  107. { WIA_DPC_FNUMBER, WIA_DPC_FNUMBER_STR },
  108. { WIA_DPC_FOCAL_LENGTH, WIA_DPC_FOCAL_LENGTH_STR },
  109. { WIA_DPC_FOCUS_DISTANCE, WIA_DPC_FOCUS_DISTANCE_STR },
  110. { WIA_DPC_FOCUS_MODE, WIA_DPC_FOCUS_MODE_STR },
  111. { WIA_DPC_EXPOSURE_METERING_MODE, WIA_DPC_EXPOSURE_METERING_MODE_STR },
  112. { WIA_DPC_FLASH_MODE, WIA_DPC_FLASH_MODE_STR },
  113. { WIA_DPC_EXPOSURE_TIME, WIA_DPC_EXPOSURE_TIME_STR },
  114. { WIA_DPC_EXPOSURE_MODE, WIA_DPC_EXPOSURE_MODE_STR },
  115. { WIA_DPC_EXPOSURE_INDEX, WIA_DPC_EXPOSURE_INDEX_STR },
  116. { WIA_DPC_EXPOSURE_COMP, WIA_DPC_EXPOSURE_COMP_STR },
  117. { WIA_DPA_DEVICE_TIME, WIA_DPA_DEVICE_TIME_STR },
  118. { WIA_DPC_CAPTURE_DELAY, WIA_DPC_CAPTURE_DELAY_STR },
  119. { WIA_DPC_CAPTURE_MODE, WIA_DPC_CAPTURE_MODE_STR },
  120. { WIA_DPC_CONTRAST, WIA_DPC_CONTRAST_STR },
  121. { WIA_DPC_SHARPNESS, WIA_DPC_SHARPNESS_STR },
  122. { WIA_DPC_DIGITAL_ZOOM, WIA_DPC_DIGITAL_ZOOM_STR },
  123. { WIA_DPC_EFFECT_MODE, WIA_DPC_EFFECT_MODE_STR },
  124. { WIA_DPC_BURST_NUMBER, WIA_DPC_BURST_NUMBER_STR },
  125. { WIA_DPC_BURST_INTERVAL, WIA_DPC_BURST_INTERVAL_STR },
  126. { WIA_DPC_TIMELAPSE_NUMBER, WIA_DPC_TIMELAPSE_NUMBER_STR },
  127. { WIA_DPC_TIMELAPSE_INTERVAL, WIA_DPC_TIMELAPSE_INTERVAL_STR },
  128. { WIA_DPC_FOCUS_METERING_MODE, WIA_DPC_FOCUS_METERING_MODE_STR },
  129. { WIA_DPC_UPLOAD_URL, WIA_DPC_UPLOAD_URL_STR },
  130. { WIA_DPC_ARTIST, WIA_DPC_ARTIST_STR },
  131. { WIA_DPC_COPYRIGHT_INFO, WIA_DPC_COPYRIGHT_INFO_STR }
  132. };
  133. const UINT g_NumPropInfo = sizeof(g_PropInfo) / sizeof(g_PropInfo[0]);
  134. //
  135. // Helper function - returns number of logical storages (those which have
  136. // StorageId & PTP_STORAGEID_LOGICAL > 0)
  137. //
  138. int CWiaMiniDriver::NumLogicalStorages()
  139. {
  140. DBG_FN("CWiaMiniDriver::NumLogicalStorages");
  141. int nResult = 0;
  142. for (int i = 0; i < m_StorageIds.GetSize(); i++)
  143. {
  144. if (m_StorageIds[i] & PTP_STORAGEID_LOGICAL)
  145. {
  146. nResult++;
  147. }
  148. }
  149. return nResult;
  150. }
  151. //
  152. // This function creates the driver item tree
  153. //
  154. // Input:
  155. // RootItemFullName -- the root item full name
  156. // ppRoot -- to receive the root driver item
  157. //
  158. HRESULT
  159. CWiaMiniDriver::CreateDrvItemTree(IWiaDrvItem **ppRoot)
  160. {
  161. DBG_FN("CWiaMiniDriver::CreateDrvItemTree");
  162. HRESULT hr = S_OK;
  163. DRVITEM_CONTEXT *pDrvItemContext;
  164. if (!ppRoot)
  165. {
  166. wiauDbgError("CreateDrvItemTree", "invalid arg");
  167. return E_INVALIDARG;
  168. }
  169. //
  170. // Create the root item name
  171. //
  172. BSTR bstrRoot = SysAllocString(L"Root");
  173. if (!bstrRoot)
  174. {
  175. wiauDbgError("CreateDrvItemTree", "memory allocation failed");
  176. return E_OUTOFMEMORY;
  177. }
  178. //
  179. // Create the root item.
  180. //
  181. *ppRoot = NULL;
  182. pDrvItemContext = NULL;
  183. hr = wiasCreateDrvItem(WiaItemTypeDevice | WiaItemTypeRoot | WiaItemTypeFolder,
  184. bstrRoot,
  185. m_bstrRootItemFullName,
  186. (IWiaMiniDrv *)this,
  187. sizeof(DRVITEM_CONTEXT),
  188. (BYTE **) &pDrvItemContext,
  189. ppRoot
  190. );
  191. SysFreeString(bstrRoot);
  192. if (FAILED(hr) || !*ppRoot || !pDrvItemContext)
  193. {
  194. wiauDbgError("CreateDrvItemTree", "wiasCreateDrvItem failed");
  195. return hr;
  196. }
  197. pDrvItemContext->pObjectInfo = NULL;
  198. pDrvItemContext->NumFormatInfos = 0;
  199. pDrvItemContext->pFormatInfos = NULL;
  200. pDrvItemContext->ThumbSize = 0;
  201. pDrvItemContext->pThumb = NULL;
  202. //
  203. // Clear the handle/driver item mapping (it might be non-empty if camera was reset, see bug #685926)
  204. //
  205. m_HandleItem.RemoveAll();
  206. //
  207. // Add an entry in the object handle/driver item association mapping for the root
  208. //
  209. if (!m_HandleItem.Add(0, *ppRoot))
  210. {
  211. wiauDbgError("CreateDrvItemTree", "memory allocation failed");
  212. return E_OUTOFMEMORY;
  213. }
  214. //
  215. // Now create all the other items by looping through the list of all of the object
  216. // handles on the device
  217. //
  218. CArray32 ObjectHandleList;
  219. if (NumLogicalStorages() > 0)
  220. {
  221. hr = m_pPTPCamera->GetObjectHandles(PTP_STORAGEID_ALL, PTP_FORMATCODE_ALL, PTP_OBJECTHANDLE_ALL,
  222. &ObjectHandleList);
  223. if (FAILED(hr))
  224. {
  225. wiauDbgError("CreateDrvItemTree", "GetObjectHandles failed");
  226. return hr;
  227. }
  228. }
  229. //
  230. // In order to fill drv items tree correctly, get information for all objects, and add them
  231. // in order of depth (closest to the root first)
  232. //
  233. CWiaMap<DWORD, CPtpObjectInfo*> HandleToInfoMap;
  234. UINT nItems = ObjectHandleList.GetSize();
  235. CPtpObjectInfo *ObjectInfoList = new CPtpObjectInfo[nItems];
  236. BYTE *DepthList = new BYTE[nItems];
  237. if (ObjectInfoList == NULL || DepthList == NULL)
  238. {
  239. wiauDbgError("CreateDrvItemTree", "memory allocation failed");
  240. hr = E_OUTOFMEMORY;
  241. goto cleanup;
  242. }
  243. //
  244. // Get the ObjectInfo for all objects
  245. //
  246. for (UINT i = 0; i < nItems; i++)
  247. {
  248. hr = m_pPTPCamera->GetObjectInfo(ObjectHandleList[i], &ObjectInfoList[i]);
  249. if (FAILED(hr))
  250. {
  251. wiauDbgError("CreateDrvItemTree", "GetObjectInfo failed");
  252. goto cleanup;
  253. }
  254. if (!HandleToInfoMap.Add(ObjectHandleList[i], &ObjectInfoList[i]))
  255. {
  256. wiauDbgError("CreateDrvItemTree", "failed to item to Handle-ObjectInfo map");
  257. hr = E_OUTOFMEMORY;
  258. goto cleanup;
  259. }
  260. }
  261. //
  262. // Find depth of every object
  263. //
  264. for (i = 0; i < nItems; i++)
  265. {
  266. DepthList[i] = 0;
  267. DWORD CurHandle = ObjectHandleList[i];
  268. while (CurHandle = HandleToInfoMap.Lookup(CurHandle)->m_ParentHandle)
  269. {
  270. DepthList[i]++;
  271. }
  272. }
  273. //
  274. // Add objects in order of depth (closest to the root first)
  275. //
  276. UINT nItemsAdded = 0;
  277. UINT CurDepth = 0;
  278. while (nItemsAdded < nItems)
  279. {
  280. for (i = 0; i < nItems; i++)
  281. {
  282. if (DepthList[i] == CurDepth)
  283. {
  284. hr = AddObject(ObjectHandleList[i], FALSE, &ObjectInfoList[i]);
  285. if (FAILED(hr))
  286. {
  287. wiauDbgError("CreateDrvItemTree", "AddObject failed");
  288. goto cleanup;
  289. }
  290. nItemsAdded++;
  291. }
  292. }
  293. CurDepth++;
  294. }
  295. cleanup:
  296. if (ObjectInfoList)
  297. {
  298. delete[] ObjectInfoList;
  299. }
  300. if (DepthList)
  301. {
  302. delete[] DepthList;
  303. }
  304. return hr;
  305. }
  306. //
  307. // This function adds an object to the driver item tree
  308. //
  309. // Input:
  310. // ObjectHandle -- PTP handle for the object
  311. // bQueueEvent -- TRUE if WIA event should be queued
  312. // pObjectInfo -- optional ObjectInfo for this object. If NULL, info will be queried from camera
  313. //
  314. HRESULT
  315. CWiaMiniDriver::AddObject(
  316. DWORD ObjectHandle,
  317. BOOL bQueueEvent,
  318. CPtpObjectInfo *pProvidedObjectInfo
  319. )
  320. {
  321. USES_CONVERSION;
  322. DBG_FN("CWiaMiniDriver::AddObject");
  323. HRESULT hr = S_OK;
  324. CPtpObjectInfo *pObjectInfo = NULL;
  325. BSTR bstrItemFullName = NULL;
  326. BSTR bstrParentName = NULL;
  327. IWiaDrvItem *pItem = NULL;
  328. //
  329. // flag to indicate if pObjecInfo pointer has been copied to WiaDrvItem
  330. // if TRUE, it should not be deleted in Cleanup
  331. //
  332. BOOL fObjectInfoUsed = FALSE;
  333. //
  334. // Get the ObjectInfo from camera or use provided info if it's given
  335. //
  336. if (pProvidedObjectInfo == NULL)
  337. {
  338. pObjectInfo = new CPtpObjectInfo;
  339. if (!pObjectInfo)
  340. {
  341. wiauDbgError("AddObject", "memory allocation failed");
  342. hr = E_OUTOFMEMORY;
  343. goto Cleanup;
  344. }
  345. hr = m_pPTPCamera->GetObjectInfo(ObjectHandle, pObjectInfo);
  346. if (FAILED(hr))
  347. {
  348. wiauDbgError("AddObject", "GetObjectInfo failed");
  349. goto Cleanup;
  350. }
  351. }
  352. else
  353. {
  354. pObjectInfo = new CPtpObjectInfo(*pProvidedObjectInfo); // default copying constructor
  355. if (!pObjectInfo)
  356. {
  357. wiauDbgError("AddObject", "memory allocation failed");
  358. hr = E_OUTOFMEMORY;
  359. goto Cleanup;
  360. }
  361. }
  362. int storeIdx = m_StorageIds.Find(pObjectInfo->m_StorageId);
  363. //
  364. // Look for objects to hide if this is a DCF store
  365. //
  366. if (m_StorageInfos[storeIdx].m_FileSystemType == PTP_FILESYSTEMTYPE_DCF)
  367. {
  368. BOOL bHideObject = FALSE;
  369. //
  370. // If the DCIM folder has been identified and this is a folder under DCIM, hide it
  371. //
  372. if (m_DcimHandle[storeIdx])
  373. {
  374. if (pObjectInfo->m_ParentHandle == m_DcimHandle[storeIdx])
  375. bHideObject = TRUE;
  376. }
  377. //
  378. // Otherwise see if this is the DCIM folder
  379. //
  380. else if (wcscmp(pObjectInfo->m_cbstrFileName.String(), L"DCIM") == 0)
  381. {
  382. bHideObject = TRUE;
  383. m_DcimHandle[storeIdx] = ObjectHandle;
  384. }
  385. if (bHideObject)
  386. {
  387. //
  388. // Create a dummy entry in the handle/item map so that objects under this
  389. // folder will be put under the root
  390. //
  391. if (!m_HandleItem.Add(ObjectHandle, m_pDrvItemRoot))
  392. {
  393. wiauDbgError("AddObject", "add handle item failed");
  394. hr = E_OUTOFMEMORY;
  395. goto Cleanup;
  396. }
  397. wiauDbgTrace("AddObject", "hiding DCIM folder 0x%08x", ObjectHandle);
  398. hr = S_OK;
  399. goto Cleanup;
  400. }
  401. }
  402. //
  403. // If this is an "ancillary data" association, don't create an item but put the handle
  404. // in the ancillary association array
  405. //
  406. if (pObjectInfo->m_AssociationType == PTP_ASSOCIATIONTYPE_ANCILLARYDATA)
  407. {
  408. if (!m_AncAssocParent.Add(ObjectHandle, m_HandleItem.Lookup(pObjectInfo->m_ParentHandle)))
  409. {
  410. wiauDbgError("AddObject", "add ancillary assoc handle failed");
  411. hr = E_OUTOFMEMORY;
  412. goto Cleanup;
  413. }
  414. hr = S_OK;
  415. goto Cleanup;
  416. }
  417. //
  418. // Keep count of the number of images
  419. //
  420. UINT16 FormatCode = pObjectInfo->m_FormatCode;
  421. if (FormatCode & PTP_FORMATMASK_IMAGE)
  422. {
  423. m_NumImages++;
  424. //
  425. // Also make sure that the bit depth is non-zero.
  426. //
  427. if (pObjectInfo->m_ImageBitDepth == 0) {
  428. switch(pObjectInfo->m_FormatCode) {
  429. case PTP_FORMATCODE_IMAGE_GIF:
  430. pObjectInfo->m_ImageBitDepth = 8;
  431. break;
  432. default:
  433. pObjectInfo->m_ImageBitDepth = 24;
  434. }
  435. }
  436. }
  437. //
  438. // Update Storage Info (we are especially interested in Free Space info)
  439. //
  440. hr = UpdateStorageInfo(pObjectInfo->m_StorageId);
  441. if (FAILED(hr))
  442. {
  443. wiauDbgError("AddObject", "UpdateStorageInfo failed");
  444. // we can proceed, even if storage info can't be updated
  445. hr = S_OK;
  446. }
  447. //
  448. // For images, check to see if the parent is an ancillary association
  449. //
  450. IWiaDrvItem *pParent = NULL;
  451. LONG ExtraItemFlags = 0;
  452. int ancIdx = m_AncAssocParent.FindKey(pObjectInfo->m_ParentHandle);
  453. if ((FormatCode & PTP_FORMATMASK_IMAGE) &&
  454. (ancIdx >= 0))
  455. {
  456. ExtraItemFlags |= WiaItemTypeHasAttachments;
  457. pParent = m_AncAssocParent.GetValueAt(ancIdx);
  458. }
  459. //
  460. // For normal images, just look up the parent item in the map
  461. //
  462. else
  463. {
  464. pParent = m_HandleItem.Lookup(pObjectInfo->m_ParentHandle);
  465. }
  466. //
  467. // If a parent wasn't found, just use the root as the parent
  468. //
  469. if (!pParent)
  470. {
  471. pParent = m_pDrvItemRoot;
  472. }
  473. //
  474. // Look up info about the object's format
  475. //
  476. FORMAT_INFO *pFormatInfo = FormatCodeToFormatInfo(FormatCode, pObjectInfo->m_AssociationType);
  477. //
  478. // Get the item's name, generating it if necessary
  479. //
  480. CBstr *pFileName = &(pObjectInfo->m_cbstrFileName);
  481. TCHAR tcsName[MAX_PATH];
  482. TCHAR *ptcsDot;
  483. if (pFileName->Length() == 0)
  484. {
  485. hr = StringCchPrintf(tcsName, ARRAYSIZE(tcsName), W2T(pFormatInfo->FormatString), ObjectHandle);
  486. if (FAILED(hr))
  487. {
  488. wiauDbgErrorHr(hr, "AddObject", "StringCchPrintf failed");
  489. goto Cleanup;
  490. }
  491. hr = pFileName->Copy(T2W(tcsName));
  492. if (FAILED(hr))
  493. {
  494. wiauDbgError("AddObject", "CBstr::Copy failed");
  495. goto Cleanup;
  496. }
  497. }
  498. //
  499. // For images Chop off the filename extension, if it exists
  500. //
  501. WCHAR *pDot = wcsrchr(pFileName->String(), L'.');
  502. if (pDot)
  503. {
  504. // Copy extension first
  505. hr = pObjectInfo->m_cbstrExtension.Copy(pDot + 1);
  506. if (FAILED(hr))
  507. {
  508. wiauDbgError("AddObject", "copy string failed");
  509. goto Cleanup;
  510. }
  511. // then remove the extension from the item name
  512. hr = StringCchCopy(tcsName, ARRAYSIZE(tcsName), W2T(pFileName->String()));
  513. if (FAILED(hr))
  514. {
  515. wiauDbgErrorHr(hr, "AddObject", "StringCchCopy failed");
  516. goto Cleanup;
  517. }
  518. ptcsDot = _tcsrchr(tcsName, TEXT('.'));
  519. *ptcsDot = TEXT('\0');
  520. hr = pFileName->Copy(T2W(tcsName));
  521. if (FAILED(hr))
  522. {
  523. wiauDbgError("AddObject", "copy string failed");
  524. goto Cleanup;
  525. }
  526. }
  527. if(pObjectInfo->m_cbstrExtension.Length()) {
  528. // this is special-case handling of .MOV files for which we
  529. // don't have GUID, but which need to be treated as video
  530. // elsewhere
  531. if(_wcsicmp(pObjectInfo->m_cbstrExtension.String(), L"MOV") == 0) {
  532. pFormatInfo->ItemType = ITEMTYPE_VIDEO;
  533. }
  534. }
  535. //
  536. // Create the item's full name
  537. //
  538. hr = pParent->GetFullItemName(&bstrParentName);
  539. if (FAILED(hr))
  540. {
  541. wiauDbgError("AddObject", "GetFullItemName failed");
  542. goto Cleanup;
  543. }
  544. hr = StringCchPrintf(tcsName, ARRAYSIZE(tcsName), TEXT("%s\\%s"), W2T(bstrParentName), W2T(pFileName->String()));
  545. if (FAILED(hr))
  546. {
  547. wiauDbgErrorHr(hr, "AddObject", "StringCchPrintf failed");
  548. goto Cleanup;
  549. }
  550. bstrItemFullName = SysAllocString(T2W(tcsName));
  551. if (!bstrItemFullName)
  552. {
  553. wiauDbgError("AddObject", "memory allocation failed");
  554. hr = E_OUTOFMEMORY;
  555. goto Cleanup;
  556. }
  557. //
  558. // Create the driver item
  559. //
  560. DRVITEM_CONTEXT *pDrvItemContext = NULL;
  561. hr = wiasCreateDrvItem(pFormatInfo->ItemType | ExtraItemFlags,
  562. pFileName->String(),
  563. bstrItemFullName,
  564. (IWiaMiniDrv *)this,
  565. sizeof(DRVITEM_CONTEXT),
  566. (BYTE **) &pDrvItemContext,
  567. &pItem);
  568. if (FAILED(hr) || !pItem || !pDrvItemContext)
  569. {
  570. wiauDbgError("AddObject", "wiasCreateDriverItem failed");
  571. goto Cleanup;
  572. }
  573. //
  574. // Fill in the driver item context. Wait until the thumbnail is requested before
  575. // reading it in.
  576. //
  577. pDrvItemContext->pObjectInfo = pObjectInfo;
  578. fObjectInfoUsed = TRUE; // indicate that pObjectInfo pointer has been copied and should not be freed
  579. pDrvItemContext->NumFormatInfos = 0;
  580. pDrvItemContext->pFormatInfos = NULL;
  581. pDrvItemContext->ThumbSize = 0;
  582. pDrvItemContext->pThumb = NULL;
  583. //
  584. // Place the new item under it's parent
  585. //
  586. hr = pItem->AddItemToFolder(pParent);
  587. if (FAILED(hr))
  588. {
  589. wiauDbgError("AddObject", "AddItemToFolder failed");
  590. pItem->Release();
  591. pItem = NULL;
  592. fObjectInfoUsed = FALSE;
  593. goto Cleanup;
  594. }
  595. //
  596. // Add the object handle/driver item association to the list
  597. //
  598. if (!m_HandleItem.Add(ObjectHandle, pItem))
  599. {
  600. wiauDbgError("AddObject", "memory allocation failed");
  601. hr = E_OUTOFMEMORY;
  602. goto Cleanup;
  603. }
  604. //
  605. // If this image is replacing an ancillary association folder, put another entry
  606. // in the object handle/item map for that folder
  607. //
  608. if (ancIdx >= 0)
  609. {
  610. if (!m_HandleItem.Add(pObjectInfo->m_ParentHandle, pItem))
  611. {
  612. wiauDbgError("AddObject", "memory allocation failed");
  613. hr = E_OUTOFMEMORY;
  614. goto Cleanup;
  615. }
  616. }
  617. //
  618. // Post an item added event, if requested
  619. //
  620. if (bQueueEvent)
  621. {
  622. hr = wiasQueueEvent(m_bstrDeviceId, &WIA_EVENT_ITEM_CREATED, bstrItemFullName);
  623. if (FAILED(hr))
  624. {
  625. wiauDbgError("AddObject", "wiasQueueEvent failed");
  626. goto Cleanup;
  627. }
  628. }
  629. Cleanup:
  630. //
  631. // Delete pObjectInfo only if the pointer was not copied to WiaDrvItem
  632. //
  633. if (pObjectInfo && !fObjectInfoUsed)
  634. {
  635. delete pObjectInfo;
  636. pObjectInfo = NULL;
  637. }
  638. if (bstrParentName)
  639. {
  640. SysFreeString(bstrParentName);
  641. bstrParentName = NULL;
  642. }
  643. if (bstrItemFullName)
  644. {
  645. SysFreeString(bstrItemFullName);
  646. bstrItemFullName = NULL;
  647. }
  648. return hr;
  649. }
  650. //
  651. // This function initializes device properties
  652. //
  653. // Input:
  654. // pWiasContext -- wias context
  655. //
  656. HRESULT
  657. CWiaMiniDriver::InitDeviceProperties(BYTE *pWiasContext)
  658. {
  659. DBG_FN("CWiaMiniDriver::InitDeviceProperties");
  660. HRESULT hr = S_OK;
  661. const INT NUM_ROOT_PROPS = 12;
  662. //
  663. // Define things here that need to live until SendToWia() is called
  664. //
  665. CArray32 widthList, heightList; // Used by code that split image width and height
  666. SYSTEMTIME SystemTime; // Used for device time
  667. int NumFormats = 0; // Used by format setting code
  668. LPGUID *pFormatGuids = NULL; // Used by format setting code
  669. FORMAT_INFO *pFormatInfo = NULL; // Used by format setting code
  670. int FormatCount = 0; // Used by format setting code
  671. //
  672. // Create the property list for the device
  673. //
  674. CWiauPropertyList RootProps;
  675. CArray16 *pSupportedProps = &m_DeviceInfo.m_SupportedProps;
  676. hr = RootProps.Init(pSupportedProps->GetSize() + NUM_ROOT_PROPS);
  677. if (FAILED(hr))
  678. {
  679. wiauDbgError("InitDeviceProperties", "Init failed");
  680. return hr;
  681. }
  682. INT index;
  683. int count;
  684. //
  685. // WIA_IPA_ACCESS_RIGHTS
  686. //
  687. hr = RootProps.DefineProperty(&index, WIA_IPA_ACCESS_RIGHTS, WIA_IPA_ACCESS_RIGHTS_STR,
  688. WIA_PROP_READ, WIA_PROP_NONE);
  689. if (FAILED(hr)) goto failure;
  690. RootProps.SetCurrentValue(index, (LONG) WIA_ITEM_READ|WIA_ITEM_WRITE);
  691. //
  692. // WIA_DPA_FIRMWARE_VERSION
  693. //
  694. hr = RootProps.DefineProperty(&index, WIA_DPA_FIRMWARE_VERSION, WIA_DPA_FIRMWARE_VERSION_STR,
  695. WIA_PROP_READ, WIA_PROP_NONE);
  696. if (FAILED(hr)) goto failure;
  697. RootProps.SetCurrentValue(index, m_DeviceInfo.m_cbstrDeviceVersion.String());
  698. //
  699. // WIA_DPC_PICTURES_TAKEN
  700. //
  701. hr = RootProps.DefineProperty(&index, WIA_DPC_PICTURES_TAKEN, WIA_DPC_PICTURES_TAKEN_STR,
  702. WIA_PROP_READ, WIA_PROP_NONE);
  703. if (FAILED(hr)) goto failure;
  704. RootProps.SetCurrentValue(index, m_NumImages);
  705. //
  706. // WIA_DPC_PICTURES_REMAINING
  707. //
  708. hr = RootProps.DefineProperty(&index, WIA_DPC_PICTURES_REMAINING, WIA_DPC_PICTURES_REMAINING_STR,
  709. WIA_PROP_READ, WIA_PROP_NONE);
  710. if (FAILED(hr)) goto failure;
  711. RootProps.SetCurrentValue(index, GetTotalFreeImageSpace());
  712. //
  713. // WIA_IPA_FORMAT -- Translate from the CaptureFormats field of DeviceInfo
  714. //
  715. hr = RootProps.DefineProperty(&index, WIA_IPA_FORMAT, WIA_IPA_FORMAT_STR,
  716. WIA_PROP_READ, WIA_PROP_NONE);
  717. if (FAILED(hr)) goto failure;
  718. NumFormats = m_DeviceInfo.m_SupportedCaptureFmts.GetSize();
  719. pFormatGuids = new LPGUID[NumFormats];
  720. FormatCount = 0;
  721. if (!pFormatGuids)
  722. {
  723. wiauDbgError("InitDeviceProperties", "memory allocation failed");
  724. return E_OUTOFMEMORY;
  725. }
  726. for (count = 0; count < NumFormats; count++)
  727. {
  728. pFormatInfo = FormatCodeToFormatInfo(m_DeviceInfo.m_SupportedCaptureFmts[count]);
  729. if (pFormatInfo->FormatGuid != NULL)
  730. pFormatGuids[FormatCount++] = pFormatInfo->FormatGuid;
  731. }
  732. //
  733. // Kodak DC4800 needs to have WIA_IPA_FORMAT set to JPEG. This hack can be removed
  734. // only if support of DC4800 is removed
  735. //
  736. if (m_pPTPCamera && m_pPTPCamera->GetHackModel() == HACK_MODEL_DC4800)
  737. {
  738. RootProps.SetCurrentValue(index, (CLSID *) &WiaImgFmt_JPEG);
  739. }
  740. else if (FormatCount == 1)
  741. {
  742. RootProps.SetCurrentValue(index, pFormatGuids[0]);
  743. }
  744. else if (FormatCount > 1)
  745. {
  746. RootProps.SetAccessSubType(index, WIA_PROP_RW, WIA_PROP_NONE);
  747. RootProps.SetValidValues(index, pFormatGuids[0], pFormatGuids[0], FormatCount, pFormatGuids);
  748. }
  749. else
  750. wiauDbgWarning("InitDeviceProperties", "Device has no valid formats");
  751. delete []pFormatGuids;
  752. //
  753. // Loop through PTP property description structures, translating them to WIA properties
  754. //
  755. PPROP_INFO pPropInfo;
  756. ULONG Access;
  757. ULONG SubType;
  758. for (count = 0; count < m_PropDescs.GetSize(); count++)
  759. {
  760. CPtpPropDesc *pCurrentPD = &m_PropDescs[count];
  761. WORD PropCode = pCurrentPD->m_PropCode;
  762. //
  763. // Set the property access and subtype
  764. //
  765. if (pCurrentPD->m_GetSet == PTP_PROPGETSET_GETSET)
  766. {
  767. Access = WIA_PROP_RW;
  768. if (pCurrentPD->m_FormFlag == PTP_FORMFLAGS_NONE)
  769. {
  770. //
  771. // If property is writeable and valid values are not a list or a range, set subtype to
  772. // WIA_PROP_NONE now
  773. //
  774. SubType = WIA_PROP_NONE;
  775. }
  776. else
  777. {
  778. //
  779. // If property is writable and valid values are a list or a range, valid subtype will
  780. // be set during a call to overloaded SetCurrentValue.
  781. //
  782. SubType = 0;
  783. }
  784. }
  785. else
  786. {
  787. //
  788. // If property is read-only, it's subtype is always WIA_PROP_NONE
  789. //
  790. Access = WIA_PROP_READ;
  791. SubType = WIA_PROP_NONE;
  792. }
  793. //
  794. // Process image capture dimensions separately, since they are in a string
  795. //
  796. if (PropCode == PTP_PROPERTYCODE_IMAGESIZE)
  797. {
  798. //
  799. // Define separate properties for image width and height
  800. //
  801. hr = RootProps.DefineProperty(&index, WIA_DPC_PICT_WIDTH, WIA_DPC_PICT_WIDTH_STR, Access, SubType);
  802. if (FAILED(hr)) goto failure;
  803. hr = RootProps.DefineProperty(&index, WIA_DPC_PICT_HEIGHT, WIA_DPC_PICT_HEIGHT_STR, Access, SubType);
  804. if (FAILED(hr)) goto failure;
  805. LONG curWidth, curHeight;
  806. SplitImageSize(pCurrentPD->m_cbstrCurrent, &curWidth, &curHeight);
  807. //
  808. // If the image capture size property is read-only, just set the current values
  809. //
  810. if (Access == WIA_PROP_READ)
  811. {
  812. RootProps.SetCurrentValue(index-1, curWidth);
  813. RootProps.SetCurrentValue(index, curHeight);
  814. }
  815. //
  816. // Otherwise, set the valid values too
  817. //
  818. else
  819. {
  820. //
  821. // Convert default values
  822. //
  823. LONG defWidth, defHeight;
  824. SplitImageSize(pCurrentPD->m_cbstrDefault, &defWidth, &defHeight);
  825. if (pCurrentPD->m_FormFlag == PTP_FORMFLAGS_RANGE)
  826. {
  827. //
  828. // Convert max, min, and step
  829. //
  830. LONG minWidth, minHeight, maxWidth, maxHeight, stepWidth, stepHeight;
  831. SplitImageSize(pCurrentPD->m_cbstrRangeMin, &minWidth, &minHeight);
  832. SplitImageSize(pCurrentPD->m_cbstrRangeMax, &maxWidth, &maxHeight);
  833. SplitImageSize(pCurrentPD->m_cbstrRangeStep, &stepWidth, &stepHeight);
  834. RootProps.SetValidValues(index-1, defWidth, curWidth, minWidth, maxWidth, stepWidth);
  835. RootProps.SetValidValues(index, defHeight, curHeight, minHeight, maxHeight, stepHeight);
  836. }
  837. else if (pCurrentPD->m_FormFlag == PTP_FORMFLAGS_ENUM)
  838. {
  839. //
  840. // Convert list of strings
  841. //
  842. ULONG width, height;
  843. int numElem = pCurrentPD->m_NumValues;
  844. if (!widthList.GrowTo(numElem) ||
  845. !heightList.GrowTo(numElem))
  846. {
  847. wiauDbgError("InitDeviceProperties", "memory allocation failed");
  848. return E_OUTOFMEMORY;
  849. }
  850. for (int countVals = 0; countVals < numElem; countVals++)
  851. {
  852. SplitImageSize(pCurrentPD->m_cbstrValues[countVals], (LONG*) &width, (LONG*) &height);
  853. if (!widthList.Add(width) ||
  854. !heightList.Add(height))
  855. {
  856. wiauDbgError("InitDeviceProperties", "error adding width or height");
  857. return E_FAIL;
  858. }
  859. }
  860. RootProps.SetValidValues(index-1, defWidth, curWidth, numElem, (LONG *) widthList.GetData());
  861. RootProps.SetValidValues(index, defHeight, curHeight, numElem, (LONG *) heightList.GetData());
  862. }
  863. }
  864. continue;
  865. } // if (PropCode == PTP_PROPERTYCODE_IMAGESIZE)
  866. //
  867. // Look up the property info structure, which contains the WIA prop id and string
  868. //
  869. pPropInfo = PropCodeToPropInfo(PropCode);
  870. if (!pPropInfo->PropId)
  871. {
  872. wiauDbgError("InitDeviceProperties", "property code not found in array, 0x%04x", PropCode);
  873. return E_FAIL;
  874. }
  875. //
  876. // Define the property based on the fields in the property info structure
  877. //
  878. hr = RootProps.DefineProperty(&index, pPropInfo->PropId, pPropInfo->PropName, Access, SubType);
  879. if (FAILED(hr)) goto failure;
  880. //
  881. // Handle the device date/time. Convert it to SYSTEMTIME and create the property, skipping the rest.
  882. //
  883. if (PropCode == PTP_PROPERTYCODE_DATETIME)
  884. {
  885. hr = PtpTime2SystemTime(&(pCurrentPD->m_cbstrCurrent), &SystemTime);
  886. if (FAILED(hr))
  887. {
  888. wiauDbgError("InitDeviceProperties", "invalid date/time string");
  889. continue;
  890. }
  891. RootProps.SetCurrentValue(index, &SystemTime);
  892. continue;
  893. }
  894. //
  895. // Handle all other properties
  896. //
  897. if (Access == WIA_PROP_RW)
  898. {
  899. //
  900. // Set the valid values for ranges
  901. //
  902. if (pCurrentPD->m_FormFlag == PTP_FORMFLAGS_RANGE)
  903. {
  904. //
  905. // WIA can't handle string ranges, so handle just integers
  906. //
  907. if (pCurrentPD->m_DataType != PTP_DATATYPE_STRING)
  908. RootProps.SetValidValues(index, (LONG) pCurrentPD->m_lDefault,
  909. (LONG) pCurrentPD->m_lCurrent,
  910. (LONG) pCurrentPD->m_lRangeMin,
  911. (LONG) pCurrentPD->m_lRangeMax,
  912. (LONG) pCurrentPD->m_lRangeStep);
  913. }
  914. //
  915. // Set the valid values for lists
  916. //
  917. else if (pCurrentPD->m_FormFlag == PTP_FORMFLAGS_ENUM)
  918. {
  919. if (pCurrentPD->m_DataType == PTP_DATATYPE_STRING)
  920. RootProps.SetValidValues(index, pCurrentPD->m_cbstrDefault.String(),
  921. pCurrentPD->m_cbstrCurrent.String(),
  922. pCurrentPD->m_NumValues,
  923. (BSTR *) (pCurrentPD->m_cbstrValues.GetData()));
  924. else
  925. RootProps.SetValidValues(index, (LONG) pCurrentPD->m_lDefault,
  926. (LONG) pCurrentPD->m_lCurrent,
  927. pCurrentPD->m_NumValues,
  928. (LONG *) (pCurrentPD->m_lValues.GetData()));
  929. }
  930. //
  931. // Unrecognized form. Just set the current values
  932. //
  933. if (pCurrentPD->m_DataType == PTP_DATATYPE_STRING)
  934. RootProps.SetCurrentValue(index, pCurrentPD->m_cbstrCurrent.String());
  935. else
  936. RootProps.SetCurrentValue(index, (LONG) pCurrentPD->m_lCurrent);
  937. }
  938. else
  939. {
  940. //
  941. // For read-only properties, just set the current value
  942. //
  943. if (pCurrentPD->m_DataType == PTP_DATATYPE_STRING)
  944. RootProps.SetCurrentValue(index, pCurrentPD->m_cbstrCurrent.String());
  945. else
  946. RootProps.SetCurrentValue(index, (LONG) pCurrentPD->m_lCurrent);
  947. }
  948. }
  949. // Last step: send all the properties to WIA
  950. hr = RootProps.SendToWia(pWiasContext);
  951. if (FAILED(hr))
  952. {
  953. wiauDbgErrorHr(hr, "InitDeviceProperties", "SendToWia failed");
  954. return hr;
  955. }
  956. return hr;
  957. //
  958. // Any failures from DefineProperty will end up here
  959. //
  960. failure:
  961. wiauDbgErrorHr(hr, "InitDeviceProperties", "DefineProperty failed");
  962. return hr;
  963. }
  964. // This function reads the device properties
  965. //
  966. // Input:
  967. // pWiasContext -- wias context
  968. // NumPropSpecs -- number of properties to be read
  969. // pPropSpecs -- list of PROPSPEC that designates what properties to read
  970. //
  971. HRESULT
  972. CWiaMiniDriver::ReadDeviceProperties(
  973. BYTE *pWiasContext,
  974. LONG NumPropSpecs,
  975. const PROPSPEC *pPropSpecs
  976. )
  977. {
  978. DBG_FN("CWiaMiniDriver::ReadDeviceProperties");
  979. HRESULT hr = S_OK;
  980. if (!NumPropSpecs || !pPropSpecs)
  981. {
  982. wiauDbgError("ReadDeviceProperties", "invalid arg");
  983. return E_INVALIDARG;
  984. }
  985. //
  986. // Update the device properties
  987. //
  988. if (m_PropDescs.GetSize() > 0)
  989. {
  990. //
  991. // Loop through all of the PropSpecs
  992. //
  993. for (int count = 0; count < NumPropSpecs; count++)
  994. {
  995. PROPID propId = pPropSpecs[count].propid;
  996. //
  997. // Update free image space, if requested
  998. //
  999. if (propId == WIA_DPC_PICTURES_REMAINING)
  1000. {
  1001. hr = wiasWritePropLong(pWiasContext, WIA_DPC_PICTURES_REMAINING, GetTotalFreeImageSpace());
  1002. if (FAILED(hr))
  1003. {
  1004. wiauDbgError("ReadDeviceProperties", "wiasWritePropLong failed");
  1005. return hr;
  1006. }
  1007. }
  1008. //
  1009. // Update pictures taken, if requested
  1010. //
  1011. else if (propId == WIA_DPC_PICTURES_TAKEN)
  1012. {
  1013. hr = wiasWritePropLong(pWiasContext, WIA_DPC_PICTURES_TAKEN, m_NumImages);
  1014. if (FAILED(hr))
  1015. {
  1016. wiauDbgError("ReadDeviceProperties", "wiasWritePropLong failed");
  1017. return hr;
  1018. }
  1019. }
  1020. //
  1021. // Image size is a special case property, which we handle here
  1022. //
  1023. else if (propId == WIA_DPC_PICT_WIDTH ||
  1024. propId == WIA_DPC_PICT_HEIGHT)
  1025. {
  1026. int propDescIdx = m_DeviceInfo.m_SupportedProps.Find(PTP_PROPERTYCODE_IMAGESIZE);
  1027. if (propDescIdx < 0)
  1028. continue;
  1029. LONG width, height;
  1030. SplitImageSize(m_PropDescs[propDescIdx].m_cbstrCurrent, &width, &height);
  1031. if (propId == WIA_DPC_PICT_WIDTH)
  1032. hr = wiasWritePropLong(pWiasContext, propId, width);
  1033. else
  1034. hr = wiasWritePropLong(pWiasContext, propId, height);
  1035. if (FAILED(hr))
  1036. {
  1037. wiauDbgError("ReadDeviceProperties", "wiasWritePropLong failed");
  1038. return hr;
  1039. }
  1040. }
  1041. //
  1042. // See if the property is one that is contained in the PropSpec array
  1043. //
  1044. else
  1045. {
  1046. //
  1047. // Try to convert the WIA prop id to a PTP prop code
  1048. //
  1049. WORD propCode = PropIdToPropCode(propId);
  1050. if (propCode == 0)
  1051. continue;
  1052. //
  1053. // Try to find the prop code (and thus the prop desc structure) in the member array
  1054. //
  1055. int propDescIdx = m_DeviceInfo.m_SupportedProps.Find(propCode);
  1056. if (propDescIdx < 0)
  1057. continue;
  1058. //
  1059. // If it's the device time property, convert to SYSTEMTIME and write to WIA
  1060. //
  1061. if (propId == WIA_DPA_DEVICE_TIME)
  1062. {
  1063. hr = m_pPTPCamera->GetDevicePropValue(propCode, &m_PropDescs[propDescIdx]);
  1064. if (FAILED(hr))
  1065. {
  1066. wiauDbgError("ReadDeviceProperties", "GetDevicePropValue failed");
  1067. return hr;
  1068. }
  1069. SYSTEMTIME st;
  1070. hr = PtpTime2SystemTime(&m_PropDescs[propDescIdx].m_cbstrCurrent, &st);
  1071. if (FAILED(hr))
  1072. {
  1073. wiauDbgError("ReadDeviceProperties", "PtpTime2SystemTime failed");
  1074. return hr;
  1075. }
  1076. PROPVARIANT pv;
  1077. pv.vt = VT_UI2 | VT_VECTOR;
  1078. pv.caui.cElems = sizeof(SYSTEMTIME)/sizeof(WORD);
  1079. pv.caui.pElems = (USHORT *) &st;
  1080. PROPSPEC ps;
  1081. ps.ulKind = PRSPEC_PROPID;
  1082. ps.propid = propId;
  1083. hr = wiasWriteMultiple(pWiasContext, 1, &ps, &pv);
  1084. if (FAILED(hr))
  1085. {
  1086. wiauDbgError("ReadDeviceProperties", "wiasWriteMultiple failed");
  1087. return hr;
  1088. }
  1089. }
  1090. //
  1091. // If it's a string property, write the updated value to WIA
  1092. //
  1093. else if (m_PropDescs[propDescIdx].m_DataType == PTP_DATATYPE_STRING)
  1094. {
  1095. hr = wiasWritePropStr(pWiasContext, propId,
  1096. m_PropDescs[propDescIdx].m_cbstrCurrent.String());
  1097. if (FAILED(hr))
  1098. {
  1099. wiauDbgError("ReadDeviceProperties", "wiasWritePropLong failed");
  1100. return hr;
  1101. }
  1102. }
  1103. //
  1104. // If it's an integer property, write the updated value to WIA
  1105. //
  1106. else
  1107. {
  1108. hr = wiasWritePropLong(pWiasContext, propId,
  1109. m_PropDescs[propDescIdx].m_lCurrent);
  1110. if (FAILED(hr))
  1111. {
  1112. wiauDbgError("ReadDeviceProperties", "wiasWritePropLong failed");
  1113. return hr;
  1114. }
  1115. }
  1116. }
  1117. }
  1118. }
  1119. return hr;
  1120. }
  1121. //
  1122. // This function does nothing, since the values were already sent to the device in ValidateDeviceProp
  1123. //
  1124. // Input:
  1125. // pWiasContext -- the WIA item context
  1126. // pmdtc -- the transfer context
  1127. //
  1128. HRESULT
  1129. CWiaMiniDriver::WriteDeviceProperties(
  1130. BYTE *pWiasContext
  1131. )
  1132. {
  1133. DBG_FN("CWiaMiniDriver::WriteDeviceProperties");
  1134. HRESULT hr = S_OK;
  1135. return hr;
  1136. }
  1137. //
  1138. // This function validates device property current settings and writes them to the device. The
  1139. // settings need to be written here vs. WriteDeviceProperties in case the user unplugs the camera.
  1140. //
  1141. // Input:
  1142. // pWiasContext -- the item's context
  1143. // NumPropSpecs -- number of properties to be validated
  1144. // pPropSpecs -- properties to be validated
  1145. //
  1146. HRESULT
  1147. CWiaMiniDriver::ValidateDeviceProperties(
  1148. BYTE *pWiasContext,
  1149. LONG NumPropSpecs,
  1150. const PROPSPEC *pPropSpecs
  1151. )
  1152. {
  1153. USES_CONVERSION;
  1154. DBG_FN("CWiaMiniDriver::ValidateDeviceProperties");
  1155. HRESULT hr = S_OK;
  1156. //
  1157. // Call WIA service helper to check against valid values
  1158. //
  1159. hr = wiasValidateItemProperties(pWiasContext, NumPropSpecs, pPropSpecs);
  1160. if (FAILED(hr))
  1161. {
  1162. wiauDbgWarning("ValidateDeviceProperties", "wiasValidateItemProperties failed");
  1163. return hr;
  1164. }
  1165. {
  1166. //
  1167. // Ensure exclusive access
  1168. //
  1169. CPtpMutex cpm(m_hPtpMutex);
  1170. PROPVARIANT *pPropVar = new PROPVARIANT[NumPropSpecs];
  1171. if (pPropVar == NULL)
  1172. {
  1173. wiauDbgError("ValidateDeviceProperties", "memory allocation failed");
  1174. return E_OUTOFMEMORY;
  1175. }
  1176. //
  1177. // Read all of the new property values
  1178. //
  1179. hr = wiasReadMultiple(pWiasContext, NumPropSpecs, pPropSpecs, pPropVar, NULL);
  1180. if (FAILED(hr))
  1181. {
  1182. wiauDbgError("ValidateDeviceProperties", "wiasReadMultiple failed");
  1183. delete []pPropVar;
  1184. return hr;
  1185. }
  1186. //
  1187. // First do validation
  1188. //
  1189. LONG width = 0;
  1190. LONG height = 0;
  1191. for (int count = 0; count < NumPropSpecs; count++)
  1192. {
  1193. //
  1194. // Handle changes to the picture width
  1195. //
  1196. if (pPropSpecs[count].propid == WIA_DPC_PICT_WIDTH)
  1197. {
  1198. width = pPropVar[count].lVal;
  1199. height = 0;
  1200. //
  1201. // Look through the valid values and find the corresponding height
  1202. //
  1203. hr = FindCorrDimension(pWiasContext, &width, &height);
  1204. if (FAILED(hr))
  1205. {
  1206. wiauDbgError("ValidateDeviceProperties", "FindCorrDimension failed");
  1207. delete []pPropVar;
  1208. return hr;
  1209. }
  1210. //
  1211. // If the app is trying to set height, make sure it's correct
  1212. //
  1213. int idx;
  1214. if (wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_DPC_PICT_HEIGHT, &idx))
  1215. {
  1216. if (height != pPropVar[idx].lVal)
  1217. {
  1218. wiauDbgError("ValidateDeviceProperties", "app attempting to set incorrect height");
  1219. delete []pPropVar;
  1220. return E_INVALIDARG;
  1221. }
  1222. }
  1223. else
  1224. {
  1225. hr = wiasWritePropLong(pWiasContext, WIA_DPC_PICT_HEIGHT, height);
  1226. if (FAILED(hr))
  1227. {
  1228. wiauDbgError("ValidateDeviceProperties", "wiasWritePropLong failed");
  1229. delete []pPropVar;
  1230. return hr;
  1231. }
  1232. }
  1233. } // if (pPropSpecs[count].propid == WIA_DPC_PICT_WIDTH)
  1234. //
  1235. // Handle changes to the picture height
  1236. //
  1237. else if (pPropSpecs[count].propid == WIA_DPC_PICT_HEIGHT)
  1238. {
  1239. //
  1240. // See if the app is trying to set width also. If so, the height has
  1241. // already been set, so don't set it again.
  1242. //
  1243. if (!wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_DPC_PICT_WIDTH))
  1244. {
  1245. width = 0;
  1246. height = pPropVar[count].lVal;
  1247. //
  1248. // Look through the valid values and find the corresponding width
  1249. //
  1250. hr = FindCorrDimension(pWiasContext, &width, &height);
  1251. if (FAILED(hr))
  1252. {
  1253. wiauDbgError("ValidateDeviceProperties", "FindCorrDimension failed");
  1254. delete []pPropVar;
  1255. return hr;
  1256. }
  1257. //
  1258. // Set the width
  1259. //
  1260. hr = wiasWritePropLong(pWiasContext, WIA_DPC_PICT_WIDTH, width);
  1261. if (FAILED(hr))
  1262. {
  1263. wiauDbgError("ValidateDeviceProperties", "wiasWritePropLong failed");
  1264. delete []pPropVar;
  1265. return hr;
  1266. }
  1267. }
  1268. } // else if (pPropSpecs[count].propid == WIA_DPC_PICT_HEIGHT)
  1269. //
  1270. // Handle device time
  1271. //
  1272. else if (pPropSpecs[count].propid == WIA_DPA_DEVICE_TIME)
  1273. {
  1274. int propIndex = m_DeviceInfo.m_SupportedProps.Find(PTP_PROPERTYCODE_DATETIME);
  1275. CPtpPropDesc *pCurrentPD = &m_PropDescs[propIndex];
  1276. //
  1277. // Convert the date/time to a string
  1278. //
  1279. SYSTEMTIME *pSystemTime = (SYSTEMTIME *) pPropVar[count].caui.pElems;
  1280. hr = SystemTime2PtpTime(pSystemTime, &pCurrentPD->m_cbstrCurrent, m_bTwoDigitsMillisecondsOutput);
  1281. if (FAILED(hr))
  1282. {
  1283. wiauDbgError("ValidateDeviceProperties", "invalid date/time string");
  1284. delete []pPropVar;
  1285. return E_FAIL;
  1286. }
  1287. //
  1288. // Write the new date/time to the device
  1289. //
  1290. hr = m_pPTPCamera->SetDevicePropValue(PTP_PROPERTYCODE_DATETIME, pCurrentPD);
  1291. if (FAILED(hr))
  1292. {
  1293. wiauDbgError("ValidateDeviceProperties", "SetDevicePropValue failed");
  1294. delete []pPropVar;
  1295. return hr;
  1296. }
  1297. } // else if (pPropSpecs[count].propid == WIA_DPA_DEVICE_TIME)
  1298. } // for (count...
  1299. //
  1300. // Now write the new values to the camera
  1301. //
  1302. PROPSPEC propSpec;
  1303. BOOL bWroteWidthHeight = FALSE;
  1304. WORD propCode = 0;
  1305. int pdIdx = 0;
  1306. CPtpPropDesc *pCurrentPD = NULL;
  1307. for (int count = 0; count < NumPropSpecs; count++)
  1308. {
  1309. //
  1310. // Skip date/time since it was already written above
  1311. //
  1312. if (pPropSpecs[count].propid == WIA_DPA_DEVICE_TIME)
  1313. continue;
  1314. //
  1315. // Handle changes to the picture width or height
  1316. //
  1317. if ((pPropSpecs[count].propid == WIA_DPC_PICT_WIDTH) ||
  1318. (pPropSpecs[count].propid == WIA_DPC_PICT_HEIGHT))
  1319. {
  1320. //
  1321. // If width and height were already written, don't do it again
  1322. //
  1323. if (bWroteWidthHeight)
  1324. continue;
  1325. TCHAR ptcsImageSize[MAX_PATH];
  1326. hr = StringCchPrintfW(ptcsImageSize, ARRAYSIZE(ptcsImageSize), TEXT("%dx%d"), width, height);
  1327. if (FAILED(hr))
  1328. {
  1329. wiauDbgError("ValidateDeviceProperties", "StringCchPrintfW failed");
  1330. delete []pPropVar;
  1331. return E_FAIL;
  1332. }
  1333. propCode = PTP_PROPERTYCODE_IMAGESIZE;
  1334. pdIdx = m_DeviceInfo.m_SupportedProps.Find(propCode);
  1335. if (pdIdx < 0)
  1336. {
  1337. wiauDbgWarning("ValidateDeviceProperties", "Width/height not supported by camera");
  1338. continue;
  1339. }
  1340. pCurrentPD = &m_PropDescs[pdIdx];
  1341. hr = pCurrentPD->m_cbstrCurrent.Copy(T2W(ptcsImageSize));
  1342. if (FAILED(hr))
  1343. {
  1344. wiauDbgError("ValidateDeviceProperties", "Copy bstr failed");
  1345. delete []pPropVar;
  1346. return hr;
  1347. }
  1348. //
  1349. // Write the new value to the device
  1350. //
  1351. hr = m_pPTPCamera->SetDevicePropValue(propCode, pCurrentPD);
  1352. if (FAILED(hr))
  1353. {
  1354. wiauDbgError("ValidateDeviceProperties", "SetDevicePropValue failed");
  1355. delete []pPropVar;
  1356. return hr;
  1357. }
  1358. bWroteWidthHeight = TRUE;
  1359. }
  1360. else
  1361. {
  1362. //
  1363. // Find the prop code and prop desc structure
  1364. //
  1365. propCode = PropIdToPropCode(pPropSpecs[count].propid);
  1366. pdIdx = m_DeviceInfo.m_SupportedProps.Find(propCode);
  1367. if (pdIdx < 0)
  1368. {
  1369. wiauDbgWarning("ValidateDeviceProperties", "Property not supported by camera");
  1370. continue;
  1371. }
  1372. pCurrentPD = &m_PropDescs[pdIdx];
  1373. //
  1374. // Put the new value into the PropSpec structure
  1375. //
  1376. if (pPropVar[count].vt == VT_BSTR)
  1377. {
  1378. hr = pCurrentPD->m_cbstrCurrent.Copy(pPropVar[count].bstrVal);
  1379. if (FAILED(hr))
  1380. {
  1381. wiauDbgError("ValidateDeviceProperties", "Copy bstr failed");
  1382. delete []pPropVar;
  1383. return hr;
  1384. }
  1385. }
  1386. else if (pPropVar[count].vt == VT_I4)
  1387. {
  1388. pCurrentPD->m_lCurrent = pPropVar[count].lVal;
  1389. }
  1390. else
  1391. {
  1392. wiauDbgError("ValidateDeviceProperties", "unsupported variant type");
  1393. delete []pPropVar;
  1394. return E_FAIL;
  1395. }
  1396. //
  1397. // Write the new value to the device
  1398. //
  1399. hr = m_pPTPCamera->SetDevicePropValue(propCode, pCurrentPD);
  1400. if (FAILED(hr))
  1401. {
  1402. wiauDbgError("ValidateDeviceProperties", "SetDevicePropValue failed");
  1403. delete []pPropVar;
  1404. return hr;
  1405. }
  1406. }
  1407. }
  1408. delete []pPropVar;
  1409. }
  1410. return hr;
  1411. }
  1412. //
  1413. // This function finds the corresponding height for a width value, or vice versa. Set the
  1414. // value to find to zero.
  1415. //
  1416. // Input:
  1417. // pWidth -- pointer to the width value
  1418. // pHeight -- pointer to the height value
  1419. //
  1420. HRESULT
  1421. CWiaMiniDriver::FindCorrDimension(BYTE *pWiasContext, LONG *pWidth, LONG *pHeight)
  1422. {
  1423. DBG_FN("CWiaMiniDriver::FindCorrDimensions");
  1424. HRESULT hr = S_OK;
  1425. if (!pWiasContext ||
  1426. (*pWidth == 0 && *pHeight == 0))
  1427. {
  1428. wiauDbgError("FindCorrDimension", "invalid args");
  1429. return E_INVALIDARG;
  1430. }
  1431. PROPSPEC ps[2];
  1432. ULONG af[2];
  1433. PROPVARIANT pv[2];
  1434. ps[0].ulKind = PRSPEC_PROPID;
  1435. ps[0].propid = WIA_DPC_PICT_WIDTH;
  1436. ps[1].ulKind = PRSPEC_PROPID;
  1437. ps[1].propid = WIA_DPC_PICT_HEIGHT;
  1438. hr = wiasGetPropertyAttributes(pWiasContext, 2, ps, af, pv);
  1439. if (FAILED(hr))
  1440. {
  1441. wiauDbgError("FindCorrDimension", "wiasGetPropertyAttributes failed");
  1442. return E_FAIL;
  1443. }
  1444. int count = 0 ;
  1445. if (af[0] & WIA_PROP_LIST)
  1446. {
  1447. LONG numValues = pv[0].cal.pElems[WIA_LIST_COUNT];
  1448. LONG *pValidWidths = &pv[0].cal.pElems[WIA_LIST_VALUES];
  1449. LONG *pValidHeights = &pv[1].cal.pElems[WIA_LIST_VALUES];
  1450. if (*pWidth == 0)
  1451. {
  1452. //
  1453. // Find the height in the valid values array
  1454. //
  1455. for (count = 0; count < numValues; count++)
  1456. {
  1457. if (pValidHeights[count] == *pHeight)
  1458. {
  1459. //
  1460. // Set the width and exit
  1461. //
  1462. *pWidth = pValidWidths[count];
  1463. break;
  1464. }
  1465. }
  1466. }
  1467. else
  1468. {
  1469. //
  1470. // Find the width in the valid values array
  1471. //
  1472. for (count = 0; count < numValues; count++)
  1473. {
  1474. if (pValidWidths[count] == *pWidth)
  1475. {
  1476. //
  1477. // Set the height and exit
  1478. //
  1479. *pHeight = pValidHeights[count];
  1480. break;
  1481. }
  1482. }
  1483. }
  1484. }
  1485. else if (af[0] & WIA_PROP_RANGE)
  1486. {
  1487. LONG minWidth = pv[0].cal.pElems[WIA_RANGE_MIN];
  1488. LONG maxWidth = pv[0].cal.pElems[WIA_RANGE_MAX];
  1489. LONG stepWidth = pv[0].cal.pElems[WIA_RANGE_STEP];
  1490. LONG minHeight = pv[1].cal.pElems[WIA_RANGE_MIN];
  1491. LONG maxHeight = pv[1].cal.pElems[WIA_RANGE_MAX];
  1492. LONG stepHeight = pv[1].cal.pElems[WIA_RANGE_STEP];
  1493. if (*pWidth == 0)
  1494. {
  1495. //
  1496. // Set the width to the proportionally correct value, clipping to the step value
  1497. //
  1498. *pWidth = FindProportionalValue(*pHeight, minHeight, maxHeight, minWidth, maxWidth, stepWidth);
  1499. }
  1500. else
  1501. {
  1502. //
  1503. // Set the height to the proportionally correct value, clipping to the step value
  1504. //
  1505. *pHeight = FindProportionalValue(*pWidth, minWidth, maxWidth, minHeight, maxHeight, stepHeight);
  1506. }
  1507. }
  1508. return hr;
  1509. }
  1510. //
  1511. // This function takes the proportion of valueX between minX and maxX and uses that to
  1512. // find a value of the same proportion between minY and maxY. It then clips that value
  1513. // to the step value
  1514. //
  1515. int CWiaMiniDriver::FindProportionalValue(int valueX, int minX, int maxX, int minY, int maxY, int stepY)
  1516. {
  1517. int valueY;
  1518. //
  1519. // Find proportional value
  1520. //
  1521. valueY = (valueX - minX) * (maxY - minY) / (maxX - minX) + minY;
  1522. //
  1523. // Clip the value to the step
  1524. //
  1525. valueY = ((valueY + ((stepY - 1) / 2)) - minY) / stepY * stepY + minY;
  1526. return valueY;
  1527. }
  1528. //
  1529. // This helper function returns a pointer to the property info structure
  1530. // based on the property code
  1531. //
  1532. // Input:
  1533. // PropCode -- the format code
  1534. //
  1535. // Output:
  1536. // Returns pointer to the property info structure
  1537. //
  1538. PPROP_INFO
  1539. CWiaMiniDriver::PropCodeToPropInfo(WORD PropCode)
  1540. {
  1541. DBG_FN("CWiaMiniDriver::PropCodeToPropInfo");
  1542. PPROP_INFO pPropInfo = NULL;
  1543. UINT index = 0;
  1544. const WORD PROPCODE_MASK = 0x0fff;
  1545. if (PropCode & PTP_DATACODE_VENDORMASK)
  1546. {
  1547. //
  1548. // Look up vendor extended PropCode
  1549. //
  1550. pPropInfo = m_VendorPropMap.Lookup(PropCode);
  1551. if (!pPropInfo)
  1552. {
  1553. pPropInfo = &g_PropInfo[0];
  1554. }
  1555. }
  1556. else
  1557. {
  1558. //
  1559. // Look up the prop code in the prop info array
  1560. //
  1561. index = PropCode & PROPCODE_MASK;
  1562. if (index >= g_NumPropInfo)
  1563. {
  1564. index = 0;
  1565. }
  1566. pPropInfo = &g_PropInfo[index];
  1567. }
  1568. return pPropInfo;
  1569. }
  1570. //
  1571. // This helper function returns a pointer to the format info structure
  1572. // based on the format code
  1573. //
  1574. // Input:
  1575. // FormatCode -- the format code
  1576. // AssocType -- association type (for associations)
  1577. //
  1578. // Output:
  1579. // Returns pointer to the format info structure
  1580. //
  1581. PFORMAT_INFO
  1582. FormatCodeToFormatInfo(WORD FormatCode, WORD AssocType)
  1583. {
  1584. DBG_FN("FormatCodeToFormatString");
  1585. PFORMAT_INFO pFormatInfo = NULL;
  1586. UINT index = 0;
  1587. const WORD FORMATCODE_MASK = 0x07ff;
  1588. if (FormatCode & PTP_DATACODE_VENDORMASK)
  1589. {
  1590. //
  1591. // WIAFIX-9/6/2000-davepar This should ideally query GDI+ somehow for a filter
  1592. // which the vendor could register
  1593. //
  1594. pFormatInfo = &g_NonImageFormatInfo[0];
  1595. }
  1596. else if (FormatCode == PTP_FORMATCODE_ASSOCIATION)
  1597. {
  1598. //
  1599. // Look up the association type
  1600. //
  1601. index = AssocType;
  1602. if (index > g_NumAssocFormatInfo)
  1603. {
  1604. index = 0;
  1605. }
  1606. pFormatInfo = &g_AssocFormatInfo[index];
  1607. }
  1608. else
  1609. {
  1610. //
  1611. // Look up the format code in either the image or non-image format info array
  1612. //
  1613. index = FormatCode & FORMATCODE_MASK;
  1614. if (FormatCode & PTP_FORMATMASK_IMAGE)
  1615. {
  1616. if (index > g_NumImageFormatInfo)
  1617. {
  1618. index = 0;
  1619. }
  1620. pFormatInfo = &g_ImageFormatInfo[index];
  1621. }
  1622. else
  1623. {
  1624. if (index >= g_NumNonImageFormatInfo)
  1625. {
  1626. index = 0;
  1627. }
  1628. pFormatInfo = &g_NonImageFormatInfo[index];
  1629. }
  1630. }
  1631. return pFormatInfo;
  1632. }
  1633. //
  1634. // This function converts a WIA format GUID into a PTP format code
  1635. //
  1636. WORD
  1637. FormatGuidToFormatCode(GUID *pFormatGuid)
  1638. {
  1639. WORD count = 0;
  1640. //
  1641. // Look through the image formats first
  1642. //
  1643. for (count = 0; count < g_NumImageFormatInfo; count++)
  1644. {
  1645. if (g_ImageFormatInfo[count].FormatGuid &&
  1646. IsEqualGUID(*pFormatGuid, *(g_ImageFormatInfo[count].FormatGuid)))
  1647. {
  1648. return count | PTP_FORMATCODE_IMAGE_UNDEFINED;
  1649. }
  1650. }
  1651. //
  1652. // Then look through the non image formats
  1653. //
  1654. for (count = 0; count < g_NumNonImageFormatInfo; count++)
  1655. {
  1656. if (g_NonImageFormatInfo[count].FormatGuid &&
  1657. IsEqualGUID(*pFormatGuid, *(g_NonImageFormatInfo[count].FormatGuid)))
  1658. {
  1659. return count | PTP_FORMATCODE_UNDEFINED;
  1660. }
  1661. }
  1662. //
  1663. // The GUID wasn't found in either array
  1664. //
  1665. return PTP_FORMATCODE_UNDEFINED;
  1666. }
  1667. //
  1668. // This function looks up a prop id in the property info array and returns a
  1669. // property code for it.
  1670. //
  1671. WORD
  1672. PropIdToPropCode(PROPID PropId)
  1673. {
  1674. WORD PropCode;
  1675. for (PropCode = 0; PropCode < g_NumPropInfo; PropCode++)
  1676. {
  1677. if (g_PropInfo[PropCode].PropId == PropId)
  1678. {
  1679. return PropCode | PTP_PROPERTYCODE_UNDEFINED;
  1680. }
  1681. }
  1682. //
  1683. // Not found
  1684. //
  1685. return 0;
  1686. }
  1687. //
  1688. // This function splits a PTP image size string (WXH) into two separate longs
  1689. //
  1690. VOID
  1691. SplitImageSize(
  1692. CBstr cbstr,
  1693. LONG *pWidth,
  1694. LONG *pHeight
  1695. )
  1696. {
  1697. USES_CONVERSION;
  1698. int num = _stscanf(W2T(cbstr.String()), TEXT("%dx%d"), pWidth, pHeight);
  1699. //
  1700. // The spec mentions "x" as divider, but let's be paranoid and check "X" as well
  1701. //
  1702. if (num != 2)
  1703. {
  1704. num = _stscanf(W2T(cbstr.String()), TEXT("%dX%d"), pWidth, pHeight);
  1705. }
  1706. if (num != 2)
  1707. {
  1708. wiauDbgError("SplitImageSize", "invalid current image dimensions");
  1709. *pWidth = 0;
  1710. *pHeight = 0;
  1711. }
  1712. return;
  1713. }