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.

1712 lines
46 KiB

  1. /**************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 2000
  4. *
  5. * TITLE: fakecam.cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * DATE: 18 July, 2000
  10. *
  11. * DESCRIPTION:
  12. * Fake Camera device implementation
  13. *
  14. * TODO: Every function in this file must be changed so that it actually
  15. * talks to a real camera.
  16. *
  17. ***************************************************************************/
  18. #include "pch.h"
  19. //
  20. // Globals
  21. //
  22. HINSTANCE g_hInst;
  23. GUID g_guidUnknownFormat;
  24. //
  25. // Initializes access to the camera and allocates the device info
  26. // structure and private storage area
  27. //
  28. HRESULT WiaMCamInit(MCAM_DEVICE_INFO **ppDeviceInfo)
  29. {
  30. wiauDbgInit(g_hInst);
  31. DBG_FN("WiaMCamInit");
  32. HRESULT hr = S_OK;
  33. //
  34. // Locals
  35. //
  36. MCAM_DEVICE_INFO *pDeviceInfo = NULL;
  37. FAKECAM_DEVICE_INFO *pPrivateDeviceInfo = NULL;
  38. REQUIRE_ARGS(!ppDeviceInfo, hr, "WiaMCamInit");
  39. *ppDeviceInfo = NULL;
  40. //
  41. // Allocate the MCAM_DEVICE_INFO structure
  42. //
  43. pDeviceInfo = new MCAM_DEVICE_INFO;
  44. REQUIRE_ALLOC(pDeviceInfo, hr, "WiaMCamInit");
  45. memset(pDeviceInfo, 0, sizeof(MCAM_DEVICE_INFO));
  46. pDeviceInfo->iSize = sizeof(MCAM_DEVICE_INFO);
  47. pDeviceInfo->iMcamVersion = MCAM_VERSION;
  48. //
  49. // Allocate the FAKECAM_DEVICE_INFO structure that the
  50. // microdriver uses to store info
  51. //
  52. pPrivateDeviceInfo = new FAKECAM_DEVICE_INFO;
  53. REQUIRE_ALLOC(pPrivateDeviceInfo, hr, "WiaMCamInit");
  54. memset(pPrivateDeviceInfo, 0, sizeof(FAKECAM_DEVICE_INFO));
  55. pDeviceInfo->pPrivateStorage = (BYTE *) pPrivateDeviceInfo;
  56. Cleanup:
  57. if (FAILED(hr)) {
  58. if (pDeviceInfo) {
  59. delete pDeviceInfo;
  60. pDeviceInfo = NULL;
  61. }
  62. if (pPrivateDeviceInfo) {
  63. delete pPrivateDeviceInfo;
  64. pPrivateDeviceInfo = NULL;
  65. }
  66. }
  67. *ppDeviceInfo = pDeviceInfo;
  68. return hr;
  69. }
  70. //
  71. // Frees any remaining structures held by the microdriver
  72. //
  73. HRESULT WiaMCamUnInit(MCAM_DEVICE_INFO *pDeviceInfo)
  74. {
  75. DBG_FN("WiaMCamUnInit");
  76. HRESULT hr = S_OK;
  77. if (pDeviceInfo)
  78. {
  79. //
  80. // Free anything that was dynamically allocated in the MCAM_DEVICE_INFO
  81. // structure
  82. //
  83. if (pDeviceInfo->pPrivateStorage) {
  84. delete pDeviceInfo->pPrivateStorage;
  85. pDeviceInfo->pPrivateStorage = NULL;
  86. }
  87. delete pDeviceInfo;
  88. pDeviceInfo = NULL;
  89. }
  90. return hr;
  91. }
  92. //
  93. // Open a connection to the device
  94. //
  95. HRESULT WiaMCamOpen(MCAM_DEVICE_INFO *pDeviceInfo, PWSTR pwszPortName)
  96. {
  97. DBG_FN("WiaMCamOpen");
  98. HRESULT hr = S_OK;
  99. BOOL ret;
  100. //
  101. // Locals
  102. //
  103. TCHAR tszTempStr[MAX_PATH] = TEXT("");
  104. REQUIRE_ARGS(!pDeviceInfo || !pwszPortName, hr, "WiaMCamOpen");
  105. //
  106. // Convert the wide port string to a tstr
  107. //
  108. hr = wiauStrW2T(pwszPortName, tszTempStr, sizeof(tszTempStr));
  109. REQUIRE_SUCCESS(hr, "WiaMCamOpen", "wiauStrW2T failed");
  110. //
  111. // Open the camera
  112. //
  113. hr = FakeCamOpen(tszTempStr, pDeviceInfo);
  114. REQUIRE_SUCCESS(hr, "WiaMCamOpen", "FakeCamOpen failed");
  115. Cleanup:
  116. return hr;
  117. }
  118. //
  119. // Closes the connection with the camera
  120. //
  121. HRESULT WiaMCamClose(MCAM_DEVICE_INFO *pDeviceInfo)
  122. {
  123. DBG_FN("WiaMCamClose");
  124. HRESULT hr = S_OK;
  125. REQUIRE_ARGS(!pDeviceInfo, hr, "WiaMCamClose");
  126. //
  127. // For a real camera, CloseHandle should be called here
  128. //
  129. Cleanup:
  130. return hr;
  131. }
  132. //
  133. // Returns information about the camera, the list of items on the camera,
  134. // and starts monitoring events from the camera
  135. //
  136. HRESULT WiaMCamGetDeviceInfo(MCAM_DEVICE_INFO *pDeviceInfo, MCAM_ITEM_INFO **ppItemList)
  137. {
  138. DBG_FN("WiaMCamGetDeviceInfo");
  139. HRESULT hr = S_OK;
  140. //
  141. // Locals
  142. //
  143. FAKECAM_DEVICE_INFO *pPrivateDeviceInfo = NULL;
  144. PTSTR ptszRootPath = NULL;
  145. REQUIRE_ARGS(!pDeviceInfo || !ppItemList || !pDeviceInfo->pPrivateStorage, hr, "WiaMCamGetDeviceInfo");
  146. *ppItemList = NULL;
  147. pPrivateDeviceInfo = (UNALIGNED FAKECAM_DEVICE_INFO *) pDeviceInfo->pPrivateStorage;
  148. ptszRootPath = pPrivateDeviceInfo->tszRootPath;
  149. //
  150. // Build a list of all items available. The fields in the item info
  151. // structure can either be filled in here, or for better performance
  152. // wait until GetItemInfo is called.
  153. //
  154. hr = SearchDir(pPrivateDeviceInfo, NULL, ptszRootPath);
  155. REQUIRE_SUCCESS(hr, "WiaMCamGetDeviceInfo", "SearchDir failed");
  156. //
  157. // Fill in the MCAM_DEVICE_INFO structure
  158. //
  159. //
  160. // Firmware version should be retrieved from the device, converting
  161. // to WSTR if necessary
  162. //
  163. pDeviceInfo->pwszFirmwareVer = L"04.18.65";
  164. // ISSUE-8/4/2000-davepar Put properties into an INI file
  165. pDeviceInfo->lPicturesTaken = pPrivateDeviceInfo->iNumImages;
  166. pDeviceInfo->lPicturesRemaining = 100 - pDeviceInfo->lPicturesTaken;
  167. pDeviceInfo->lTotalItems = pPrivateDeviceInfo->iNumItems;
  168. GetLocalTime(&pDeviceInfo->Time);
  169. // pDeviceInfo->lExposureMode = EXPOSUREMODE_MANUAL;
  170. // pDeviceInfo->lExposureComp = 0;
  171. *ppItemList = pPrivateDeviceInfo->pFirstItem;
  172. Cleanup:
  173. return hr;
  174. }
  175. //
  176. // Called to retrieve an event from the device
  177. //
  178. HRESULT WiaMCamReadEvent(MCAM_DEVICE_INFO *pDeviceInfo, MCAM_EVENT_INFO **ppEventList)
  179. {
  180. DBG_FN("WiaMCamReadEvent");
  181. HRESULT hr = S_OK;
  182. return hr;
  183. }
  184. //
  185. // Called when events are no longer needed
  186. //
  187. HRESULT WiaMCamStopEvents(MCAM_DEVICE_INFO *pDeviceInfo)
  188. {
  189. DBG_FN("WiaMCamStopEvents");
  190. HRESULT hr = S_OK;
  191. return hr;
  192. }
  193. //
  194. // Fill in the item info structure
  195. //
  196. HRESULT WiaMCamGetItemInfo(MCAM_DEVICE_INFO *pDeviceInfo, MCAM_ITEM_INFO *pItemInfo)
  197. {
  198. DBG_FN("WiaMCamGetItemInfo");
  199. HRESULT hr = S_OK;
  200. //
  201. // This is where the driver should fill in all the fields in the
  202. // ITEM_INFO structure. For this fake driver, the fields are filled
  203. // in by WiaMCamGetDeviceInfo because it's easier.
  204. //
  205. return hr;
  206. }
  207. //
  208. // Frees the item info structure
  209. //
  210. HRESULT WiaMCamFreeItemInfo(MCAM_DEVICE_INFO *pDeviceInfo, MCAM_ITEM_INFO *pItemInfo)
  211. {
  212. DBG_FN("WiaMCamFreeItemInfo");
  213. HRESULT hr = S_OK;
  214. //
  215. // Locals
  216. //
  217. FAKECAM_DEVICE_INFO *pPrivateDeviceInfo = NULL;
  218. REQUIRE_ARGS(!pDeviceInfo || !pItemInfo || !pDeviceInfo->pPrivateStorage, hr, "WiaMCamFreeItemInfo");
  219. if (pItemInfo->pPrivateStorage) {
  220. PTSTR ptszFullName = (PTSTR) pItemInfo->pPrivateStorage;
  221. wiauDbgTrace("WiaMCamFreeItemInfo", "Removing %" WIAU_DEBUG_TSTR, ptszFullName);
  222. delete []ptszFullName;
  223. ptszFullName = NULL;
  224. pItemInfo->pPrivateStorage = NULL;
  225. }
  226. if (pItemInfo->pwszName)
  227. {
  228. delete []pItemInfo->pwszName;
  229. pItemInfo->pwszName = NULL;
  230. }
  231. pPrivateDeviceInfo = (UNALIGNED FAKECAM_DEVICE_INFO *) pDeviceInfo->pPrivateStorage;
  232. hr = RemoveItem(pPrivateDeviceInfo, pItemInfo);
  233. REQUIRE_SUCCESS(hr, "WiaMCamFreeItemInfo", "RemoveItem failed");
  234. if (IsImageType(pItemInfo->pguidFormat)) {
  235. pPrivateDeviceInfo->iNumImages--;
  236. }
  237. pPrivateDeviceInfo->iNumItems--;
  238. delete pItemInfo;
  239. pItemInfo = NULL;
  240. Cleanup:
  241. return hr;
  242. }
  243. //
  244. // Retrieves the thumbnail for an item
  245. //
  246. HRESULT WiaMCamGetThumbnail(MCAM_DEVICE_INFO *pDeviceInfo, MCAM_ITEM_INFO *pItem,
  247. int *pThumbSize, BYTE **ppThumb)
  248. {
  249. DBG_FN("WiaMCamGetThumbnail");
  250. HRESULT hr = S_OK;
  251. //
  252. // Locals
  253. //
  254. PTSTR ptszFullName = NULL;
  255. BYTE *pBuffer = NULL;
  256. LONG ThumbOffset = 0;
  257. REQUIRE_ARGS(!pDeviceInfo || !pItem || !pThumbSize || !ppThumb, hr, "WiaMCamGetThumbnail");
  258. *ppThumb = NULL;
  259. *pThumbSize = 0;
  260. ptszFullName = (PTSTR) pItem->pPrivateStorage;
  261. hr = ReadJpegHdr(ptszFullName, &pBuffer);
  262. REQUIRE_SUCCESS(hr, "WiaMCamGetThumbnail", "ReadJpegHdr failed");
  263. IFD ImageIfd, ThumbIfd;
  264. BOOL bSwap;
  265. hr = ReadExifJpeg(pBuffer, &ImageIfd, &ThumbIfd, &bSwap);
  266. REQUIRE_SUCCESS(hr, "WiaMCamGetThumbnail", "ReadExifJpeg failed");
  267. for (int count = 0; count < ThumbIfd.Count; count++)
  268. {
  269. if (ThumbIfd.pEntries[count].Tag == TIFF_JPEG_DATA) {
  270. ThumbOffset = ThumbIfd.pEntries[count].Offset;
  271. }
  272. else if (ThumbIfd.pEntries[count].Tag == TIFF_JPEG_LEN) {
  273. *pThumbSize = ThumbIfd.pEntries[count].Offset;
  274. }
  275. }
  276. if (!ThumbOffset || !*pThumbSize)
  277. {
  278. wiauDbgError("WiaMCamGetThumbnail", "Thumbnail not found");
  279. hr = E_FAIL;
  280. goto Cleanup;
  281. }
  282. *ppThumb = new BYTE[*pThumbSize];
  283. REQUIRE_ALLOC(*ppThumb, hr, "WiaMCamGetThumbnail");
  284. memcpy(*ppThumb, pBuffer + APP1_OFFSET + ThumbOffset, *pThumbSize);
  285. Cleanup:
  286. if (pBuffer) {
  287. delete []pBuffer;
  288. }
  289. FreeIfd(&ImageIfd);
  290. FreeIfd(&ThumbIfd);
  291. return hr;
  292. }
  293. //
  294. // Retrieves the data for an item
  295. //
  296. HRESULT WiaMCamGetItemData(MCAM_DEVICE_INFO *pDeviceInfo, MCAM_ITEM_INFO *pItem,
  297. UINT uiState, BYTE *pBuf, DWORD dwLength)
  298. {
  299. DBG_FN("WiaMCamGetItemData");
  300. HRESULT hr = S_OK;
  301. BOOL ret;
  302. //
  303. // Locals
  304. //
  305. PTSTR ptszFullName = NULL;
  306. FAKECAM_DEVICE_INFO *pPrivateDeviceInfo = NULL;
  307. REQUIRE_ARGS(!pDeviceInfo || !pItem || !pDeviceInfo->pPrivateStorage, hr, "WiaMCamGetItemData");
  308. pPrivateDeviceInfo = (UNALIGNED FAKECAM_DEVICE_INFO *) pDeviceInfo->pPrivateStorage;
  309. if (uiState & MCAM_STATE_FIRST)
  310. {
  311. if (pPrivateDeviceInfo->hFile != NULL)
  312. {
  313. wiauDbgError("WiaMCamGetItemData", "File handle is already open");
  314. hr = E_FAIL;
  315. goto Cleanup;
  316. }
  317. ptszFullName = (PTSTR) pItem->pPrivateStorage;
  318. wiauDbgTrace("WiaMCamGetItemData", "Opening %" WIAU_DEBUG_TSTR " for reading", ptszFullName);
  319. pPrivateDeviceInfo->hFile = CreateFile(ptszFullName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
  320. REQUIRE_FILEHANDLE(pPrivateDeviceInfo->hFile, hr, "WiaMCamGetItemData", "CreateFile failed");
  321. }
  322. if (!(uiState & MCAM_STATE_CANCEL))
  323. {
  324. DWORD dwReceived = 0;
  325. if (!pPrivateDeviceInfo->hFile) {
  326. wiauDbgError("WiaMCamGetItemData", "File handle is NULL");
  327. hr = E_FAIL;
  328. goto Cleanup;
  329. }
  330. if (!pBuf) {
  331. wiauDbgError("WiaMCamGetItemData", "Data buffer is NULL");
  332. hr = E_INVALIDARG;
  333. goto Cleanup;
  334. }
  335. ret = ReadFile(pPrivateDeviceInfo->hFile, pBuf, dwLength, &dwReceived, NULL);
  336. REQUIRE_FILEIO(ret, hr, "WiaMCamGetItemData", "ReadFile failed");
  337. if (dwLength != dwReceived)
  338. {
  339. wiauDbgError("WiaMCamGetItemData", "Incorrect amount read %d", dwReceived);
  340. hr = E_FAIL;
  341. goto Cleanup;
  342. }
  343. Sleep(100);
  344. }
  345. if (uiState & (MCAM_STATE_LAST | MCAM_STATE_CANCEL))
  346. {
  347. if (!pPrivateDeviceInfo->hFile) {
  348. wiauDbgError("WiaMCamGetItemData", "File handle is NULL");
  349. hr = E_FAIL;
  350. goto Cleanup;
  351. }
  352. CloseHandle(pPrivateDeviceInfo->hFile);
  353. pPrivateDeviceInfo->hFile = NULL;
  354. }
  355. Cleanup:
  356. return hr;
  357. }
  358. //
  359. // Deletes an item
  360. //
  361. HRESULT WiaMCamDeleteItem(MCAM_DEVICE_INFO *pDeviceInfo, MCAM_ITEM_INFO *pItem)
  362. {
  363. DBG_FN("WiaMCamDeleteItem");
  364. HRESULT hr = S_OK;
  365. BOOL ret;
  366. //
  367. // Locals
  368. //
  369. DWORD dwFileAttr = 0;
  370. PTSTR ptszFullName = NULL;
  371. REQUIRE_ARGS(!pDeviceInfo || !pItem, hr, "WiaMCamDeleteItem");
  372. ptszFullName = (PTSTR) pItem->pPrivateStorage;
  373. dwFileAttr = GetFileAttributes(ptszFullName);
  374. REQUIRE_FILEIO(dwFileAttr != -1, hr, "WiaMCamDeleteItem", "GetFileAttributes failed");
  375. dwFileAttr |= FILE_ATTRIBUTE_HIDDEN;
  376. ret = SetFileAttributes(ptszFullName, dwFileAttr);
  377. REQUIRE_FILEIO(ret, hr, "WiaMCamDeleteItem", "SetFileAttributes failed");
  378. wiauDbgTrace("WiaMCamDeleteItem", "File %" WIAU_DEBUG_TSTR " is now hidden", ptszFullName);
  379. Cleanup:
  380. return hr;
  381. }
  382. //
  383. // Sets the protection for an item
  384. //
  385. HRESULT WiaMCamSetItemProt(MCAM_DEVICE_INFO *pDeviceInfo, MCAM_ITEM_INFO *pItem, BOOL bReadOnly)
  386. {
  387. DBG_FN("WiaMCamSetItemProt");
  388. HRESULT hr = S_OK;
  389. BOOL ret;
  390. //
  391. // Locals
  392. //
  393. DWORD dwFileAttr = 0;
  394. PTSTR ptszFullName = NULL;
  395. REQUIRE_ARGS(!pDeviceInfo || !pItem, hr, "WiaMCamSetItemProt");
  396. ptszFullName = (PTSTR) pItem->pPrivateStorage;
  397. dwFileAttr = GetFileAttributes(ptszFullName);
  398. REQUIRE_FILEIO(dwFileAttr != -1, hr, "WiaMCamSetItemProt", "GetFileAttributes failed");
  399. if (bReadOnly)
  400. dwFileAttr |= FILE_ATTRIBUTE_READONLY;
  401. else
  402. dwFileAttr &= ~FILE_ATTRIBUTE_READONLY;
  403. ret = SetFileAttributes(ptszFullName, dwFileAttr);
  404. REQUIRE_FILEIO(ret, hr, "WiaMCamSetItemProt", "SetFileAttributes failed");
  405. wiauDbgTrace("WiaMCamSetItemProt", "Protection on file %" WIAU_DEBUG_TSTR " set to %d", ptszFullName, bReadOnly);
  406. Cleanup:
  407. return hr;
  408. }
  409. //
  410. // Captures a new image
  411. //
  412. HRESULT WiaMCamTakePicture(MCAM_DEVICE_INFO *pDeviceInfo, MCAM_ITEM_INFO **ppItem)
  413. {
  414. DBG_FN("WiaMCamTakePicture");
  415. HRESULT hr = S_OK;
  416. REQUIRE_ARGS(!pDeviceInfo || !ppItem, hr, "WiaMCamTakePicture");
  417. *ppItem = NULL;
  418. Cleanup:
  419. return hr;
  420. }
  421. //
  422. // See if the camera is active
  423. //
  424. HRESULT WiaMCamStatus(MCAM_DEVICE_INFO *pDeviceInfo)
  425. {
  426. DBG_FN("WiaMCamStatus");
  427. HRESULT hr = S_OK;
  428. REQUIRE_ARGS(!pDeviceInfo, hr, "WiaMCamStatus");
  429. //
  430. // This sample device is always active, but your driver should contact the
  431. // device and return S_FALSE if it's not ready.
  432. //
  433. // if (NotReady)
  434. // return S_FALSE;
  435. Cleanup:
  436. return hr;
  437. }
  438. //
  439. // Reset the camera
  440. //
  441. HRESULT WiaMCamReset(MCAM_DEVICE_INFO *pDeviceInfo)
  442. {
  443. DBG_FN("WiaMCamReset");
  444. HRESULT hr = S_OK;
  445. REQUIRE_ARGS(!pDeviceInfo, hr, "WiaMCamReset");
  446. Cleanup:
  447. return hr;
  448. }
  449. ////////////////////////////////
  450. //
  451. // Helper functions
  452. //
  453. ////////////////////////////////
  454. //
  455. // This function pretends to open a camera. A real driver
  456. // would call CreateDevice.
  457. //
  458. HRESULT FakeCamOpen(PTSTR ptszPortName, MCAM_DEVICE_INFO *pDeviceInfo)
  459. {
  460. DBG_FN("FakeCamOpen");
  461. HRESULT hr = S_OK;
  462. BOOL ret = FALSE;
  463. //
  464. // Locals
  465. //
  466. FAKECAM_DEVICE_INFO *pPrivateDeviceInfo = NULL;
  467. DWORD dwFileAttr = 0;
  468. PTSTR ptszRootPath = NULL;
  469. UINT uiRootPathSize = 0;
  470. TCHAR tszPathTemplate[] = TEXT("%userprofile%\\image");
  471. //
  472. // Get a pointer to the private storage, so we can put the
  473. // directory name there
  474. //
  475. pPrivateDeviceInfo = (UNALIGNED FAKECAM_DEVICE_INFO *) pDeviceInfo->pPrivateStorage;
  476. ptszRootPath = pPrivateDeviceInfo->tszRootPath;
  477. uiRootPathSize = sizeof(pPrivateDeviceInfo->tszRootPath) / sizeof(pPrivateDeviceInfo->tszRootPath[0]);
  478. //
  479. // Unless the port name is set to something other than COMx,
  480. // LPTx, or AUTO, use %userprofile%\image as the search directory.
  481. // Since driver runs in LOCAL SERVICE context, %userprofile% points to profile
  482. // of LOCAL SERVICE account, like "Documents and Settings\Local Service"
  483. //
  484. if (_tcsstr(ptszPortName, TEXT("COM")) ||
  485. _tcsstr(ptszPortName, TEXT("LPT")) ||
  486. CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, ptszPortName, -1, TEXT("AUTO"), -1) == CSTR_EQUAL)
  487. {
  488. DWORD dwResult = ExpandEnvironmentStrings(tszPathTemplate, ptszRootPath, uiRootPathSize);
  489. if (dwResult == 0 || dwResult > uiRootPathSize)
  490. {
  491. wiauDbgError("WiaMCamOpen", "ExpandEnvironmentStrings failed");
  492. hr = E_FAIL;
  493. goto Cleanup;
  494. }
  495. }
  496. else
  497. {
  498. lstrcpyn(ptszRootPath, ptszPortName, uiRootPathSize);
  499. }
  500. wiauDbgTrace("Open", "Image directory path is %" WIAU_DEBUG_TSTR, ptszRootPath);
  501. dwFileAttr = GetFileAttributes(ptszRootPath);
  502. if (dwFileAttr == -1)
  503. {
  504. hr = HRESULT_FROM_WIN32(::GetLastError());
  505. if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  506. {
  507. hr = S_OK;
  508. ret = CreateDirectory(ptszRootPath, NULL);
  509. REQUIRE_FILEIO(ret, hr, "Open", "CreateDirectory failed");
  510. }
  511. else
  512. {
  513. wiauDbgErrorHr(hr, "Open", "GetFileAttributes failed");
  514. goto Cleanup;
  515. }
  516. }
  517. Cleanup:
  518. return hr;
  519. }
  520. //
  521. // This function searches a directory on the hard drive for
  522. // items.
  523. //
  524. HRESULT SearchDir(FAKECAM_DEVICE_INFO *pPrivateDeviceInfo, MCAM_ITEM_INFO *pParent, PTSTR ptszPath)
  525. {
  526. DBG_FN("SearchDir");
  527. HRESULT hr = S_OK;
  528. //
  529. // Locals
  530. //
  531. HANDLE hFind = NULL;
  532. WIN32_FIND_DATA FindData;
  533. const cchTempStrSize = MAX_PATH;
  534. TCHAR tszTempStr[cchTempStrSize] = TEXT("");
  535. TCHAR tszFullName[MAX_PATH] = TEXT("");;
  536. MCAM_ITEM_INFO *pFolder = NULL;
  537. MCAM_ITEM_INFO *pImage = NULL;
  538. REQUIRE_ARGS(!pPrivateDeviceInfo || !ptszPath, hr, "SearchDir");
  539. //
  540. // Search for folders first
  541. //
  542. //
  543. // Make sure search path fits into the buffer and gets zero-terminated
  544. //
  545. if (_sntprintf(tszTempStr, cchTempStrSize, _T("%s\\*"), ptszPath) < 0)
  546. {
  547. wiauDbgError("SearchDir", "Too long path for search");
  548. hr = E_FAIL;
  549. goto Cleanup;
  550. }
  551. tszTempStr[cchTempStrSize - 1] = 0;
  552. wiauDbgTrace("SearchDir", "Searching directory %" WIAU_DEBUG_TSTR, tszTempStr);
  553. memset(&FindData, 0, sizeof(FindData));
  554. hFind = FindFirstFile(tszTempStr, &FindData);
  555. if (hFind == INVALID_HANDLE_VALUE)
  556. {
  557. hr = HRESULT_FROM_WIN32(::GetLastError());
  558. if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  559. {
  560. hr = S_OK;
  561. wiauDbgWarning("SearchDir", "Directory %" WIAU_DEBUG_TSTR " is empty", tszTempStr);
  562. goto Cleanup;
  563. }
  564. else
  565. {
  566. wiauDbgErrorHr(hr, "SearchDir", "FindFirstFile failed");
  567. goto Cleanup;
  568. }
  569. }
  570. while (hr == S_OK)
  571. {
  572. if ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  573. (FindData.cFileName[0] != L'.'))
  574. {
  575. hr = MakeFullName(tszFullName, sizeof(tszFullName) / sizeof(tszFullName[0]),
  576. ptszPath, FindData.cFileName);
  577. REQUIRE_SUCCESS(hr, "SearchDir", "MakeFullName failed");
  578. hr = CreateFolder(pPrivateDeviceInfo, pParent, &FindData, &pFolder, tszFullName);
  579. REQUIRE_SUCCESS(hr, "SearchDir", "CreateFolder failed");
  580. hr = AddItem(pPrivateDeviceInfo, pFolder);
  581. REQUIRE_SUCCESS(hr, "SearchDir", "AddItem failed");
  582. hr = SearchDir(pPrivateDeviceInfo, pFolder, tszFullName);
  583. REQUIRE_SUCCESS(hr, "SearchDir", "Recursive SearchDir failed");
  584. }
  585. memset(&FindData, 0, sizeof(FindData));
  586. if (!FindNextFile(hFind, &FindData))
  587. {
  588. hr = HRESULT_FROM_WIN32(::GetLastError());
  589. if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES))
  590. {
  591. wiauDbgErrorHr(hr, "SearchDir", "FindNextFile failed");
  592. goto Cleanup;
  593. }
  594. }
  595. }
  596. FindClose(hFind);
  597. hr = S_OK;
  598. //
  599. // Search next for JPEGs
  600. //
  601. //
  602. // Make sure search path fits into the buffer and gets zero-terminated
  603. //
  604. if (_sntprintf(tszTempStr, cchTempStrSize, _T("%s\\*.jpg"), ptszPath) < 0)
  605. {
  606. wiauDbgError("SearchDir", "Too long path for search");
  607. hr = E_FAIL;
  608. goto Cleanup;
  609. }
  610. tszTempStr[cchTempStrSize - 1] = 0;
  611. memset(&FindData, 0, sizeof(FindData));
  612. hFind = FindFirstFile(tszTempStr, &FindData);
  613. if (hFind == INVALID_HANDLE_VALUE)
  614. {
  615. hr = HRESULT_FROM_WIN32(::GetLastError());
  616. if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  617. {
  618. hr = S_OK;
  619. wiauDbgWarning("SearchDir", "No JPEGs in directory %" WIAU_DEBUG_TSTR, tszTempStr);
  620. goto Cleanup;
  621. }
  622. else
  623. {
  624. wiauDbgErrorHr(hr, "SearchDir", "FindFirstFile failed");
  625. goto Cleanup;
  626. }
  627. }
  628. while (hr == S_OK)
  629. {
  630. if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
  631. {
  632. hr = MakeFullName(tszFullName, sizeof(tszFullName) / sizeof(tszFullName[0]),
  633. ptszPath, FindData.cFileName);
  634. REQUIRE_SUCCESS(hr, "SearchDir", "MakeFullName failed");
  635. hr = CreateImage(pPrivateDeviceInfo, pParent, &FindData, &pImage, tszFullName);
  636. REQUIRE_SUCCESS(hr, "SearchDir", "CreateImage failed");
  637. hr = AddItem(pPrivateDeviceInfo, pImage);
  638. REQUIRE_SUCCESS(hr, "SearchDir", "AddItem failed");
  639. hr = SearchForAttachments(pPrivateDeviceInfo, pImage, tszFullName);
  640. REQUIRE_SUCCESS(hr, "SearchDir", "SearchForAttachments failed");
  641. if (hr == S_OK)
  642. pImage->bHasAttachments = TRUE;
  643. hr = S_OK;
  644. }
  645. memset(&FindData, 0, sizeof(FindData));
  646. if (!FindNextFile(hFind, &FindData))
  647. {
  648. hr = HRESULT_FROM_WIN32(::GetLastError());
  649. if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES))
  650. {
  651. wiauDbgErrorHr(hr, "SearchDir", "FindNextFile failed");
  652. goto Cleanup;
  653. }
  654. }
  655. }
  656. FindClose(hFind);
  657. hr = S_OK;
  658. //
  659. // ISSUE-10/18/2000-davepar Do the same for other image types
  660. //
  661. Cleanup:
  662. return hr;
  663. }
  664. //
  665. // Searches for attachments to an image item
  666. //
  667. HRESULT SearchForAttachments(FAKECAM_DEVICE_INFO *pPrivateDeviceInfo, MCAM_ITEM_INFO *pParent, PTSTR ptszMainItem)
  668. {
  669. DBG_FN("SearchForAttachments");
  670. HRESULT hr = S_OK;
  671. //
  672. // Locals
  673. //
  674. INT iNumAttachments = 0;
  675. HANDLE hFind = NULL;
  676. WIN32_FIND_DATA FindData;
  677. TCHAR tszTempStr[MAX_PATH] = TEXT("");
  678. TCHAR tszFullName[MAX_PATH] = TEXT("");
  679. TCHAR *ptcSlash = NULL;
  680. TCHAR *ptcDot = NULL;
  681. MCAM_ITEM_INFO *pNonImage = NULL;
  682. REQUIRE_ARGS(!pPrivateDeviceInfo || !ptszMainItem, hr, "SearchForAttachments");
  683. //
  684. // Find the last dot in the filename and replace the file extension with * and do the search
  685. //
  686. lstrcpyn(tszTempStr, ptszMainItem, sizeof(tszTempStr) / sizeof(tszTempStr[0]) - 1);
  687. ptcDot = _tcsrchr(tszTempStr, TEXT('.'));
  688. if (ptcDot)
  689. {
  690. *(ptcDot+1) = TEXT('*');
  691. *(ptcDot+2) = TEXT('\0');
  692. }
  693. else
  694. {
  695. wiauDbgError("SearchForAttachments", "Filename did not contain a dot");
  696. hr = E_FAIL;
  697. goto Cleanup;
  698. }
  699. //
  700. // Replace the first four "free" characters of the name with ? (attachments only need to match
  701. // the last four characters of the name)
  702. //
  703. ptcSlash = _tcsrchr(tszTempStr, TEXT('\\'));
  704. if (ptcSlash && ptcDot - ptcSlash > 4)
  705. {
  706. for (INT i = 1; i < 5; i++)
  707. *(ptcSlash+i) = TEXT('?');
  708. }
  709. memset(&FindData, 0, sizeof(FindData));
  710. hFind = FindFirstFile(tszTempStr, &FindData);
  711. REQUIRE_FILEHANDLE(hFind, hr, "SearchForAttachments", "FindFirstFile failed");
  712. while (hr == S_OK)
  713. {
  714. if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) &&
  715. !(_tcsstr(ptszMainItem, FindData.cFileName)))
  716. {
  717. //
  718. // Figure out the full name for the item
  719. //
  720. lstrcpyn(tszTempStr, ptszMainItem, sizeof(tszTempStr) / sizeof(tszTempStr[0]));
  721. ptcSlash = _tcsrchr(tszTempStr, TEXT('\\'));
  722. if (ptcSlash)
  723. {
  724. *ptcSlash = TEXT('\0');
  725. }
  726. hr = MakeFullName(tszFullName, sizeof(tszFullName) / sizeof(tszFullName[0]),
  727. tszTempStr, FindData.cFileName);
  728. REQUIRE_SUCCESS(hr, "SearchForAttachments", "MakeFullName failed");
  729. hr = CreateNonImage(pPrivateDeviceInfo, pParent, &FindData, &pNonImage, tszFullName);
  730. REQUIRE_SUCCESS(hr, "SearchForAttachments", "CreateNonImage failed");
  731. hr = AddItem(pPrivateDeviceInfo, pNonImage);
  732. REQUIRE_SUCCESS(hr, "SearchForAttachments", "AddItem failed");
  733. iNumAttachments++;
  734. }
  735. memset(&FindData, 0, sizeof(FindData));
  736. if (!FindNextFile(hFind, &FindData))
  737. {
  738. hr = HRESULT_FROM_WIN32(::GetLastError());
  739. if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES))
  740. {
  741. wiauDbgErrorHr(hr, "SearchForAttachments", "FindNextFile failed");
  742. goto Cleanup;
  743. }
  744. }
  745. }
  746. FindClose(hFind);
  747. if (iNumAttachments > 0)
  748. hr = S_OK;
  749. else
  750. hr = S_FALSE;
  751. Cleanup:
  752. return hr;
  753. }
  754. HRESULT CreateFolder(FAKECAM_DEVICE_INFO *pPrivateDeviceInfo, MCAM_ITEM_INFO *pParent,
  755. WIN32_FIND_DATA *pFindData, MCAM_ITEM_INFO **ppFolder, PTSTR ptszFullName)
  756. {
  757. DBG_FN("CreateFolder");
  758. HRESULT hr = S_OK;
  759. //
  760. // Locals
  761. //
  762. TCHAR *ptcDot = NULL;
  763. MCAM_ITEM_INFO *pItem = NULL;
  764. TCHAR tszTempStr[MAX_PATH] = TEXT("");
  765. REQUIRE_ARGS(!pPrivateDeviceInfo || !pFindData || !ppFolder || !ptszFullName, hr, "CreateFolder");
  766. *ppFolder = NULL;
  767. pItem = new MCAM_ITEM_INFO;
  768. REQUIRE_ALLOC(pItem, hr, "CreateFolder");
  769. //
  770. // Chop off the filename extension from the name, if it exists
  771. //
  772. lstrcpyn(tszTempStr, pFindData->cFileName, sizeof(tszTempStr) / sizeof(tszTempStr[0]));
  773. ptcDot = _tcsrchr(tszTempStr, TEXT('.'));
  774. if (ptcDot)
  775. *ptcDot = TEXT('\0');
  776. //
  777. // Fill in the MCAM_ITEM_INFO structure
  778. //
  779. hr = SetCommonFields(pItem, tszTempStr, ptszFullName, pFindData);
  780. REQUIRE_SUCCESS(hr, "CreateFolder", "SetCommonFields failed");
  781. pItem->pParent = pParent;
  782. pItem->iType = WiaMCamTypeFolder;
  783. *ppFolder = pItem;
  784. pPrivateDeviceInfo->iNumItems++;
  785. wiauDbgTrace("CreateFolder", "Created folder %" WIAU_DEBUG_TSTR " at 0x%08x under 0x%08x", pFindData->cFileName, pItem, pParent);
  786. Cleanup:
  787. return hr;
  788. }
  789. HRESULT CreateImage(FAKECAM_DEVICE_INFO *pPrivateDeviceInfo, MCAM_ITEM_INFO *pParent,
  790. WIN32_FIND_DATA *pFindData, MCAM_ITEM_INFO **ppImage, PTSTR ptszFullName)
  791. {
  792. DBG_FN("CreateImage");
  793. HRESULT hr = S_OK;
  794. //
  795. // Locals
  796. //
  797. PTSTR ptszDot = NULL;
  798. MCAM_ITEM_INFO *pItem = NULL;
  799. TCHAR tszTempStr[MAX_PATH] = TEXT("");
  800. WORD width = 0;
  801. WORD height = 0;
  802. REQUIRE_ARGS(!pPrivateDeviceInfo || !pFindData || !ppImage || !ptszFullName, hr, "CreateImage");
  803. *ppImage = NULL;
  804. pItem = new MCAM_ITEM_INFO;
  805. REQUIRE_ALLOC(pItem, hr, "CreateImage");
  806. //
  807. // Chop off the filename extension from the name, if it exists
  808. //
  809. lstrcpyn(tszTempStr, pFindData->cFileName, sizeof(tszTempStr) / sizeof(tszTempStr[0]));
  810. ptszDot = _tcsrchr(tszTempStr, TEXT('.'));
  811. if (ptszDot)
  812. *ptszDot = TEXT('\0');
  813. //
  814. // Fill in the MCAM_ITEM_INFO structure
  815. //
  816. hr = SetCommonFields(pItem, tszTempStr, ptszFullName, pFindData);
  817. REQUIRE_SUCCESS(hr, "CreateImage", "SetCommonFields failed");
  818. pItem->pParent = pParent;
  819. pItem->iType = WiaMCamTypeImage;
  820. pItem->pguidFormat = &WiaImgFmt_JPEG;
  821. pItem->lSize = pFindData->nFileSizeLow;
  822. pItem->pguidThumbFormat = &WiaImgFmt_JPEG;
  823. //
  824. // Copy the file extension into the extension field
  825. //
  826. if (ptszDot) {
  827. hr = wiauStrT2W(ptszDot + 1, pItem->wszExt, MCAM_EXT_LEN * sizeof(pItem->wszExt[0]));
  828. REQUIRE_SUCCESS(hr, "CreateImage", "wiauStrT2W failed");
  829. }
  830. //
  831. // Interpret the JPEG image to get the image dimensions and thumbnail size
  832. //
  833. hr = ReadDimFromJpeg(ptszFullName, &width, &height);
  834. REQUIRE_SUCCESS(hr, "CreateImage", "ReadDimFromJpeg failed");
  835. pItem->lWidth = width;
  836. pItem->lHeight = height;
  837. pItem->lDepth = 24;
  838. pItem->lChannels = 3;
  839. pItem->lBitsPerChannel = 8;
  840. *ppImage = pItem;
  841. pPrivateDeviceInfo->iNumItems++;
  842. pPrivateDeviceInfo->iNumImages++;
  843. wiauDbgTrace("CreateImage", "Created image %" WIAU_DEBUG_TSTR " at 0x%08x under 0x%08x", pFindData->cFileName, pItem, pParent);
  844. Cleanup:
  845. return hr;
  846. }
  847. HRESULT CreateNonImage(FAKECAM_DEVICE_INFO *pPrivateDeviceInfo, MCAM_ITEM_INFO *pParent,
  848. WIN32_FIND_DATA *pFindData, MCAM_ITEM_INFO **ppNonImage, PTSTR ptszFullName)
  849. {
  850. DBG_FN("CreateNonImage");
  851. HRESULT hr = S_OK;
  852. //
  853. // Locals
  854. //
  855. PTSTR ptszDot = NULL;
  856. MCAM_ITEM_INFO *pItem = NULL;
  857. TCHAR tszTempStr[MAX_PATH] = TEXT("");
  858. PTSTR ptszExt = NULL;
  859. REQUIRE_ARGS(!pPrivateDeviceInfo || !pFindData || !ppNonImage || !ptszFullName, hr, "CreateNonImage");
  860. *ppNonImage = NULL;
  861. pItem = new MCAM_ITEM_INFO;
  862. REQUIRE_ALLOC(pItem, hr, "CreateNonImage");
  863. //
  864. // The name cannot contain a dot and the name needs to be unique
  865. // wrt the parent image, so replace the dot with an underline character.
  866. //
  867. lstrcpyn(tszTempStr, pFindData->cFileName, sizeof(tszTempStr) / sizeof(tszTempStr[0]));
  868. ptszDot = _tcsrchr(tszTempStr, TEXT('.'));
  869. if (ptszDot)
  870. *ptszDot = TEXT('_');
  871. //
  872. // Fill in the MCAM_ITEM_INFO structure
  873. //
  874. hr = SetCommonFields(pItem, tszTempStr, ptszFullName, pFindData);
  875. REQUIRE_SUCCESS(hr, "CreateNonImage", "SetCommonFields failed");
  876. pItem->pParent = pParent;
  877. pItem->iType = WiaMCamTypeOther;
  878. pItem->lSize = pFindData->nFileSizeLow;
  879. //
  880. // Set the format of the item based on the file extension
  881. //
  882. if (ptszDot) {
  883. ptszExt = ptszDot + 1;
  884. //
  885. // Copy the file extension into the extension field
  886. //
  887. hr = wiauStrT2W(ptszExt, pItem->wszExt, MCAM_EXT_LEN * sizeof(pItem->wszExt[0]));
  888. REQUIRE_SUCCESS(hr, "CreateNonImage", "wiauStrT2W failed");
  889. if (_tcsicmp(ptszExt, TEXT("wav")) == 0) {
  890. pItem->pguidFormat = &WiaAudFmt_WAV;
  891. pItem->iType = WiaMCamTypeAudio;
  892. }
  893. else if (_tcsicmp(ptszExt, TEXT("mp3")) == 0) {
  894. pItem->pguidFormat = &WiaAudFmt_MP3;
  895. pItem->iType = WiaMCamTypeAudio;
  896. }
  897. else if (_tcsicmp(ptszExt, TEXT("wma")) == 0) {
  898. pItem->pguidFormat = &WiaAudFmt_WMA;
  899. pItem->iType = WiaMCamTypeAudio;
  900. }
  901. else if (_tcsicmp(ptszExt, TEXT("rtf")) == 0) {
  902. pItem->pguidFormat = &WiaImgFmt_RTF;
  903. pItem->iType = WiaMCamTypeOther;
  904. }
  905. else if (_tcsicmp(ptszExt, TEXT("htm")) == 0) {
  906. pItem->pguidFormat = &WiaImgFmt_HTML;
  907. pItem->iType = WiaMCamTypeOther;
  908. }
  909. else if (_tcsicmp(ptszExt, TEXT("html")) == 0) {
  910. pItem->pguidFormat = &WiaImgFmt_HTML;
  911. pItem->iType = WiaMCamTypeOther;
  912. }
  913. else if (_tcsicmp(ptszExt, TEXT("txt")) == 0) {
  914. pItem->pguidFormat = &WiaImgFmt_TXT;
  915. pItem->iType = WiaMCamTypeOther;
  916. }
  917. else if (_tcsicmp(ptszExt, TEXT("mpg")) == 0) {
  918. pItem->pguidFormat = &WiaImgFmt_MPG;
  919. pItem->iType = WiaMCamTypeVideo;
  920. }
  921. else if (_tcsicmp(ptszExt, TEXT("avi")) == 0) {
  922. pItem->pguidFormat = &WiaImgFmt_AVI;
  923. pItem->iType = WiaMCamTypeVideo;
  924. }
  925. else if (_tcsicmp(ptszExt, TEXT("asf")) == 0) {
  926. pItem->pguidFormat = &WiaImgFmt_ASF;
  927. pItem->iType = WiaMCamTypeVideo;
  928. }
  929. else if (_tcsicmp(ptszExt, TEXT("exe")) == 0) {
  930. pItem->pguidFormat = &WiaImgFmt_EXEC;
  931. pItem->iType = WiaMCamTypeOther;
  932. }
  933. else {
  934. //
  935. // Generate a random GUID for the format
  936. //
  937. if (g_guidUnknownFormat.Data1 == 0) {
  938. hr = CoCreateGuid(&g_guidUnknownFormat);
  939. REQUIRE_SUCCESS(hr, "CreateNonImage", "CoCreateGuid failed");
  940. }
  941. pItem->pguidFormat = &g_guidUnknownFormat;
  942. pItem->iType = WiaMCamTypeOther;
  943. }
  944. }
  945. *ppNonImage = pItem;
  946. pPrivateDeviceInfo->iNumItems++;
  947. wiauDbgTrace("CreateNonImage", "Created non-image %" WIAU_DEBUG_TSTR " at 0x%08x under 0x%08x", pFindData->cFileName, pItem, pParent);
  948. Cleanup:
  949. return hr;
  950. }
  951. //
  952. // Sets the fields of the MCAM_ITEM_INFO that are common to all items
  953. //
  954. HRESULT SetCommonFields(MCAM_ITEM_INFO *pItem,
  955. PTSTR ptszShortName,
  956. PTSTR ptszFullName,
  957. WIN32_FIND_DATA *pFindData)
  958. {
  959. DBG_FN("SetCommonFields");
  960. HRESULT hr = S_OK;
  961. BOOL ret;
  962. //
  963. // Locals
  964. //
  965. PTSTR ptszTempStr = NULL;
  966. INT iSize = 0;
  967. REQUIRE_ARGS(!pItem || !ptszShortName || !ptszFullName || !pFindData, hr, "SetFullName");
  968. //
  969. // Initialize the structure
  970. //
  971. memset(pItem, 0, sizeof(MCAM_ITEM_INFO));
  972. pItem->iSize = sizeof(MCAM_ITEM_INFO);
  973. iSize = lstrlen(ptszShortName) + 1;
  974. pItem->pwszName = new WCHAR[iSize];
  975. REQUIRE_ALLOC(pItem->pwszName, hr, "SetCommonFields");
  976. wiauStrT2W(ptszShortName, pItem->pwszName, iSize * sizeof(WCHAR));
  977. REQUIRE_SUCCESS(hr, "SetCommonFields", "wiauStrT2W failed");
  978. FILETIME ftLocalFileTime;
  979. memset(&pItem->Time, 0, sizeof(pItem->Time));
  980. memset(&ftLocalFileTime, 0, sizeof(FILETIME));
  981. ret = FileTimeToLocalFileTime(&pFindData->ftLastWriteTime, &ftLocalFileTime);
  982. REQUIRE_FILEIO(ret, hr, "SetCommonFields", "FileTimeToLocalFileTime failed");
  983. ret = FileTimeToSystemTime(&ftLocalFileTime, &pItem->Time);
  984. REQUIRE_FILEIO(ret, hr, "SetCommonFields", "FileTimeToSystemTime failed");
  985. pItem->bReadOnly = pFindData->dwFileAttributes & FILE_ATTRIBUTE_READONLY;
  986. pItem->bCanSetReadOnly = TRUE;
  987. //
  988. // Set the private storage area of the MCAM_ITEM_INFO structure to the
  989. // full path name of the item
  990. //
  991. iSize = lstrlen(ptszFullName) + 1;
  992. ptszTempStr = new TCHAR[iSize];
  993. REQUIRE_ALLOC(ptszTempStr, hr, "SetCommonFields");
  994. lstrcpy(ptszTempStr, ptszFullName);
  995. pItem->pPrivateStorage = (BYTE *) ptszTempStr;
  996. Cleanup:
  997. return hr;
  998. }
  999. HRESULT AddItem(FAKECAM_DEVICE_INFO *pPrivateDeviceInfo, MCAM_ITEM_INFO *pItem)
  1000. {
  1001. HRESULT hr = S_OK;
  1002. REQUIRE_ARGS(!pPrivateDeviceInfo || !pItem, hr, "AddItem");
  1003. if (pPrivateDeviceInfo->pLastItem) {
  1004. //
  1005. // Insert the item at the end of the list
  1006. //
  1007. pPrivateDeviceInfo->pLastItem->pNext = pItem;
  1008. pItem->pPrev = pPrivateDeviceInfo->pLastItem;
  1009. pItem->pNext = NULL;
  1010. pPrivateDeviceInfo->pLastItem = pItem;
  1011. }
  1012. else
  1013. {
  1014. //
  1015. // List is currently empty, add this as first and only item
  1016. //
  1017. pPrivateDeviceInfo->pFirstItem = pPrivateDeviceInfo->pLastItem = pItem;
  1018. pItem->pPrev = pItem->pNext = NULL;
  1019. }
  1020. Cleanup:
  1021. return hr;
  1022. }
  1023. HRESULT RemoveItem(FAKECAM_DEVICE_INFO *pPrivateDeviceInfo, MCAM_ITEM_INFO *pItem)
  1024. {
  1025. HRESULT hr = S_OK;
  1026. REQUIRE_ARGS(!pPrivateDeviceInfo || !pItem, hr, "RemoveItem");
  1027. if (pItem->pPrev)
  1028. pItem->pPrev->pNext = pItem->pNext;
  1029. if (pItem->pNext)
  1030. pItem->pNext->pPrev = pItem->pPrev;
  1031. if (pPrivateDeviceInfo->pFirstItem == pItem)
  1032. pPrivateDeviceInfo->pFirstItem = pItem->pNext;
  1033. if (pPrivateDeviceInfo->pLastItem == pItem)
  1034. pPrivateDeviceInfo->pLastItem = pItem->pPrev;
  1035. Cleanup:
  1036. return hr;
  1037. }
  1038. //
  1039. // This function reads a JPEG file looking for the frame header, which contains
  1040. // the width and height of the image.
  1041. //
  1042. HRESULT ReadDimFromJpeg(PTSTR ptszFullName, WORD *pWidth, WORD *pHeight)
  1043. {
  1044. DBG_FN("ReadDimFromJpeg");
  1045. HRESULT hr = S_OK;
  1046. BOOL ret;
  1047. //
  1048. // Locals
  1049. //
  1050. HANDLE hFile = NULL;
  1051. BYTE *pBuffer = NULL;
  1052. DWORD BytesRead = 0;
  1053. BYTE *pCur = NULL;
  1054. int SegmentLength = 0;
  1055. const int Overlap = 8; // if pCur gets within Overlap bytes of the end, read another chunk
  1056. const DWORD BytesToRead = 32 * 1024;
  1057. REQUIRE_ARGS(!ptszFullName || !pWidth || !pHeight, hr, "ReadDimFromJpeg");
  1058. *pWidth = 0;
  1059. *pHeight = 0;
  1060. hFile = CreateFile(ptszFullName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
  1061. REQUIRE_FILEHANDLE(hFile, hr, "ReadDimFromJpeg", "CreateFile failed");
  1062. pBuffer = new BYTE[BytesToRead];
  1063. REQUIRE_ALLOC(pBuffer, hr, "ReadDimFromJpeg");
  1064. ret = ReadFile(hFile, pBuffer, BytesToRead, &BytesRead, NULL);
  1065. REQUIRE_FILEIO(ret, hr, "ReadDimFromJpeg", "ReadFile failed");
  1066. wiauDbgTrace("ReadDimFromJpeg", "Read %d bytes", BytesRead);
  1067. pCur = pBuffer;
  1068. //
  1069. // Pretend that we read Overlap fewer bytes than were actually read
  1070. //
  1071. BytesRead -= Overlap;
  1072. while (SUCCEEDED(hr) &&
  1073. BytesRead != 0 &&
  1074. pCur[1] != 0xc0)
  1075. {
  1076. if (pCur[0] != 0xff)
  1077. {
  1078. wiauDbgError("ReadDimFromJpeg", "Not a JFIF format image");
  1079. hr = E_FAIL;
  1080. goto Cleanup;
  1081. }
  1082. //
  1083. // if the marker is >= 0xd0 and <= 0xd9 or is equal to 0x01
  1084. // there is no length field
  1085. //
  1086. if (((pCur[1] & 0xf0) == 0xd0 &&
  1087. (pCur[1] & 0x0f) < 0xa) ||
  1088. pCur[1] == 0x01)
  1089. {
  1090. SegmentLength = 0;
  1091. }
  1092. else
  1093. {
  1094. SegmentLength = ByteSwapWord(*((UNALIGNED WORD *) (pCur + 2)));
  1095. }
  1096. pCur += SegmentLength + 2;
  1097. if (pCur >= pBuffer + BytesRead)
  1098. {
  1099. memcpy(pBuffer, pBuffer + BytesRead, Overlap);
  1100. pCur -= BytesRead;
  1101. ret = ReadFile(hFile, pBuffer + Overlap, BytesToRead - Overlap, &BytesRead, NULL);
  1102. REQUIRE_FILEIO(ret, hr, "ReadDimFromJpeg", "ReadFile failed");
  1103. wiauDbgTrace("ReadDimFromJpeg", "Read %d more bytes", BytesRead);
  1104. }
  1105. }
  1106. if (pCur[0] != 0xff)
  1107. {
  1108. wiauDbgError("ReadDimFromJpeg", "Not a JFIF format image");
  1109. return E_FAIL;
  1110. }
  1111. *pHeight = ByteSwapWord(*((UNALIGNED WORD *) (pCur + 5)));
  1112. *pWidth = ByteSwapWord(*((UNALIGNED WORD *) (pCur + 7)));
  1113. Cleanup:
  1114. if (pBuffer) {
  1115. delete []pBuffer;
  1116. }
  1117. if (hFile && hFile != INVALID_HANDLE_VALUE) {
  1118. CloseHandle(hFile);
  1119. }
  1120. return hr;
  1121. }
  1122. //
  1123. // The next section contains functions useful for reading information from
  1124. // Exif files.
  1125. //
  1126. HRESULT ReadJpegHdr(PTSTR ptszFullName, BYTE **ppBuf)
  1127. {
  1128. DBG_FN("ReadJpegHdr");
  1129. HRESULT hr = S_OK;
  1130. BOOL ret;
  1131. //
  1132. // Locals
  1133. //
  1134. HANDLE hFile = NULL;
  1135. BYTE JpegHdr[] = {0xff, 0xd8, 0xff, 0xe1};
  1136. const int JpegHdrSize = sizeof(JpegHdr) + 2;
  1137. BYTE tempBuf[JpegHdrSize];
  1138. DWORD BytesRead = 0;
  1139. WORD TagSize = 0;
  1140. hFile = CreateFile(ptszFullName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
  1141. REQUIRE_FILEHANDLE(hFile, hr, "ReadJpegHdr", "CreateFile failed");
  1142. ret = ReadFile(hFile, tempBuf, JpegHdrSize, &BytesRead, NULL);
  1143. REQUIRE_FILEIO(ret, hr, "ReadJpegHdr", "ReadFile failed");
  1144. if (BytesRead != JpegHdrSize) {
  1145. wiauDbgError("ReadJpegHdr", "Wrong amount read %d", BytesRead);
  1146. hr = E_FAIL;
  1147. goto Cleanup;
  1148. }
  1149. if (memcmp(tempBuf, JpegHdr, sizeof(JpegHdr)) != 0)
  1150. {
  1151. wiauDbgError("ReadJpegHdr", "JPEG header not found");
  1152. hr = E_FAIL;
  1153. goto Cleanup;
  1154. }
  1155. TagSize = GetWord(tempBuf + sizeof(JpegHdr), TRUE);
  1156. *ppBuf = new BYTE[TagSize];
  1157. REQUIRE_ALLOC(ppBuf, hr, "ReadJpegHdr");
  1158. ret = ReadFile(hFile, *ppBuf, TagSize, &BytesRead, NULL);
  1159. REQUIRE_FILEIO(ret, hr, "ReadJpegHdr", "ReadFile failed");
  1160. if (BytesRead != TagSize)
  1161. {
  1162. wiauDbgError("ReadJpegHdr", "Wrong amount read %d", BytesRead);
  1163. hr = E_FAIL;
  1164. goto Cleanup;
  1165. }
  1166. Cleanup:
  1167. if (hFile && hFile != INVALID_HANDLE_VALUE) {
  1168. CloseHandle(hFile);
  1169. }
  1170. return hr;
  1171. }
  1172. HRESULT ReadExifJpeg(BYTE *pBuf, IFD *pImageIfd, IFD *pThumbIfd, BOOL *pbSwap)
  1173. {
  1174. DBG_FN("ReadExifJpeg");
  1175. HRESULT hr = S_OK;
  1176. BYTE ExifTag[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
  1177. if (memcmp(pBuf, ExifTag, sizeof(ExifTag)) != 0)
  1178. {
  1179. wiauDbgError("ReadExifJpeg", "Exif tag not found");
  1180. hr = E_FAIL;
  1181. goto Cleanup;
  1182. }
  1183. hr = ReadTiff(pBuf + APP1_OFFSET, pImageIfd, pThumbIfd, pbSwap);
  1184. REQUIRE_SUCCESS(hr, "ReadExifJpeg", "ReadTiff failed");
  1185. Cleanup:
  1186. return hr;
  1187. }
  1188. HRESULT ReadTiff(BYTE *pBuf, IFD *pImageIfd, IFD *pThumbIfd, BOOL *pbSwap)
  1189. {
  1190. DBG_FN("ReadTiff");
  1191. HRESULT hr = S_OK;
  1192. //
  1193. // Locals
  1194. //
  1195. WORD MagicNumber = 0;
  1196. *pbSwap = FALSE;
  1197. if (pBuf[0] == 0x4d) {
  1198. *pbSwap = TRUE;
  1199. if (pBuf[1] != 0x4d)
  1200. {
  1201. wiauDbgError("ReadTiff", "Second TIFF byte swap indicator not present");
  1202. hr = E_FAIL;
  1203. goto Cleanup;
  1204. }
  1205. }
  1206. else if (pBuf[0] != 0x49 ||
  1207. pBuf[1] != 0x49)
  1208. {
  1209. wiauDbgError("ReadTiff", "TIFF byte swap indicator not present");
  1210. hr = E_FAIL;
  1211. goto Cleanup;
  1212. }
  1213. MagicNumber = GetWord(pBuf+2, *pbSwap);
  1214. if (MagicNumber != 42)
  1215. {
  1216. wiauDbgError("ReadTiff", "TIFF magic number not present");
  1217. hr = E_FAIL;
  1218. goto Cleanup;
  1219. }
  1220. wiauDbgTrace("ReadTiff", "Reading image IFD");
  1221. pImageIfd->Offset = GetDword(pBuf + 4, *pbSwap);
  1222. hr = ReadIfd(pBuf, pImageIfd, *pbSwap);
  1223. REQUIRE_SUCCESS(hr, "ReadTiff", "ReadIfd failed");
  1224. wiauDbgTrace("ReadTiff", "Reading thumb IFD");
  1225. pThumbIfd->Offset = pImageIfd->NextIfdOffset;
  1226. hr = ReadIfd(pBuf, pThumbIfd, *pbSwap);
  1227. REQUIRE_SUCCESS(hr, "ReadTiff", "ReadIfd failed");
  1228. Cleanup:
  1229. return hr;
  1230. }
  1231. HRESULT ReadIfd(BYTE *pBuf, IFD *pIfd, BOOL bSwap)
  1232. {
  1233. DBG_FN("ReadIfd");
  1234. HRESULT hr = S_OK;
  1235. const int DIR_ENTRY_SIZE = 12;
  1236. pBuf += pIfd->Offset;
  1237. pIfd->Count = GetWord(pBuf, bSwap);
  1238. pIfd->pEntries = new DIR_ENTRY[pIfd->Count];
  1239. if (!pIfd->pEntries)
  1240. return E_OUTOFMEMORY;
  1241. pBuf += 2;
  1242. for (int count = 0; count < pIfd->Count; count++)
  1243. {
  1244. pIfd->pEntries[count].Tag = GetWord(pBuf, bSwap);
  1245. pIfd->pEntries[count].Type = GetWord(pBuf + 2, bSwap);
  1246. pIfd->pEntries[count].Count = GetDword(pBuf + 4, bSwap);
  1247. pIfd->pEntries[count].Offset = GetDword(pBuf + 8, bSwap);
  1248. pBuf += DIR_ENTRY_SIZE;
  1249. wiauDbgDump("ReadIfd", "Tag 0x%04x, type %2d offset/value 0x%08x",
  1250. pIfd->pEntries[count].Tag, pIfd->pEntries[count].Type, pIfd->pEntries[count].Offset);
  1251. }
  1252. pIfd->NextIfdOffset = GetDword(pBuf, bSwap);
  1253. return hr;
  1254. }
  1255. VOID FreeIfd(IFD *pIfd)
  1256. {
  1257. if (pIfd->pEntries)
  1258. delete []pIfd->pEntries;
  1259. pIfd->pEntries = NULL;
  1260. }
  1261. WORD ByteSwapWord(WORD w)
  1262. {
  1263. return (w >> 8) | (w << 8);
  1264. }
  1265. DWORD ByteSwapDword(DWORD dw)
  1266. {
  1267. return ByteSwapWord((WORD) (dw >> 16)) | (ByteSwapWord((WORD) (dw & 0xffff)) << 16);
  1268. }
  1269. WORD GetWord(BYTE *pBuf, BOOL bSwap)
  1270. {
  1271. WORD w = *((UNALIGNED WORD *) pBuf);
  1272. if (bSwap)
  1273. w = ByteSwapWord(w);
  1274. return w;
  1275. }
  1276. DWORD GetDword(BYTE *pBuf, BOOL bSwap)
  1277. {
  1278. DWORD dw = *((UNALIGNED DWORD *) pBuf);
  1279. if (bSwap)
  1280. dw = ByteSwapDword(dw);
  1281. return dw;
  1282. }
  1283. /*
  1284. //
  1285. // Set the default and valid values for a property
  1286. //
  1287. VOID
  1288. FakeCamera::SetValidValues(
  1289. INT index,
  1290. CWiaPropertyList *pPropertyList
  1291. )
  1292. {
  1293. HRESULT hr = S_OK;
  1294. ULONG ExposureModeList[] = {
  1295. EXPOSUREMODE_MANUAL,
  1296. EXPOSUREMODE_AUTO,
  1297. EXPOSUREMODE_APERTURE_PRIORITY,
  1298. EXPOSUREMODE_SHUTTER_PRIORITY,
  1299. EXPOSUREMODE_PROGRAM_CREATIVE,
  1300. EXPOSUREMODE_PROGRAM_ACTION,
  1301. EXPOSUREMODE_PORTRAIT
  1302. };
  1303. PROPID PropId = pPropertyList->GetPropId(index);
  1304. WIA_PROPERTY_INFO *pPropInfo = pPropertyList->GetWiaPropInfo(index);
  1305. //
  1306. // Based on the property ID, populate the valid values range or list information
  1307. //
  1308. switch (PropId)
  1309. {
  1310. case WIA_DPC_EXPOSURE_MODE:
  1311. pPropInfo->ValidVal.List.Nom = EXPOSUREMODE_MANUAL;
  1312. pPropInfo->ValidVal.List.cNumList = sizeof(ExposureModeList) / sizeof(ExposureModeList[0]);
  1313. pPropInfo->ValidVal.List.pList = (BYTE*) ExposureModeList;
  1314. break;
  1315. case WIA_DPC_EXPOSURE_COMP:
  1316. pPropInfo->ValidVal.Range.Nom = 0;
  1317. pPropInfo->ValidVal.Range.Min = -200;
  1318. pPropInfo->ValidVal.Range.Max = 200;
  1319. pPropInfo->ValidVal.Range.Inc = 50;
  1320. break;
  1321. default:
  1322. WIAS_LERROR(g_pIWiaLog,WIALOG_NO_RESOURCE_ID,("FakeCamera::SetValidValues, property 0x%08x not defined", PropId));
  1323. return;
  1324. }
  1325. return;
  1326. }
  1327. */
  1328. /**************************************************************************\
  1329. * DllEntryPoint
  1330. *
  1331. * Main library entry point. Receives DLL event notification from OS.
  1332. *
  1333. * We are not interested in thread attaches and detaches,
  1334. * so we disable thread notifications for performance reasons.
  1335. *
  1336. * Arguments:
  1337. *
  1338. * hinst -
  1339. * dwReason -
  1340. * lpReserved -
  1341. *
  1342. * Return Value:
  1343. *
  1344. * Returns TRUE to allow the DLL to load.
  1345. *
  1346. \**************************************************************************/
  1347. extern "C" __declspec( dllexport )
  1348. BOOL APIENTRY DllEntryPoint(
  1349. HINSTANCE hinst,
  1350. DWORD dwReason,
  1351. LPVOID lpReserved)
  1352. {
  1353. switch (dwReason) {
  1354. case DLL_PROCESS_ATTACH:
  1355. g_hInst = hinst;
  1356. DisableThreadLibraryCalls(hinst);
  1357. break;
  1358. case DLL_PROCESS_DETACH:
  1359. break;
  1360. }
  1361. return TRUE;
  1362. }
  1363. /**************************************************************************\
  1364. * DllCanUnloadNow
  1365. *
  1366. * Determines whether the DLL has any outstanding interfaces.
  1367. *
  1368. * Arguments:
  1369. *
  1370. * None
  1371. *
  1372. * Return Value:
  1373. *
  1374. * Returns S_OK if the DLL can unload, S_FALSE if it is not safe to unload.
  1375. *
  1376. \**************************************************************************/
  1377. extern "C" STDMETHODIMP DllCanUnloadNow(void)
  1378. {
  1379. return S_OK;
  1380. }