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.

1870 lines
60 KiB

  1. /*++
  2. Copyright (C) 1999- Microsoft Corporation
  3. Module Name:
  4. imgitem.cpp
  5. Abstract:
  6. This module implements image item related function of CWiaMiniDriver class
  7. Author:
  8. William Hsieh (williamh) created
  9. Revision History:
  10. --*/
  11. #include "pch.h"
  12. //
  13. // Minimum data call back transfer buffer size
  14. //
  15. const LONG MIN_BUFFER_SIZE = 0x8000;
  16. //
  17. // Arrays used for setting up valid value lists for properties
  18. //
  19. LONG g_TymedArray[] = {
  20. TYMED_FILE,
  21. TYMED_CALLBACK
  22. };
  23. //
  24. // This function initializes the item's properties
  25. // Input:
  26. // pWiasContext -- wias service context
  27. // lFlags -- misc flags
  28. // plDevErrVal -- to return device error;
  29. //
  30. HRESULT
  31. CWiaMiniDriver::InitItemProperties(BYTE *pWiasContext)
  32. {
  33. DBG_FN("CWiaMiniDriver::InitItemProperties");
  34. HRESULT hr = S_OK;
  35. //
  36. // Locals
  37. //
  38. LONG ItemType = 0;
  39. FORMAT_INFO *pFormatInfo = NULL;
  40. BSTR bstrFileExt = NULL;
  41. CLSID *pImageFormats = NULL;
  42. hr = wiasGetItemType(pWiasContext, &ItemType);
  43. if (FAILED(hr))
  44. {
  45. wiauDbgError("InitItemProperties", "wiasGetItemType failed");
  46. return hr;
  47. }
  48. BOOL bBitmap = FALSE; // Indicates that preferred format is bitmap
  49. LONG lBytesPerLine = 0;
  50. //
  51. // There are no properties for storage items. In fact, there are no driver items created for
  52. // stores.
  53. //
  54. if (ItemType & WiaItemTypeStorage)
  55. return hr;
  56. DRVITEM_CONTEXT *pItemCtx;
  57. hr = WiasContextToItemContext(pWiasContext, &pItemCtx, NULL);
  58. if (FAILED(hr))
  59. {
  60. wiauDbgError("InitItemProperties", "WiasContextToItemContext failed");
  61. return hr;
  62. }
  63. //
  64. // Set up properties that are used for all item types
  65. //
  66. CWiauPropertyList ItemProps;
  67. CPtpObjectInfo *pObjectInfo = pItemCtx->pObjectInfo;
  68. const INT NUM_ITEM_PROPS = 24;
  69. hr = ItemProps.Init(NUM_ITEM_PROPS);
  70. if (FAILED(hr))
  71. {
  72. wiauDbgError("InitItemProperties", "Init failed");
  73. return hr;
  74. }
  75. INT index;
  76. //
  77. // WIA_IPA_ITEM_TIME
  78. //
  79. SYSTEMTIME SystemTime;
  80. hr = GetObjectTime(pObjectInfo, &SystemTime);
  81. if (FAILED(hr))
  82. {
  83. wiauDbgError("InitItemProperties", "GetObjectTime failed");
  84. return hr;
  85. }
  86. hr = ItemProps.DefineProperty(&index, WIA_IPA_ITEM_TIME, WIA_IPA_ITEM_TIME_STR,
  87. WIA_PROP_READ, WIA_PROP_NONE);
  88. if (FAILED(hr)) goto failure;
  89. ItemProps.SetCurrentValue(index, &SystemTime);
  90. //
  91. // WIA_IPA_ACCESS_RIGHTS
  92. //
  93. LONG lProtection;
  94. hr = IsObjectProtected(pObjectInfo, lProtection);
  95. if (FAILED(hr))
  96. {
  97. wiauDbgError("InitItemProperties", "IsObjectProtected failed");
  98. return hr;
  99. }
  100. hr = ItemProps.DefineProperty(&index, WIA_IPA_ACCESS_RIGHTS, WIA_IPA_ACCESS_RIGHTS_STR,
  101. WIA_PROP_READ, WIA_PROP_FLAG | WIA_PROP_NONE);
  102. if (FAILED(hr)) goto failure;
  103. //
  104. // If device does not support delete command, access rights are always Read-Only
  105. //
  106. if (m_DeviceInfo.m_SupportedOps.Find(PTP_OPCODE_DELETEOBJECT) < 0)
  107. {
  108. lProtection = WIA_PROP_READ;
  109. ItemProps.SetCurrentValue(index, lProtection);
  110. }
  111. else
  112. {
  113. //
  114. // If device supports the SetObjectProtection command, item access rights is r/w
  115. //
  116. if (m_DeviceInfo.m_SupportedOps.Find(PTP_OPCODE_SETOBJECTPROTECTION) >= 0)
  117. {
  118. ItemProps.SetAccessSubType(index, WIA_PROP_RW, WIA_PROP_FLAG);
  119. ItemProps.SetValidValues(index, lProtection, lProtection, WIA_ITEM_RWD);
  120. }
  121. else
  122. {
  123. ItemProps.SetCurrentValue(index, lProtection);
  124. }
  125. }
  126. pFormatInfo = FormatCodeToFormatInfo(pObjectInfo->m_FormatCode);
  127. //
  128. // WIA_IPA_FILENAME_EXTENSION
  129. //
  130. hr = ItemProps.DefineProperty(&index, WIA_IPA_FILENAME_EXTENSION, WIA_IPA_FILENAME_EXTENSION_STR,
  131. WIA_PROP_READ, WIA_PROP_NONE);
  132. if (FAILED(hr)) goto failure;
  133. if(pFormatInfo->ExtString && pFormatInfo->ExtString[0]) {
  134. bstrFileExt = SysAllocString(pFormatInfo->ExtString);
  135. } else {
  136. if(pObjectInfo->m_cbstrExtension.Length()) {
  137. bstrFileExt = SysAllocString(pObjectInfo->m_cbstrExtension.String());
  138. }
  139. }
  140. ItemProps.SetCurrentValue(index, bstrFileExt);
  141. //
  142. // Set up properties common to files
  143. //
  144. if (ItemType & WiaItemTypeFile)
  145. {
  146. //
  147. // WIA_IPA_PREFERRED_FORMAT
  148. //
  149. hr = ItemProps.DefineProperty(&index, WIA_IPA_PREFERRED_FORMAT, WIA_IPA_PREFERRED_FORMAT_STR,
  150. WIA_PROP_READ, WIA_PROP_NONE);
  151. if (FAILED(hr)) goto failure;
  152. ItemProps.SetCurrentValue(index, pFormatInfo->FormatGuid);
  153. bBitmap = IsEqualGUID(WiaImgFmt_BMP, *pFormatInfo->FormatGuid) ||
  154. IsEqualGUID(WiaImgFmt_MEMORYBMP, *pFormatInfo->FormatGuid);
  155. //
  156. // WIA_IPA_FORMAT
  157. //
  158. // For images, BMP may also be added below
  159. //
  160. hr = ItemProps.DefineProperty(&index, WIA_IPA_FORMAT, WIA_IPA_FORMAT_STR,
  161. WIA_PROP_READ, WIA_PROP_NONE);
  162. if (FAILED(hr)) goto failure;
  163. ItemProps.SetAccessSubType(index, WIA_PROP_RW, WIA_PROP_LIST);
  164. ItemProps.SetCurrentValue(index, pFormatInfo->FormatGuid);
  165. ItemProps.SetValidValues(index, pFormatInfo->FormatGuid, pFormatInfo->FormatGuid,
  166. 1, &pFormatInfo->FormatGuid);
  167. //
  168. // WIA_IPA_COMPRESSION
  169. //
  170. hr = ItemProps.DefineProperty(&index, WIA_IPA_COMPRESSION, WIA_IPA_COMPRESSION_STR,
  171. WIA_PROP_READ, WIA_PROP_NONE);
  172. if (FAILED(hr)) goto failure;
  173. ItemProps.SetCurrentValue(index, (LONG) WIA_COMPRESSION_NONE);
  174. //
  175. // WIA_IPA_TYMED
  176. //
  177. hr = ItemProps.DefineProperty(&index, WIA_IPA_TYMED, WIA_IPA_TYMED_STR,
  178. WIA_PROP_RW, WIA_PROP_LIST);
  179. if (FAILED(hr)) goto failure;
  180. ItemProps.SetValidValues(index, TYMED_FILE, TYMED_FILE,
  181. sizeof(g_TymedArray) / sizeof(g_TymedArray[0]), g_TymedArray);
  182. //
  183. // WIA_IPA_ITEM_SIZE
  184. //
  185. hr = ItemProps.DefineProperty(&index, WIA_IPA_ITEM_SIZE, WIA_IPA_ITEM_SIZE_STR,
  186. WIA_PROP_READ, WIA_PROP_NONE);
  187. if (FAILED(hr)) goto failure;
  188. if (bBitmap) {
  189. lBytesPerLine = ((pObjectInfo->m_ImagePixWidth * pObjectInfo->m_ImageBitDepth + 31) & ~31) / 8;
  190. ItemProps.SetCurrentValue(index, (LONG) (lBytesPerLine * pObjectInfo->m_ImagePixHeight));
  191. }
  192. else
  193. ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_CompressedSize);
  194. //
  195. // WIA_IPA_MIN_BUFFER_SIZE
  196. //
  197. hr = ItemProps.DefineProperty(&index, WIA_IPA_MIN_BUFFER_SIZE, WIA_IPA_MIN_BUFFER_SIZE_STR,
  198. WIA_PROP_READ, WIA_PROP_NONE);
  199. if (FAILED(hr)) goto failure;
  200. LONG minBufSize;
  201. if (!bBitmap && pObjectInfo->m_CompressedSize > 0)
  202. minBufSize = min(MIN_BUFFER_SIZE, pObjectInfo->m_CompressedSize);
  203. else
  204. minBufSize = MIN_BUFFER_SIZE;
  205. ItemProps.SetCurrentValue(index, minBufSize);
  206. }
  207. //
  208. // Set up the image-only properties
  209. //
  210. if (ItemType & WiaItemTypeImage)
  211. {
  212. //
  213. // WIA_IPA_DATATYPE
  214. //
  215. hr = ItemProps.DefineProperty(&index, WIA_IPA_DATATYPE, WIA_IPA_DATATYPE_STR,
  216. WIA_PROP_READ, WIA_PROP_NONE);
  217. if (FAILED(hr)) goto failure;
  218. if(pObjectInfo->m_ImageBitDepth <= 8) {
  219. ItemProps.SetCurrentValue(index, (LONG) WIA_DATA_GRAYSCALE);
  220. } else {
  221. ItemProps.SetCurrentValue(index, (LONG) WIA_DATA_COLOR);
  222. }
  223. //
  224. // WIA_IPA_DEPTH
  225. //
  226. hr = ItemProps.DefineProperty(&index, WIA_IPA_DEPTH, WIA_IPA_DEPTH_STR,
  227. WIA_PROP_READ, WIA_PROP_NONE);
  228. if (FAILED(hr)) goto failure;
  229. ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_ImageBitDepth);
  230. //
  231. // WIA_IPA_FORMAT
  232. //
  233. // If the image format is something that can be converted, change the access to
  234. // read/write and add BMP to the valid value list.
  235. //
  236. if (pFormatInfo->FormatGuid)
  237. {
  238. index = ItemProps.LookupPropId(WIA_IPA_FORMAT);
  239. ItemProps.SetAccessSubType(index, WIA_PROP_RW, WIA_PROP_LIST);
  240. pImageFormats = new CLSID[3];
  241. if(!pImageFormats) {
  242. wiauDbgError("InitItemProperties", "failed to allocate 3 GUIDs");
  243. hr = E_OUTOFMEMORY;
  244. goto failure;
  245. }
  246. pImageFormats[0] = *pFormatInfo->FormatGuid;
  247. pImageFormats[1] = WiaImgFmt_BMP;
  248. pImageFormats[2] = WiaImgFmt_MEMORYBMP;
  249. ItemProps.SetValidValues(index, pFormatInfo->FormatGuid, pFormatInfo->FormatGuid,
  250. 3,
  251. &pImageFormats);
  252. }
  253. //
  254. // WIA_IPA_CHANNELS_PER_PIXEL
  255. //
  256. hr = ItemProps.DefineProperty(&index, WIA_IPA_CHANNELS_PER_PIXEL, WIA_IPA_CHANNELS_PER_PIXEL_STR,
  257. WIA_PROP_READ, WIA_PROP_NONE);
  258. if (FAILED(hr)) goto failure;
  259. ItemProps.SetCurrentValue(index, (LONG) (pObjectInfo->m_ImageBitDepth == 8 ? 1 : 3));
  260. //
  261. // WIA_IPA_BITS_PER_CHANNEL
  262. //
  263. hr = ItemProps.DefineProperty(&index, WIA_IPA_BITS_PER_CHANNEL, WIA_IPA_BITS_PER_CHANNEL_STR,
  264. WIA_PROP_READ, WIA_PROP_NONE);
  265. if (FAILED(hr)) goto failure;
  266. ItemProps.SetCurrentValue(index, (LONG) 8);
  267. //
  268. // WIA_IPA_PLANAR
  269. //
  270. hr = ItemProps.DefineProperty(&index, WIA_IPA_PLANAR, WIA_IPA_PLANAR_STR,
  271. WIA_PROP_READ, WIA_PROP_NONE);
  272. if (FAILED(hr)) goto failure;
  273. ItemProps.SetCurrentValue(index, (LONG) WIA_PACKED_PIXEL);
  274. //
  275. // WIA_IPA_PIXELS_PER_LINE
  276. //
  277. hr = ItemProps.DefineProperty(&index, WIA_IPA_PIXELS_PER_LINE, WIA_IPA_PIXELS_PER_LINE_STR,
  278. WIA_PROP_READ, WIA_PROP_NONE);
  279. if (FAILED(hr)) goto failure;
  280. ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_ImagePixWidth);
  281. //
  282. // WIA_IPA_BYTES_PER_LINE
  283. //
  284. hr = ItemProps.DefineProperty(&index, WIA_IPA_BYTES_PER_LINE, WIA_IPA_BYTES_PER_LINE_STR,
  285. WIA_PROP_READ, WIA_PROP_NONE);
  286. if (FAILED(hr)) goto failure;
  287. if (bBitmap)
  288. lBytesPerLine;
  289. else
  290. ItemProps.SetCurrentValue(index, (LONG) 0);
  291. //
  292. // WIA_IPA_NUMBER_OF_LINES
  293. //
  294. hr = ItemProps.DefineProperty(&index, WIA_IPA_NUMBER_OF_LINES, WIA_IPA_NUMBER_OF_LINES_STR,
  295. WIA_PROP_READ, WIA_PROP_NONE);
  296. if (FAILED(hr)) goto failure;
  297. ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_ImagePixHeight);
  298. //
  299. // WIA_IPC_SEQUENCE
  300. //
  301. if (pObjectInfo->m_SequenceNumber > 0)
  302. {
  303. hr = ItemProps.DefineProperty(&index, WIA_IPC_SEQUENCE, WIA_IPC_SEQUENCE_STR,
  304. WIA_PROP_READ, WIA_PROP_NONE);
  305. if (FAILED(hr)) goto failure;
  306. ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_SequenceNumber);
  307. }
  308. //
  309. // WIA_IPC_TIMEDELAY
  310. //
  311. // This property needs to be populated from the AssociationDesc field in the parent's ObjectInfo
  312. // structure, but only if the parent's AssociationType field is TimeSequence.
  313. // WIAFIX-10/3/2000-davepar Implement this property
  314. }
  315. //
  316. // Set up properties common to image and video items that have
  317. // thumbnails
  318. //
  319. if (ItemType & (WiaItemTypeImage | WiaItemTypeVideo) && pObjectInfo->m_ThumbPixWidth)
  320. {
  321. //
  322. // WIA_IPC_THUMBNAIL
  323. //
  324. hr = ItemProps.DefineProperty(&index, WIA_IPC_THUMBNAIL, WIA_IPC_THUMBNAIL_STR,
  325. WIA_PROP_READ, WIA_PROP_NONE);
  326. if (FAILED(hr)) goto failure;
  327. ItemProps.SetCurrentValue(index, (BYTE *) NULL, 0);
  328. //
  329. // WIA_IPC_THUMB_WIDTH
  330. //
  331. hr = ItemProps.DefineProperty(&index, WIA_IPC_THUMB_WIDTH, WIA_IPC_THUMB_WIDTH_STR,
  332. WIA_PROP_READ, WIA_PROP_NONE);
  333. if (FAILED(hr)) goto failure;
  334. ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_ThumbPixWidth);
  335. //
  336. // WIA_IPC_THUMB_HEIGHT
  337. //
  338. hr = ItemProps.DefineProperty(&index, WIA_IPC_THUMB_HEIGHT, WIA_IPC_THUMB_HEIGHT_STR,
  339. WIA_PROP_READ, WIA_PROP_NONE);
  340. if (FAILED(hr)) goto failure;
  341. ItemProps.SetCurrentValue(index, (LONG) pObjectInfo->m_ThumbPixHeight);
  342. }
  343. //
  344. // Last step: send all the properties to WIA
  345. //
  346. hr = ItemProps.SendToWia(pWiasContext);
  347. if (FAILED(hr))
  348. {
  349. wiauDbgErrorHr(hr, "InitItemProperties", "SendToWia failed");
  350. goto failure;
  351. }
  352. if (bstrFileExt)
  353. SysFreeString(bstrFileExt);
  354. delete [] pImageFormats;
  355. return hr;
  356. //
  357. // Any failures from DefineProperty will end up here
  358. //
  359. failure:
  360. delete [] pImageFormats;
  361. if (bstrFileExt)
  362. SysFreeString(bstrFileExt);
  363. wiauDbgErrorHr(hr, "InitItemProperties", "DefineProperty failed");
  364. return hr;
  365. }
  366. //
  367. // This function determines the protection status (whether an object can be
  368. // deleted or written to) of an object on the device.
  369. //
  370. // Input:
  371. // pObjectInfo -- pointer to the ObjectInfo structure
  372. // Output:
  373. // bProtected -- indicates whether the object is protected
  374. //
  375. HRESULT
  376. CWiaMiniDriver::IsObjectProtected(
  377. CPtpObjectInfo *pObjectInfo,
  378. LONG &lProtection)
  379. {
  380. DBG_FN("CWiaMiniDriver::IsObjectProtected");
  381. HRESULT hr = S_OK;
  382. lProtection = WIA_ITEM_READ;
  383. if (!pObjectInfo)
  384. {
  385. wiauDbgError("ObjectProtected", "invalid arg");
  386. return E_INVALIDARG;
  387. }
  388. if (pObjectInfo->m_ProtectionStatus == PTP_PROTECTIONSTATUS_READONLY)
  389. return hr;
  390. //
  391. // Check the protection status of the store as well
  392. //
  393. INT storeIndex = m_StorageIds.Find(pObjectInfo->m_StorageId);
  394. if (storeIndex < 0)
  395. {
  396. wiauDbgWarning("ObjectProtected", "couldn't find the object's store");
  397. return hr;
  398. }
  399. switch (m_StorageInfos[storeIndex].m_AccessCapability)
  400. {
  401. case PTP_STORAGEACCESS_RWD:
  402. lProtection = WIA_ITEM_RWD;
  403. break;
  404. case PTP_STORAGEACCESS_R:
  405. lProtection = WIA_ITEM_READ;
  406. break;
  407. case PTP_STORAGEACCESS_RD:
  408. lProtection = WIA_ITEM_RD;
  409. break;
  410. default:
  411. //
  412. // Not a fatal error, but this is an unknown access capability. Use read-only.
  413. //
  414. wiauDbgError("ObjectProtected", "unknown storage access capability");
  415. lProtection = WIA_ITEM_READ;
  416. break;
  417. }
  418. return hr;
  419. }
  420. //
  421. // This function gets the object time and converts it to a system time
  422. //
  423. // Input:
  424. // pObjNode -- the object
  425. // pSystemTime -- to receive the object time
  426. // Output:
  427. // HRESULT
  428. //
  429. HRESULT
  430. CWiaMiniDriver::GetObjectTime(
  431. CPtpObjectInfo *pObjectInfo,
  432. SYSTEMTIME *pSystemTime
  433. )
  434. {
  435. DBG_FN("CWiaMiniDriver::GetObjectTime");
  436. HRESULT hr = S_OK;
  437. CBstr *pTimeStr = NULL;
  438. if (!pObjectInfo || !pSystemTime)
  439. {
  440. wiauDbgError("GetObjectTime", "invalid arg");
  441. return E_INVALIDARG;
  442. }
  443. //
  444. // Try to use the modification date, then the capture date
  445. //
  446. if (pObjectInfo->m_cbstrModificationDate.Length() > 0)
  447. pTimeStr = &pObjectInfo->m_cbstrModificationDate;
  448. else if (pObjectInfo->m_cbstrCaptureDate.Length() > 0)
  449. pTimeStr = &pObjectInfo->m_cbstrCaptureDate;
  450. //
  451. // See if a valid date/time was found, otherwise use system time
  452. //
  453. if (pTimeStr)
  454. {
  455. hr = PtpTime2SystemTime(pTimeStr, pSystemTime);
  456. if (FAILED(hr))
  457. {
  458. wiauDbgError("GetObjectTime", "PtpTime2SystemTime failed");
  459. return hr;
  460. }
  461. }
  462. else
  463. {
  464. GetLocalTime(pSystemTime);
  465. }
  466. return hr;
  467. }
  468. //
  469. // This function reads item properties. In this situation, only the thumbnail
  470. // properties are important.
  471. //
  472. // Input:
  473. // pWiasContext -- wia service context
  474. // NumPropSpecs -- number of properties to read
  475. // pPropSpecs -- what properties to read
  476. //
  477. HRESULT
  478. CWiaMiniDriver::ReadItemProperties(
  479. BYTE *pWiasContext,
  480. LONG NumPropSpecs,
  481. const PROPSPEC *pPropSpecs
  482. )
  483. {
  484. DBG_FN("CWiaMiniDriver::ReadItemProperties");
  485. HRESULT hr = S_OK;
  486. LONG ItemType = 0;
  487. hr = wiasGetItemType(pWiasContext, &ItemType);
  488. if (FAILED(hr))
  489. {
  490. wiauDbgError("ReadItemProperties", "wiasGetItemType failed");
  491. return hr;
  492. }
  493. PDRVITEM_CONTEXT pItemCtx = NULL;
  494. hr = WiasContextToItemContext(pWiasContext, &pItemCtx);
  495. if (FAILED(hr))
  496. {
  497. wiauDbgError("ReadItemProperties", "WiasContextToItemContext failed");
  498. return hr;
  499. }
  500. //
  501. // For all items (except the root or stores), update the item time if requested. The time may
  502. // have been updated by an ObjectInfoChanged event.
  503. //
  504. if (IsItemTypeFolder(ItemType) || ItemType & WiaItemTypeFile)
  505. {
  506. if (wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_IPA_ITEM_TIME))
  507. {
  508. SYSTEMTIME SystemTime;
  509. hr = GetObjectTime(pItemCtx->pObjectInfo, &SystemTime);
  510. if (FAILED(hr))
  511. {
  512. wiauDbgError("ReadItemProperties", "GetObjectTime failed");
  513. return hr;
  514. }
  515. PROPVARIANT propVar;
  516. PROPSPEC propSpec;
  517. propVar.vt = VT_VECTOR | VT_UI2;
  518. propVar.caui.cElems = sizeof(SystemTime) / sizeof(WORD);
  519. propVar.caui.pElems = (WORD *) &SystemTime;
  520. propSpec.ulKind = PRSPEC_PROPID;
  521. propSpec.propid = WIA_IPA_ITEM_TIME;
  522. hr = wiasWriteMultiple(pWiasContext, 1, &propSpec, &propVar );
  523. if (FAILED(hr))
  524. {
  525. wiauDbgError("ReadItemProperties", "wiasWriteMultiple failed");
  526. return hr;
  527. }
  528. }
  529. }
  530. if(ItemType & WiaItemTypeImage && pItemCtx->pObjectInfo->m_ImagePixWidth == 0) {
  531. // image geometry is missing -- see if this is what we are asked
  532. PROPID propsToUpdate[] = {
  533. WIA_IPA_PIXELS_PER_LINE,
  534. WIA_IPA_NUMBER_OF_LINES
  535. };
  536. if(wiauPropsInPropSpec(NumPropSpecs, pPropSpecs, sizeof(propsToUpdate) / sizeof(PROPID), propsToUpdate))
  537. {
  538. // we can deal with any image as long as GDI+ understands it
  539. UINT NativeImageSize = pItemCtx->pObjectInfo->m_CompressedSize;
  540. UINT width, height, depth;
  541. wiauDbgWarning("ReadImageProperties", "Retrieving missing geometry! Expensive!");
  542. //
  543. // Allocate memory for the native image
  544. //
  545. BYTE *pNativeImage = new BYTE[NativeImageSize];
  546. if(pNativeImage == NULL) {
  547. return E_OUTOFMEMORY;
  548. }
  549. //
  550. // Get the data from the camera
  551. //
  552. hr = m_pPTPCamera->GetObjectData(pItemCtx->pObjectInfo->m_ObjectHandle,
  553. pNativeImage, &NativeImageSize, (LPVOID) 0);
  554. if(hr == S_FALSE) {
  555. wiauDbgWarning("ReadItemProperties", "GetObjectData() cancelled");
  556. delete [] pNativeImage;
  557. return S_FALSE;
  558. }
  559. if(FAILED(hr)) {
  560. wiauDbgError("ReadItemProperties", "GetObjectData() failed");
  561. delete [] pNativeImage;
  562. return S_FALSE;
  563. }
  564. //
  565. // get image geometry, discard native image
  566. //
  567. if(pItemCtx->pObjectInfo->m_FormatCode == PTP_FORMATCODE_IMAGE_EXIF ||
  568. pItemCtx->pObjectInfo->m_FormatCode == PTP_FORMATCODE_IMAGE_JFIF)
  569. {
  570. hr = GetJpegDimensions(pNativeImage, NativeImageSize, &width, &height, &depth);
  571. } else {
  572. hr = GetImageDimensions(pItemCtx->pObjectInfo->m_FormatCode, pNativeImage, NativeImageSize, &width, &height, &depth);
  573. }
  574. delete [] pNativeImage;
  575. if(FAILED(hr)) {
  576. wiauDbgError("ReadItemProperties", "failed to get image geometry from compressed image");
  577. return hr;
  578. }
  579. pItemCtx->pObjectInfo->m_ImagePixWidth = width;
  580. pItemCtx->pObjectInfo->m_ImagePixHeight = height;
  581. hr = wiasWritePropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, width);
  582. if(FAILED(hr)) {
  583. wiauDbgError("ReadItemProperties", "failed to write image width");
  584. return hr;
  585. }
  586. hr = wiasWritePropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, height);
  587. if(FAILED(hr)) {
  588. wiauDbgError("ReadItemProperties", "failed to set image height");
  589. return hr;
  590. }
  591. }
  592. }
  593. //
  594. // For images and video, update the thumbnail properties if requested
  595. //
  596. if (ItemType & (WiaItemTypeImage | WiaItemTypeVideo))
  597. {
  598. //
  599. // Get the thumbnail if requested to update any of the thumbnail properties and
  600. // the thumbnail is not already cached.
  601. //
  602. PROPID propsToUpdate[] = {
  603. WIA_IPC_THUMB_WIDTH,
  604. WIA_IPC_THUMB_HEIGHT,
  605. WIA_IPC_THUMBNAIL
  606. };
  607. if (wiauPropsInPropSpec(NumPropSpecs, pPropSpecs, sizeof(propsToUpdate) / sizeof(PROPID), propsToUpdate))
  608. {
  609. if (!pItemCtx->pThumb)
  610. {
  611. hr = CacheThumbnail(pItemCtx);
  612. if (FAILED(hr))
  613. {
  614. wiauDbgError("ReadItemProperties", "CacheThumbnail failed");
  615. return hr;
  616. }
  617. }
  618. //
  619. // Update the related thumbnail properties. Update the thumb width and height in case
  620. // the device didn't report them in the ObjectInfo structure (they are optional there).
  621. //
  622. PROPSPEC propSpecs[3];
  623. PROPVARIANT propVars[3];
  624. propSpecs[0].ulKind = PRSPEC_PROPID;
  625. propSpecs[0].propid = WIA_IPC_THUMB_WIDTH;
  626. propVars[0].vt = VT_I4;
  627. propVars[0].lVal = pItemCtx->pObjectInfo->m_ThumbPixWidth;
  628. propSpecs[1].ulKind = PRSPEC_PROPID;
  629. propSpecs[1].propid = WIA_IPC_THUMB_HEIGHT;
  630. propVars[1].vt = VT_I4;
  631. propVars[1].lVal = pItemCtx->pObjectInfo->m_ThumbPixHeight;
  632. propSpecs[2].ulKind = PRSPEC_PROPID;
  633. propSpecs[2].propid = WIA_IPC_THUMBNAIL;
  634. propVars[2].vt = VT_VECTOR | VT_UI1;
  635. propVars[2].caub.cElems = pItemCtx->ThumbSize;
  636. propVars[2].caub.pElems = pItemCtx->pThumb;
  637. hr = wiasWriteMultiple(pWiasContext, 3, propSpecs, propVars);
  638. if (FAILED(hr))
  639. {
  640. wiauDbgError("ReadItemProperties", "wiasWriteMultiple failed");
  641. delete pItemCtx->pThumb;
  642. pItemCtx->pThumb = NULL;
  643. }
  644. }
  645. }
  646. return hr;
  647. }
  648. //
  649. // This function caches the thumbnail into the given DRVITEM_CONTEXT
  650. //
  651. // Input:
  652. // pItemCtx -- the designated DRVITEM_CONTEXT
  653. //
  654. HRESULT
  655. CWiaMiniDriver::CacheThumbnail(PDRVITEM_CONTEXT pItemCtx)
  656. {
  657. DBG_FN("CWiaMiniDriver::CacheThumbnail");
  658. HRESULT hr = S_OK;
  659. if (pItemCtx->pThumb)
  660. {
  661. wiauDbgError("CacheThumbnail", "thumbnail is already cached");
  662. return E_FAIL;
  663. }
  664. CPtpObjectInfo *pObjectInfo = pItemCtx->pObjectInfo;
  665. if (!pObjectInfo) {
  666. wiauDbgError("CacheThumbnail", "Object info pointer is null");
  667. return E_FAIL;
  668. }
  669. if (pObjectInfo->m_ThumbCompressedSize <= 0)
  670. {
  671. wiauDbgWarning("CacheThumbnail", "No thumbnail available for this item");
  672. return hr;
  673. }
  674. //
  675. // We have to load the thumbnail in its native format
  676. //
  677. BYTE *pNativeThumb;
  678. pNativeThumb = new BYTE[pObjectInfo->m_ThumbCompressedSize];
  679. if (!pNativeThumb)
  680. {
  681. wiauDbgError("CacheThumbnail", "memory allocation failed");
  682. return E_OUTOFMEMORY;
  683. }
  684. UINT size = pObjectInfo->m_ThumbCompressedSize;
  685. hr = m_pPTPCamera->GetThumb(pObjectInfo->m_ObjectHandle, pNativeThumb, &size);
  686. if (FAILED(hr))
  687. {
  688. wiauDbgError("CacheThumbnail", "GetThumb failed");
  689. delete []pNativeThumb;
  690. return hr;
  691. }
  692. //
  693. // Figure out what base image format the thumbnail is in. Note that BMP thumbnails
  694. // are not allowed currently.
  695. //
  696. BOOL bTiff = FALSE;
  697. BOOL bJpeg = FALSE;
  698. if (PTP_FORMATCODE_IMAGE_TIFF == pObjectInfo->m_ThumbFormat ||
  699. PTP_FORMATCODE_IMAGE_TIFFEP == pObjectInfo->m_ThumbFormat ||
  700. PTP_FORMATCODE_IMAGE_TIFFIT == pObjectInfo->m_ThumbFormat)
  701. bTiff = TRUE;
  702. else if (PTP_FORMATCODE_IMAGE_EXIF == pObjectInfo->m_ThumbFormat ||
  703. PTP_FORMATCODE_IMAGE_JFIF == pObjectInfo->m_ThumbFormat)
  704. bJpeg = TRUE;
  705. else
  706. {
  707. wiauDbgWarning("CacheThumbnail", "unknown thumbnail format");
  708. delete []pNativeThumb;
  709. return hr;
  710. }
  711. //
  712. // If the thumbnail format is JPEG or TIFF, get the real thumbnail
  713. // width and height from the header information.
  714. //
  715. UINT BitDepth;
  716. UINT width, height;
  717. if (bTiff)
  718. {
  719. hr = GetTiffDimensions(pNativeThumb,
  720. pObjectInfo->m_ThumbCompressedSize,
  721. &width,
  722. &height,
  723. &BitDepth);
  724. }
  725. else if (bJpeg)
  726. {
  727. hr = GetJpegDimensions(pNativeThumb,
  728. pObjectInfo->m_ThumbCompressedSize,
  729. &width,
  730. &height,
  731. &BitDepth);
  732. }
  733. if (FAILED(hr))
  734. {
  735. wiauDbgError("CacheThumbnail", "get image dimensions failed");
  736. delete []pNativeThumb;
  737. return hr;
  738. }
  739. pObjectInfo->m_ThumbPixWidth = width;
  740. pObjectInfo->m_ThumbPixHeight = height;
  741. //
  742. // Calculate the size of the headerless BMP and allocate space for it
  743. //
  744. ULONG LineSize;
  745. LineSize = GetDIBLineSize(pObjectInfo->m_ThumbPixWidth, 24);
  746. pItemCtx->ThumbSize = LineSize * pObjectInfo->m_ThumbPixHeight;
  747. pItemCtx->pThumb = new BYTE [pItemCtx->ThumbSize];
  748. if (!pItemCtx->pThumb)
  749. {
  750. wiauDbgError("CacheThumbnail", "memory allocation failure");
  751. delete []pNativeThumb;
  752. return E_OUTOFMEMORY;
  753. }
  754. //
  755. // Convert the thumbnail format to headerless BMP
  756. //
  757. if (bTiff)
  758. {
  759. hr = Tiff2DIBBitmap(pNativeThumb,
  760. pObjectInfo->m_ThumbCompressedSize,
  761. pItemCtx->pThumb + LineSize * (height - 1),
  762. pItemCtx->ThumbSize,
  763. LineSize,
  764. 0
  765. );
  766. }
  767. else if (bJpeg)
  768. {
  769. hr = Jpeg2DIBBitmap(pNativeThumb,
  770. pObjectInfo->m_ThumbCompressedSize,
  771. pItemCtx->pThumb + LineSize * (height - 1),
  772. pItemCtx->ThumbSize,
  773. LineSize,
  774. 0
  775. );
  776. }
  777. if (FAILED(hr))
  778. {
  779. wiauDbgError("CacheThumbnail", "conversion to bitmap failed");
  780. delete []pNativeThumb;
  781. delete []pItemCtx->pThumb;
  782. pItemCtx->pThumb = NULL;
  783. return hr;
  784. }
  785. delete []pNativeThumb;
  786. return hr;
  787. }
  788. //
  789. // This function validates the given item properties.
  790. //
  791. // Input:
  792. // pWiasContext -- wia service context
  793. // NumPropSpecs -- number of properties to validate
  794. // pPropSpecs -- the properties
  795. //
  796. HRESULT
  797. CWiaMiniDriver::ValidateItemProperties(
  798. BYTE *pWiasContext,
  799. LONG NumPropSpecs,
  800. const PROPSPEC *pPropSpecs,
  801. LONG ItemType
  802. )
  803. {
  804. DBG_FN("CWiaMiniDriver::ValidateItemProperties");
  805. HRESULT hr = S_OK;
  806. //
  807. // Locals
  808. //
  809. FORMAT_INFO *pFormatInfo = NULL;
  810. DRVITEM_CONTEXT *pItemCtx;
  811. hr = WiasContextToItemContext(pWiasContext, &pItemCtx);
  812. if (FAILED(hr))
  813. {
  814. wiauDbgError("ValidateItemProperties", "WiasContextToItemContext failed");
  815. return hr;
  816. }
  817. //
  818. // If access rights are changed, send the new value to the camera
  819. //
  820. // WIAFIX-10/3/2000-davepar To be 100% correct, a change in the store protection should
  821. // update the access rights for all of the items on the store. This could be done in response
  822. // to a StoreInfoChanged event.
  823. //
  824. if (wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_IPA_ACCESS_RIGHTS))
  825. {
  826. LONG rights;
  827. hr = wiasReadPropLong(pWiasContext, WIA_IPA_ACCESS_RIGHTS, &rights, NULL, TRUE);
  828. if (FAILED(hr))
  829. {
  830. wiauDbgError("ValidateItemProperties", "wiasReadPropLong");
  831. return hr;
  832. }
  833. WORD objProt = (rights == WIA_ITEM_READ) ? PTP_PROTECTIONSTATUS_READONLY : PTP_PROTECTIONSTATUS_NONE;
  834. hr = m_pPTPCamera->SetObjectProtection(pItemCtx->pObjectInfo->m_ObjectHandle, objProt);
  835. if (FAILED(hr))
  836. {
  837. wiauDbgError("ValidateItemProperties", "SetObjectProtection failed");
  838. return hr;
  839. }
  840. }
  841. //
  842. // Update the valid formats by calling a WIA service function
  843. //
  844. BOOL bFormatChanged = FALSE;
  845. if (wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_IPA_TYMED))
  846. {
  847. WIA_PROPERTY_CONTEXT PropContext;
  848. hr = wiasCreatePropContext(NumPropSpecs, (PROPSPEC*) pPropSpecs, 0, NULL, &PropContext);
  849. if (FAILED(hr))
  850. {
  851. wiauDbgError("ValidateItemProperties", "wiasCreatePropContext failed");
  852. return hr;
  853. }
  854. hr = wiasUpdateValidFormat(pWiasContext, &PropContext, (IWiaMiniDrv*) this);
  855. if (FAILED(hr))
  856. {
  857. wiauDbgError("ValidateItemProperties", "wiasUpdateValidFormat failed");
  858. return hr;
  859. }
  860. hr = wiasFreePropContext(&PropContext);
  861. if (FAILED(hr)) {
  862. wiauDbgError("ValidateItemProperties", "wiasFreePropContext failed");
  863. return hr;
  864. }
  865. bFormatChanged = TRUE;
  866. }
  867. //
  868. // The only property change that needs to be validated is a change of format on an image
  869. // item. In that case, the item's size and bytes per line, and file extension need to be updated.
  870. //
  871. if (ItemType & WiaItemTypeImage &&
  872. (bFormatChanged || wiauPropInPropSpec(NumPropSpecs, pPropSpecs, WIA_IPA_FORMAT)))
  873. {
  874. if(pItemCtx->pObjectInfo->m_ImagePixWidth == 0) {
  875. // one of those cameras
  876. GUID fmt;
  877. hr = wiasReadPropGuid(pWiasContext, WIA_IPA_FORMAT, &fmt, NULL, false);
  878. if(FAILED(hr)) {
  879. wiauDbgError("ValidateItemProperies", "Failed to retrieve new format GUID");
  880. }
  881. if(fmt == WiaImgFmt_BMP || fmt == WiaImgFmt_MEMORYBMP) {
  882. // for uncompressed transfers --
  883. // tell service we don't know item size
  884. wiasWritePropLong(pWiasContext, WIA_IPA_ITEM_SIZE, 0);
  885. } else {
  886. // for any other transfers -- tell serivce that
  887. // compressed size is the item size
  888. wiasWritePropLong(pWiasContext, WIA_IPA_ITEM_SIZE, pItemCtx->pObjectInfo->m_CompressedSize);
  889. }
  890. } else {
  891. pFormatInfo = FormatCodeToFormatInfo(pItemCtx->pObjectInfo->m_FormatCode);
  892. hr = wiauSetImageItemSize(pWiasContext, pItemCtx->pObjectInfo->m_ImagePixWidth,
  893. pItemCtx->pObjectInfo->m_ImagePixHeight,
  894. pItemCtx->pObjectInfo->m_ImageBitDepth,
  895. pItemCtx->pObjectInfo->m_CompressedSize,
  896. pFormatInfo->ExtString);
  897. if (FAILED(hr))
  898. {
  899. wiauDbgError("ValidateItemProperties", "SetImageItemSize failed");
  900. return hr;
  901. }
  902. }
  903. }
  904. //
  905. // Call WIA service helper to check against valid values
  906. //
  907. hr = wiasValidateItemProperties(pWiasContext, NumPropSpecs, pPropSpecs);
  908. if (FAILED(hr))
  909. {
  910. wiauDbgWarning("ValidateDeviceProperties", "wiasValidateItemProperties failed");
  911. return hr;
  912. }
  913. return hr;
  914. }
  915. ULONG GetBitmapHeaderSize(PMINIDRV_TRANSFER_CONTEXT pmdtc)
  916. {
  917. UINT colormapsize = 0;
  918. UINT size = sizeof(BITMAPINFOHEADER);
  919. switch(pmdtc->lCompression) {
  920. case WIA_COMPRESSION_NONE: // BI_RGB
  921. case WIA_COMPRESSION_BI_RLE4:
  922. case WIA_COMPRESSION_BI_RLE8:
  923. switch(pmdtc->lDepth) {
  924. case 1:
  925. colormapsize = 2;
  926. break;
  927. case 4:
  928. colormapsize = 16;
  929. break;
  930. case 8:
  931. colormapsize = 256;
  932. break;
  933. case 15:
  934. case 16:
  935. case 32:
  936. colormapsize = 3;
  937. break;
  938. case 24:
  939. colormapsize = 0;
  940. break;
  941. }
  942. }
  943. size += colormapsize * sizeof(RGBQUAD);
  944. if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_BMP)) {
  945. size += sizeof(BITMAPFILEHEADER);
  946. }
  947. return size;
  948. }
  949. VOID
  950. VerticalFlip(
  951. PBYTE pImageTop,
  952. LONG iWidthInBytes,
  953. LONG iHeight)
  954. {
  955. //
  956. // try to allocat a temp scan line buffer
  957. //
  958. PBYTE pBuffer = (PBYTE)LocalAlloc(LPTR,iWidthInBytes);
  959. if (pBuffer != NULL) {
  960. LONG index;
  961. PBYTE pImageBottom;
  962. pImageBottom = pImageTop + (iHeight-1) * iWidthInBytes;
  963. for (index = 0;index < (iHeight/2);index++) {
  964. memcpy(pBuffer,pImageTop,iWidthInBytes);
  965. memcpy(pImageTop,pImageBottom,iWidthInBytes);
  966. memcpy(pImageBottom,pBuffer,iWidthInBytes);
  967. pImageTop += iWidthInBytes;
  968. pImageBottom -= iWidthInBytes;
  969. }
  970. LocalFree(pBuffer);
  971. }
  972. }
  973. HRESULT
  974. CWiaMiniDriver::AcquireAndTranslateAnyImage(
  975. BYTE *pWiasContext,
  976. DRVITEM_CONTEXT *pItemCtx,
  977. PMINIDRV_TRANSFER_CONTEXT pmdtc)
  978. {
  979. #define REQUIRE(x, y) if(!(x)) { wiauDbgError("AcquireAndTranslateAnyImage", y); goto Cleanup; }
  980. DBG_FN("CWiaMiniDriver::AcquireAndTranslateAnyImage");
  981. HRESULT hr = S_OK;
  982. BYTE *pNativeImage = NULL;
  983. BYTE *pRawImageBuffer = NULL;
  984. BOOL bPatchedMDTC = FALSE;
  985. UINT NativeImageSize = pItemCtx->pObjectInfo->m_CompressedSize;
  986. UINT width, height, depth, imagesize, headersize;
  987. BOOL bFileTransfer = (pmdtc->tymed & TYMED_FILE);
  988. LONG lMsg = (bFileTransfer ? IT_MSG_STATUS : IT_MSG_DATA);
  989. LONG percentComplete;
  990. // we can deal with any image as long as GDIPlus can handle it
  991. //
  992. // Allocate memory for the native image
  993. //
  994. pNativeImage = new BYTE[NativeImageSize];
  995. hr = E_OUTOFMEMORY;
  996. REQUIRE(pNativeImage, "memory allocation failed");
  997. //
  998. // Get the data from the camera
  999. //
  1000. hr = m_pPTPCamera->GetObjectData(pItemCtx->pObjectInfo->m_ObjectHandle,
  1001. pNativeImage, &NativeImageSize, (LPVOID) pmdtc);
  1002. REQUIRE(hr != S_FALSE, "transfer cancelled");
  1003. REQUIRE(SUCCEEDED(hr), "GetObjectData failed");
  1004. //
  1005. // decompress image, retrieve its geometry
  1006. //
  1007. hr = ConvertAnyImageToBmp(pNativeImage, NativeImageSize, &width, &height, &depth, &pRawImageBuffer, &imagesize, &headersize);
  1008. REQUIRE(hr == S_OK, "failed to convert image to bitmap format");
  1009. pmdtc->lWidthInPixels = pItemCtx->pObjectInfo->m_ImagePixWidth = width;
  1010. pmdtc->cbWidthInBytes = (width * depth) / 8L;
  1011. pmdtc->lLines = pItemCtx->pObjectInfo->m_ImagePixHeight = height;
  1012. pmdtc->lDepth = pItemCtx->pObjectInfo->m_ImageBitDepth = depth;
  1013. pmdtc->lImageSize = imagesize = ((width * depth) / 8L) * height;
  1014. if(IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) {
  1015. pmdtc->lHeaderSize = headersize - sizeof(BITMAPFILEHEADER);
  1016. } else {
  1017. pmdtc->lHeaderSize = headersize;
  1018. }
  1019. pmdtc->lItemSize = pmdtc->lImageSize + pmdtc->lHeaderSize;
  1020. hr = wiasWritePropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, width);
  1021. REQUIRE(hr == S_OK, "failed to set image width");
  1022. hr = wiasWritePropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, height);
  1023. REQUIRE(hr == S_OK, "failed to set image height");
  1024. hr = wiasWritePropLong(pWiasContext, WIA_IPA_ITEM_SIZE, 0);
  1025. REQUIRE(hr == S_OK, "failed to set item size");
  1026. // setup buffer for uncompressed image
  1027. if(pmdtc->pTransferBuffer == NULL) {
  1028. if(IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) {
  1029. pmdtc->pTransferBuffer = pRawImageBuffer + sizeof(BITMAPFILEHEADER);
  1030. } else {
  1031. pmdtc->pTransferBuffer = pRawImageBuffer;
  1032. }
  1033. pmdtc->lBufferSize = pmdtc->lItemSize;
  1034. bPatchedMDTC = TRUE;
  1035. } else {
  1036. if(IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) {
  1037. memcpy(pmdtc->pTransferBuffer, pRawImageBuffer + sizeof(BITMAPFILEHEADER),
  1038. pmdtc->lHeaderSize);
  1039. } else {
  1040. memcpy(pmdtc->pTransferBuffer, pRawImageBuffer, pmdtc->lHeaderSize);
  1041. }
  1042. }
  1043. //
  1044. // Send the header to the app
  1045. //
  1046. percentComplete = 90 + (10 * pmdtc->lHeaderSize) / pmdtc->lItemSize;
  1047. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT,
  1048. percentComplete, 0, pmdtc->lHeaderSize, pmdtc, 0);
  1049. REQUIRE(hr != S_FALSE, "transfer cancelled");
  1050. REQUIRE(SUCCEEDED(hr), "sending header to app failed");
  1051. if(bFileTransfer) {
  1052. // write the whole image to file
  1053. ULONG ulWritten;
  1054. BOOL bRet;
  1055. //
  1056. // NOTE: The mini driver transfer context should have the
  1057. // file handle as a pointer, not a fixed 32-bit long. This
  1058. // may not work on 64bit.
  1059. //
  1060. bRet = WriteFile((HANDLE)pmdtc->hFile,
  1061. pRawImageBuffer,
  1062. pmdtc->lItemSize,
  1063. &ulWritten,
  1064. NULL);
  1065. if (!bRet) {
  1066. hr = HRESULT_FROM_WIN32(::GetLastError());
  1067. wiauDbgError("AcquireAndTranslateAnyImage", "WriteFile failed (0x%X)", hr);
  1068. }
  1069. } else {
  1070. LONG BytesToWrite, BytesLeft = pmdtc->lImageSize;
  1071. BYTE *pCurrent = pRawImageBuffer + headersize;
  1072. UINT offset = pmdtc->lHeaderSize;
  1073. while(BytesLeft) {
  1074. BytesToWrite = min(pmdtc->lBufferSize, BytesLeft);
  1075. memcpy(pmdtc->pTransferBuffer, pCurrent, BytesToWrite);
  1076. //
  1077. // Calculate the percentage done using 90 as a base. This makes a rough assumption that
  1078. // transferring the data from the device takes 90% of the time. If the this is the last
  1079. // transfer, set the percentage to 100, otherwise make sure it is never larger than 99.
  1080. //
  1081. if (BytesLeft == BytesToWrite)
  1082. percentComplete = 100;
  1083. else
  1084. percentComplete = min(99, 90 + (10 * offset) / pmdtc->lItemSize);
  1085. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT,
  1086. percentComplete, offset, BytesToWrite, pmdtc, 0);
  1087. REQUIRE(hr != S_FALSE, "transfer cancelled");
  1088. REQUIRE(SUCCEEDED(hr), "sending header to app failed");
  1089. pCurrent += BytesToWrite;
  1090. offset += BytesToWrite;
  1091. BytesLeft -= BytesToWrite;
  1092. }
  1093. }
  1094. Cleanup:
  1095. delete [] pNativeImage;
  1096. delete [] pRawImageBuffer;
  1097. // restore mdtc
  1098. pmdtc->lItemSize = 0;
  1099. if(bPatchedMDTC) {
  1100. pmdtc->pTransferBuffer = 0;
  1101. pmdtc->lBufferSize = 0;
  1102. }
  1103. return hr;
  1104. #undef REQUIRE
  1105. }
  1106. HRESULT
  1107. CWiaMiniDriver::AcquireAndTranslateJpegWithoutGeometry(
  1108. BYTE *pWiasContext,
  1109. DRVITEM_CONTEXT *pItemCtx,
  1110. PMINIDRV_TRANSFER_CONTEXT pmdtc)
  1111. {
  1112. #define REQUIRE(x, y) if(!(x)) { wiauDbgError("AcquireAndTranslateWithoutGeometry", y); goto Cleanup; }
  1113. DBG_FN("CWiaMiniDriver::AcquireAndTranslateWithoutGeometry");
  1114. HRESULT hr = E_FAIL;
  1115. BYTE *pNativeImage = NULL;
  1116. BYTE *pRawImageBuffer = NULL;
  1117. BOOL bPatchedMDTC = FALSE;
  1118. UINT NativeImageSize = pItemCtx->pObjectInfo->m_CompressedSize;
  1119. UINT width, height, depth, imagesize, headersize;
  1120. BOOL bFileTransfer = (pmdtc->tymed & TYMED_FILE);
  1121. LONG lMsg = (bFileTransfer ? IT_MSG_STATUS : IT_MSG_DATA);
  1122. LONG percentComplete;
  1123. // we can only deal with JPEG images
  1124. if(pItemCtx->pObjectInfo->m_FormatCode != PTP_FORMATCODE_IMAGE_JFIF &&
  1125. pItemCtx->pObjectInfo->m_FormatCode != PTP_FORMATCODE_IMAGE_EXIF)
  1126. {
  1127. hr = E_INVALIDARG;
  1128. REQUIRE(0, "don't know how to get image geometry from non-JPEG image");
  1129. }
  1130. //
  1131. // Allocate memory for the native image
  1132. //
  1133. pNativeImage = new BYTE[NativeImageSize];
  1134. hr = E_OUTOFMEMORY;
  1135. REQUIRE(pNativeImage, "memory allocation failed");
  1136. //
  1137. // Get the data from the camera
  1138. //
  1139. hr = m_pPTPCamera->GetObjectData(pItemCtx->pObjectInfo->m_ObjectHandle,
  1140. pNativeImage, &NativeImageSize, (LPVOID) pmdtc);
  1141. REQUIRE(hr != S_FALSE, "transfer cancelled");
  1142. REQUIRE(SUCCEEDED(hr), "GetObjectData failed");
  1143. //
  1144. // get image geometry
  1145. //
  1146. hr = GetJpegDimensions(pNativeImage, NativeImageSize, &width, &height, &depth);
  1147. REQUIRE(hr == S_OK, "failed to get image geometry from JPEG file");
  1148. pmdtc->lWidthInPixels = pItemCtx->pObjectInfo->m_ImagePixWidth = width;
  1149. pmdtc->lLines = pItemCtx->pObjectInfo->m_ImagePixHeight = height;
  1150. pmdtc->lDepth = pItemCtx->pObjectInfo->m_ImageBitDepth = depth;
  1151. pmdtc->lImageSize = imagesize = ((((width + 31) * depth) / 8L) & 0xFFFFFFFC) * height;
  1152. pmdtc->lHeaderSize = headersize = GetBitmapHeaderSize(pmdtc);
  1153. pmdtc->lItemSize = imagesize + headersize;
  1154. hr = wiasWritePropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, width);
  1155. REQUIRE(hr == S_OK, "failed to set image width");
  1156. hr = wiasWritePropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, height);
  1157. REQUIRE(hr == S_OK, "failed to set image height");
  1158. hr = wiasWritePropLong(pWiasContext, WIA_IPA_ITEM_SIZE, 0);
  1159. REQUIRE(hr == S_OK, "failed to set item size");
  1160. // setup buffer for uncompressed image
  1161. pRawImageBuffer = new BYTE[pmdtc->lImageSize + pmdtc->lHeaderSize];
  1162. REQUIRE(pRawImageBuffer, "failed to allocate intermdiate buffer");
  1163. if(pmdtc->pTransferBuffer == NULL) {
  1164. pmdtc->pTransferBuffer = pRawImageBuffer;
  1165. pmdtc->lBufferSize = pmdtc->lItemSize;
  1166. bPatchedMDTC = TRUE;
  1167. }
  1168. hr = wiasGetImageInformation(pWiasContext, 0, pmdtc);
  1169. REQUIRE(SUCCEEDED(hr), "wiasGetImageInformation failed");
  1170. percentComplete = 90 + (10 * pmdtc->lHeaderSize) / pmdtc->lItemSize;
  1171. //
  1172. // Send the header to the app
  1173. //
  1174. if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) {
  1175. UNALIGNED BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)pmdtc->pTransferBuffer;
  1176. pbmih->biHeight = -pmdtc->lLines;
  1177. }
  1178. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT,
  1179. percentComplete, 0, pmdtc->lHeaderSize, pmdtc, 0);
  1180. REQUIRE(hr != S_FALSE, "transfer cancelled");
  1181. REQUIRE(SUCCEEDED(hr), "sending header to app failed");
  1182. //
  1183. // Convert the image to BMP
  1184. //
  1185. hr = Jpeg2DIBBitmap(pNativeImage, NativeImageSize,
  1186. pRawImageBuffer + pmdtc->lHeaderSize + pmdtc->cbWidthInBytes * (pmdtc->lLines - 1),
  1187. pmdtc->lImageSize, pmdtc->cbWidthInBytes, 1);
  1188. REQUIRE(SUCCEEDED(hr), "image format conversion failed");
  1189. if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) {
  1190. VerticalFlip(pRawImageBuffer + pmdtc->lHeaderSize, pmdtc->cbWidthInBytes, pmdtc->lLines);
  1191. }
  1192. if(bFileTransfer) {
  1193. // write the whole image to file
  1194. #ifdef UNICODE
  1195. hr = wiasWriteBufToFile(0, pmdtc);
  1196. #else
  1197. if (pmdtc->lItemSize <= pmdtc->lBufferSize) {
  1198. ULONG ulWritten;
  1199. BOOL bRet;
  1200. //
  1201. // NOTE: The mini driver transfer context should have the
  1202. // file handle as a pointer, not a fixed 32-bit long. This
  1203. // may not work on 64bit.
  1204. //
  1205. bRet = WriteFile((HANDLE)pmdtc->hFile,
  1206. pmdtc->pTransferBuffer,
  1207. pmdtc->lItemSize,
  1208. &ulWritten,
  1209. NULL);
  1210. if (!bRet) {
  1211. hr = HRESULT_FROM_WIN32(::GetLastError());
  1212. wiauDbgError("AcquireDataAndTranslate", "WriteFile failed (0x%X)", hr);
  1213. }
  1214. }
  1215. else {
  1216. wiauDbgError("AcquireDataAndTranslate", "lItemSize is larger than buffer");
  1217. hr = E_FAIL;
  1218. }
  1219. #endif
  1220. REQUIRE(SUCCEEDED(hr), "writing image body to file");
  1221. } else {
  1222. LONG BytesToWrite, BytesLeft = pmdtc->lImageSize;
  1223. BYTE *pCurrent = pRawImageBuffer + pmdtc->lHeaderSize;
  1224. UINT offset = pmdtc->lHeaderSize;
  1225. while(BytesLeft) {
  1226. BytesToWrite = min(pmdtc->lBufferSize, BytesLeft);
  1227. memcpy(pmdtc->pTransferBuffer, pCurrent, BytesToWrite);
  1228. //
  1229. // Calculate the percentage done using 90 as a base. This makes a rough assumption that
  1230. // transferring the data from the device takes 90% of the time. If the this is the last
  1231. // transfer, set the percentage to 100, otherwise make sure it is never larger than 99.
  1232. //
  1233. if (BytesLeft == BytesToWrite)
  1234. percentComplete = 100;
  1235. else
  1236. percentComplete = min(99, 90 + (10 * offset) / pmdtc->lItemSize);
  1237. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT,
  1238. percentComplete, offset, BytesToWrite, pmdtc, 0);
  1239. REQUIRE(hr != S_FALSE, "transfer cancelled");
  1240. REQUIRE(SUCCEEDED(hr), "sending header to app failed");
  1241. pCurrent += BytesToWrite;
  1242. offset += BytesToWrite;
  1243. BytesLeft -= BytesToWrite;
  1244. }
  1245. }
  1246. Cleanup:
  1247. delete [] pNativeImage;
  1248. delete [] pRawImageBuffer;
  1249. // restore mdtc
  1250. pmdtc->lItemSize = 0;
  1251. if(bPatchedMDTC) {
  1252. pmdtc->pTransferBuffer = 0;
  1253. pmdtc->lBufferSize = 0;
  1254. }
  1255. return hr;
  1256. }
  1257. //
  1258. // This function transfers image from the camera and translates it to BMP
  1259. // format.
  1260. //
  1261. // Input:
  1262. // pWiasContext -- wias context
  1263. // pItemCtx -- the mini driver item context
  1264. // pmdtc -- the transfer context
  1265. //
  1266. HRESULT
  1267. CWiaMiniDriver::AcquireDataAndTranslate(
  1268. BYTE *pWiasContext,
  1269. DRVITEM_CONTEXT *pItemCtx,
  1270. PMINIDRV_TRANSFER_CONTEXT pmdtc
  1271. )
  1272. {
  1273. DBG_FN("CWiaMiniDriver::AcquireDataAndTranslate");
  1274. HRESULT hr = S_OK;
  1275. // non-jpeg images are handled by GDI+ process
  1276. if(pItemCtx->pObjectInfo->m_FormatCode != PTP_FORMATCODE_IMAGE_JFIF &&
  1277. pItemCtx->pObjectInfo->m_FormatCode != PTP_FORMATCODE_IMAGE_EXIF)
  1278. {
  1279. return AcquireAndTranslateAnyImage(pWiasContext, pItemCtx, pmdtc);
  1280. }
  1281. if(pItemCtx->pObjectInfo->m_ImagePixWidth == 0) {
  1282. return AcquireAndTranslateJpegWithoutGeometry(pWiasContext, pItemCtx, pmdtc);
  1283. }
  1284. //
  1285. // Allocate memory for the native image
  1286. //
  1287. UINT NativeImageSize = pItemCtx->pObjectInfo->m_CompressedSize;
  1288. BYTE *pNativeImage = new BYTE[NativeImageSize];
  1289. if (!pNativeImage)
  1290. {
  1291. wiauDbgError("AcquireDataAndTranslate", "memory allocation failed");
  1292. return E_OUTOFMEMORY;
  1293. }
  1294. //
  1295. // Get the data from the camera
  1296. //
  1297. hr = m_pPTPCamera->GetObjectData(pItemCtx->pObjectInfo->m_ObjectHandle,
  1298. pNativeImage, &NativeImageSize, (LPVOID) pmdtc);
  1299. if (FAILED(hr))
  1300. {
  1301. wiauDbgError("AcquireDataAndTranslate", "GetObjectData failed");
  1302. delete []pNativeImage;
  1303. return hr;
  1304. }
  1305. if (hr == S_FALSE)
  1306. {
  1307. wiauDbgWarning("AcquireDataAndTranslate", "transfer cancelled");
  1308. delete []pNativeImage;
  1309. return hr;
  1310. }
  1311. //
  1312. // Call the WIA service helper to fill in the BMP header
  1313. //
  1314. hr = wiasGetImageInformation(pWiasContext, 0, pmdtc);
  1315. if (FAILED(hr))
  1316. {
  1317. wiauDbgErrorHr(hr, "AcquireDataAndTranslate", "wiasGetImageInformation failed");
  1318. return hr;
  1319. }
  1320. if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) {
  1321. UNALIGNED BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)pmdtc->pTransferBuffer;
  1322. pbmih->biHeight = -pmdtc->lLines;
  1323. }
  1324. //
  1325. // Send the header to the app
  1326. //
  1327. BOOL bFileTransfer = (pmdtc->tymed & TYMED_FILE);
  1328. LONG lMsg = (bFileTransfer ? IT_MSG_STATUS : IT_MSG_DATA);
  1329. LONG percentComplete = 90 + (10 * pmdtc->lHeaderSize) / pmdtc->lItemSize;
  1330. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT,
  1331. percentComplete, 0, pmdtc->lHeaderSize, pmdtc, 0);
  1332. if (FAILED(hr))
  1333. {
  1334. wiauDbgError("AcquireDataAndTranslate", "sending header to app failed");
  1335. return hr;
  1336. }
  1337. if (hr == S_FALSE)
  1338. {
  1339. wiauDbgWarning("AcquireDataAndTranslate", "transfer cancelled");
  1340. delete []pNativeImage;
  1341. return S_FALSE;
  1342. }
  1343. //
  1344. // Set up the buffer for the rest of the transfer
  1345. //
  1346. BYTE *pTranslateBuffer = pmdtc->pTransferBuffer;
  1347. LONG BytesLeft = pmdtc->lBufferSize;
  1348. if (bFileTransfer)
  1349. {
  1350. pTranslateBuffer += pmdtc->lHeaderSize;
  1351. BytesLeft -= pmdtc->lHeaderSize;
  1352. }
  1353. //
  1354. // If the buffer is too small, allocate a new, bigger one
  1355. //
  1356. BOOL bIntermediateBuffer = FALSE;
  1357. if (BytesLeft < pmdtc->lImageSize)
  1358. {
  1359. pTranslateBuffer = new BYTE[pmdtc->lImageSize];
  1360. BytesLeft = pmdtc->lImageSize;
  1361. bIntermediateBuffer = TRUE;
  1362. }
  1363. //
  1364. // Convert the image to BMP
  1365. //
  1366. hr = Jpeg2DIBBitmap(pNativeImage, NativeImageSize,
  1367. pTranslateBuffer + pmdtc->cbWidthInBytes * (pmdtc->lLines - 1),
  1368. BytesLeft, pmdtc->cbWidthInBytes, 1);
  1369. //
  1370. // Free the native image buffer
  1371. //
  1372. delete []pNativeImage;
  1373. pNativeImage = NULL;
  1374. if (FAILED(hr))
  1375. {
  1376. wiauDbgError("AcquireDataAndTranslate", "image format conversion failed");
  1377. if (bIntermediateBuffer)
  1378. delete []pTranslateBuffer;
  1379. return hr;
  1380. }
  1381. if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP)) {
  1382. VerticalFlip(pTranslateBuffer, pmdtc->cbWidthInBytes, pmdtc->lLines);
  1383. }
  1384. LONG lOffset = pmdtc->lHeaderSize;
  1385. if (bIntermediateBuffer)
  1386. {
  1387. //
  1388. // Send the data back a chunk at a time. This assumes that it is a callback transfer, e.g. the
  1389. // buffer pointer is not being incremented.
  1390. //
  1391. LONG BytesToCopy = 0;
  1392. BYTE *pCurrent = pTranslateBuffer;
  1393. BytesLeft = pmdtc->lImageSize;
  1394. while (BytesLeft > 0)
  1395. {
  1396. BytesToCopy = min(BytesLeft, pmdtc->lBufferSize);
  1397. memcpy(pmdtc->pTransferBuffer, pCurrent, BytesToCopy);
  1398. //
  1399. // Calculate the percentage done using 90 as a base. This makes a rough assumption that
  1400. // transferring the data from the device takes 90% of the time. If the this is the last
  1401. // transfer, set the percentage to 100, otherwise make sure it is never larger than 99.
  1402. //
  1403. if (BytesLeft == BytesToCopy)
  1404. percentComplete = 100;
  1405. else
  1406. percentComplete = min(99, 90 + (10 * lOffset) / pmdtc->lItemSize);
  1407. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT,
  1408. percentComplete, lOffset, BytesToCopy, pmdtc, 0);
  1409. if (FAILED(hr))
  1410. {
  1411. wiauDbgError("AcquireDataAndTranslate", "sending header to app failed");
  1412. if (bIntermediateBuffer)
  1413. delete []pTranslateBuffer;
  1414. return hr;
  1415. }
  1416. if (hr == S_FALSE)
  1417. {
  1418. wiauDbgWarning("AcquireDataAndTranslate", "transfer cancelled");
  1419. if (bIntermediateBuffer)
  1420. delete []pTranslateBuffer;
  1421. return S_FALSE;
  1422. }
  1423. pCurrent += BytesToCopy;
  1424. lOffset += BytesToCopy;
  1425. BytesLeft -= BytesToCopy;
  1426. }
  1427. }
  1428. else
  1429. {
  1430. //
  1431. // Send the data to the app in one big chunk
  1432. //
  1433. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(lMsg, IT_STATUS_TRANSFER_TO_CLIENT,
  1434. 100, lOffset, pmdtc->lImageSize, pmdtc, 0);
  1435. if (FAILED(hr))
  1436. {
  1437. wiauDbgError("AcquireDataAndTranslate", "sending header to app failed");
  1438. if (bIntermediateBuffer)
  1439. delete []pTranslateBuffer;
  1440. return hr;
  1441. }
  1442. }
  1443. //
  1444. // Free the translate buffer
  1445. //
  1446. if (bIntermediateBuffer)
  1447. delete []pTranslateBuffer;
  1448. return hr;
  1449. }
  1450. //
  1451. // This function transfers native data to the application without translating it.
  1452. //
  1453. // Input:
  1454. // pItemCtx -- driver item context
  1455. // pmdtc -- transfer context
  1456. //
  1457. HRESULT
  1458. CWiaMiniDriver::AcquireData(
  1459. DRVITEM_CONTEXT *pItemCtx,
  1460. PMINIDRV_TRANSFER_CONTEXT pmdtc
  1461. )
  1462. {
  1463. DBG_FN("CWiaMiniDriver::AcquireData");
  1464. HRESULT hr = S_OK;
  1465. //
  1466. // If the class driver does not allocate the transfer buffer,
  1467. // we have to allocate a temporary one
  1468. //
  1469. if (!pmdtc->bClassDrvAllocBuf)
  1470. {
  1471. pmdtc->pTransferBuffer = new BYTE[pItemCtx->pObjectInfo->m_CompressedSize];
  1472. if (!pmdtc->pTransferBuffer)
  1473. {
  1474. wiauDbgError("AcquireData", "memory allocation failed");
  1475. return E_OUTOFMEMORY;
  1476. }
  1477. pmdtc->pBaseBuffer = pmdtc->pTransferBuffer;
  1478. pmdtc->lBufferSize = pItemCtx->pObjectInfo->m_CompressedSize;
  1479. }
  1480. //
  1481. // Get the data from the camera
  1482. //
  1483. UINT size = pmdtc->lBufferSize;
  1484. hr = m_pPTPCamera->GetObjectData(pItemCtx->pObjectInfo->m_ObjectHandle, pmdtc->pTransferBuffer,
  1485. &size, (LPVOID) pmdtc);
  1486. //
  1487. // Check the return code, but keep going so that the buffer gets freed
  1488. //
  1489. if (FAILED(hr))
  1490. wiauDbgError("AcquireData", "GetObjectData failed");
  1491. else if (hr == S_FALSE)
  1492. wiauDbgWarning("AcquireData", "data transfer cancelled");
  1493. //
  1494. // Free the temporary buffer, if needed
  1495. //
  1496. if (!pmdtc->bClassDrvAllocBuf)
  1497. {
  1498. if (pmdtc->pTransferBuffer)
  1499. {
  1500. delete []pmdtc->pTransferBuffer;
  1501. pmdtc->pBaseBuffer = NULL;
  1502. pmdtc->pTransferBuffer = NULL;
  1503. pmdtc->lBufferSize = 0;
  1504. }
  1505. else
  1506. {
  1507. wiauDbgWarning("AcquireData", "transfer buffer is NULL");
  1508. }
  1509. }
  1510. return hr;
  1511. }
  1512. //
  1513. // This function passes the data transfer callback through to the
  1514. // IWiaMiniDrvCallBack interface using the appropriate
  1515. // parameters.
  1516. //
  1517. // Input:
  1518. // pCallbackParam -- should hold a pointer to the transfer context
  1519. // lPercentComplete -- percent of transfer completed
  1520. // lOffset -- offset into the buffer where the data is located
  1521. // lLength -- amount of data transferred
  1522. //
  1523. HRESULT
  1524. DataCallback(
  1525. LPVOID pCallbackParam,
  1526. LONG lPercentComplete,
  1527. LONG lOffset,
  1528. LONG lLength,
  1529. BYTE **ppBuffer,
  1530. LONG *plBufferSize
  1531. )
  1532. {
  1533. DBG_FN("DataCallback");
  1534. HRESULT hr = S_OK;
  1535. if (!pCallbackParam || !ppBuffer || !*ppBuffer || !plBufferSize)
  1536. {
  1537. wiauDbgError("DataCallback", "invalid argument");
  1538. return E_INVALIDARG;
  1539. }
  1540. PMINIDRV_TRANSFER_CONTEXT pmdtc = (PMINIDRV_TRANSFER_CONTEXT) pCallbackParam;
  1541. //
  1542. // If app is asking for BMP, most likely it's being converted. Thus just give the app
  1543. // status messages. Calculate percent done so that the transfer takes 90% of the time
  1544. // and the conversion takes the last 10%.
  1545. //
  1546. if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_BMP) ||
  1547. IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP))
  1548. {
  1549. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_STATUS, IT_STATUS_TRANSFER_FROM_DEVICE,
  1550. lPercentComplete * 9 / 10, lOffset, lLength, pmdtc, 0);
  1551. *ppBuffer += lLength;
  1552. }
  1553. //
  1554. // Otherwise, see if it's a file transfer
  1555. //
  1556. else if (pmdtc->tymed & TYMED_FILE)
  1557. {
  1558. if (pmdtc->bClassDrvAllocBuf && lPercentComplete == 100)
  1559. {
  1560. //
  1561. // Call WIA to write the data to the file. There is a small a bug that causes
  1562. // TIFF headers to be changed, so temporarily change the format GUID to null.
  1563. //
  1564. GUID tempFormat;
  1565. tempFormat = pmdtc->guidFormatID;
  1566. pmdtc->guidFormatID = GUID_NULL;
  1567. hr = wiasWritePageBufToFile(pmdtc);
  1568. pmdtc->guidFormatID = tempFormat;
  1569. if (FAILED(hr))
  1570. {
  1571. wiauDbgError("DataCallback", "wiasWritePageBufToFile failed");
  1572. return hr;
  1573. }
  1574. }
  1575. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_STATUS, IT_STATUS_TRANSFER_TO_CLIENT,
  1576. lPercentComplete, lOffset, lLength, pmdtc, 0);
  1577. *ppBuffer += lLength;
  1578. }
  1579. //
  1580. // Otherwise, it's a callback transfer
  1581. //
  1582. else
  1583. {
  1584. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_DATA, IT_STATUS_TRANSFER_TO_CLIENT,
  1585. lPercentComplete, lOffset, lLength, pmdtc, 0);
  1586. //
  1587. // Update the buffer pointer and size in case the app is using double buffering
  1588. //
  1589. *ppBuffer = pmdtc->pTransferBuffer;
  1590. *plBufferSize = pmdtc->lBufferSize;
  1591. }
  1592. if (FAILED(hr))
  1593. {
  1594. wiauDbgError("DataCallback", "MiniDrvCallback failed");
  1595. }
  1596. else if (hr == S_FALSE)
  1597. {
  1598. wiauDbgWarning("DataCallback", "data transfer was cancelled by MiniDrvCallback");
  1599. }
  1600. return hr;
  1601. }