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.

2945 lines
81 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1998
  4. *
  5. * TITLE: WiaTrans.Cpp
  6. *
  7. * VERSION: 2.0
  8. *
  9. * AUTHOR: ReedB
  10. *
  11. * DATE: 7 Apr, 1998
  12. *
  13. * DESCRIPTION:
  14. * Implementation of IBandedTransfer interface for the WIA device class driver.
  15. *
  16. *******************************************************************************/
  17. #include "precomp.h"
  18. #include "stiexe.h"
  19. #include "wiamindr.h"
  20. #include "wiapsc.h"
  21. #include "helpers.h"
  22. #include "ienumwfi.h"
  23. #include "devmgr.h"
  24. //
  25. // Until transfers are re-written to use N buffers, we always use 2.
  26. //
  27. #define WIA_NUM_TRANS_BUFFERS 2
  28. /**************************************************************************\
  29. * DataThreadProc
  30. *
  31. * Use separate thread to call clients
  32. *
  33. * Arguments:
  34. *
  35. * pInfo - parameters for callback
  36. *
  37. * Return Value:
  38. *
  39. * Status
  40. *
  41. * History:
  42. *
  43. * 11/19/1998 Original Version
  44. *
  45. \**************************************************************************/
  46. DWORD WINAPI DataThreadProc(LPVOID lpParameter)
  47. {
  48. DBG_FN(::DataThreadProc);
  49. HRESULT hr;
  50. PWIA_DATA_THREAD_INFO pInfo = (PWIA_DATA_THREAD_INFO)lpParameter;
  51. hr = CoInitializeEx(0,COINIT_MULTITHREADED);
  52. if (FAILED(hr)) {
  53. DBG_ERR(("Thread callback, CoInitializeEx failed (0x%X)", hr));
  54. pInfo->hr = E_FAIL;
  55. return hr;
  56. }
  57. pInfo->hr = S_OK;
  58. do {
  59. //
  60. // wait for message from MiniDrvCallback to call client
  61. //
  62. DWORD dwRet = WaitForSingleObject(pInfo->hEventStart,INFINITE);
  63. //
  64. // check termination
  65. //
  66. if (pInfo->bTerminateThread) {
  67. break;
  68. }
  69. //
  70. // valid wait code
  71. //
  72. if (dwRet == WAIT_OBJECT_0) {
  73. //
  74. // 64bit fix. XP client code:
  75. // pInfo->hr = pInfo->pIDataCallback->BandedDataCallback(
  76. // pInfo->lReason,
  77. // pInfo->lStatus,
  78. // pInfo->lPercentComplete,
  79. // pInfo->lOffset,
  80. // pInfo->lLength,
  81. // pInfo->lClientAddress,
  82. // pInfo->lMarshalLength,
  83. // pInfo->pBuffer);
  84. //
  85. // We set ClientAddress to NULL to force COM marshalling.
  86. // That way we avoid using the shared memory window we
  87. // set up. It is the shared memory window that
  88. // messes things up for us, since only a 32bit value
  89. // was being used to store the shared buffer pointer
  90. // in the Client's address space.
  91. //
  92. pInfo->hr = pInfo->pIDataCallback->BandedDataCallback(
  93. pInfo->lReason,
  94. pInfo->lStatus,
  95. pInfo->lPercentComplete,
  96. pInfo->lOffset,
  97. pInfo->lLength,
  98. 0,
  99. pInfo->lMarshalLength,
  100. pInfo->pBuffer);
  101. if (FAILED(pInfo->hr)) {
  102. DBG_ERR(("DataThreadProc,BandedDataCallback failed (0x%X)", hr));
  103. }
  104. } else {
  105. DBG_ERR(("Thread callback, WiatForSingleObject failed"));
  106. pInfo->hr = E_FAIL;
  107. break;
  108. }
  109. SetEvent(pInfo->hEventComplete);
  110. } while (TRUE);
  111. CoUninitialize();
  112. return hr;
  113. }
  114. /*******************************************************************************
  115. *
  116. * QueryInterface
  117. * AddRef
  118. * Release
  119. * Constructor/Destructor
  120. * Initialize
  121. *
  122. * DESCRIPTION:
  123. * COM methods for CWiaMiniDrvCallBack. This class is used by itGetImage
  124. * to respond to mini driver callbacks during image transfers.
  125. *
  126. *******************************************************************************/
  127. HRESULT _stdcall CWiaMiniDrvCallBack::QueryInterface(const IID& iid, void** ppv)
  128. {
  129. *ppv = NULL;
  130. if (iid == IID_IUnknown || iid == IID_IWiaMiniDrvCallBack) {
  131. *ppv = (IWiaMiniDrvCallBack*) this;
  132. }
  133. else {
  134. return E_NOINTERFACE;
  135. }
  136. AddRef();
  137. return S_OK;
  138. }
  139. ULONG _stdcall CWiaMiniDrvCallBack::AddRef()
  140. {
  141. InterlockedIncrement((long*) &m_cRef);
  142. return m_cRef;
  143. }
  144. ULONG _stdcall CWiaMiniDrvCallBack::Release()
  145. {
  146. ULONG ulRefCount = m_cRef - 1;
  147. if (InterlockedDecrement((long*) &m_cRef) == 0) {
  148. delete this;
  149. return 0;
  150. }
  151. return ulRefCount;
  152. }
  153. /**************************************************************************\
  154. * CWiaMiniDrvCallBack::CWiaMiniDrvCallBack
  155. *
  156. * Setup data callback control and thread
  157. *
  158. * Arguments:
  159. *
  160. *
  161. *
  162. * Return Value:
  163. *
  164. * Status
  165. *
  166. * History:
  167. *
  168. * 4/9/1999 Original Version
  169. *
  170. \**************************************************************************/
  171. CWiaMiniDrvCallBack::CWiaMiniDrvCallBack()
  172. {
  173. m_cRef = 0;
  174. m_hThread = NULL;
  175. m_ThreadInfo.hEventStart = NULL;
  176. m_ThreadInfo.hEventComplete = NULL;
  177. };
  178. /**************************************************************************\
  179. * CWiaMiniDrvCallBack::~CWiaMiniDrvCallBack
  180. *
  181. * free callback thread and event
  182. *
  183. * Arguments:
  184. *
  185. *
  186. *
  187. * Return Value:
  188. *
  189. * Status
  190. *
  191. * History:
  192. *
  193. * 4/9/1999 Original Version
  194. *
  195. \**************************************************************************/
  196. CWiaMiniDrvCallBack::~CWiaMiniDrvCallBack()
  197. {
  198. DBG_FN(CWiaMiniDrvCallBack::~CWiaMiniDrvCallBack);
  199. //
  200. // terminate thread and delete event
  201. //
  202. if (m_ThreadInfo.hEventStart) {
  203. if (m_hThread) {
  204. m_ThreadInfo.bTerminateThread = TRUE;
  205. SetEvent(m_ThreadInfo.hEventStart);
  206. //
  207. // wait for thread to terminate
  208. //
  209. WaitForSingleObject(m_hThread,10000);
  210. CloseHandle(m_hThread);
  211. m_hThread = NULL;
  212. }
  213. CloseHandle(m_ThreadInfo.hEventStart);
  214. if (m_ThreadInfo.hEventComplete) {
  215. CloseHandle(m_ThreadInfo.hEventComplete);
  216. }
  217. //
  218. // force kill thread?
  219. //
  220. }
  221. }
  222. /**************************************************************************\
  223. * CWiaMiniDrvCallBack::Initialize
  224. *
  225. * Set up callback class
  226. *
  227. * Arguments:
  228. *
  229. * pmdtc - context information for this callback
  230. * pIUnknown - interface pointer back to client
  231. *
  232. * Return Value:
  233. *
  234. * Status
  235. *
  236. * History:
  237. *
  238. * 11/12/1998 Original Version
  239. *
  240. \**************************************************************************/
  241. HRESULT CWiaMiniDrvCallBack::Initialize(
  242. PMINIDRV_TRANSFER_CONTEXT pmdtc,
  243. IWiaDataCallback *pIWiaDataCallback)
  244. {
  245. DBG_FN(CWiaMiniDrvCallback::Initialize);
  246. ASSERT(pmdtc != NULL);
  247. if(pmdtc == NULL) {
  248. return E_INVALIDARG;
  249. }
  250. //
  251. // init callback params
  252. //
  253. m_mdtc = *pmdtc;
  254. //
  255. // create thread communications event, auto reset
  256. //
  257. // hEventStart is signaled when the MiniDrvCallback routine wishes the
  258. // thread to begin a new callback
  259. //
  260. // hEventComplete is signaled when thread is ready to accept another
  261. // callback
  262. //
  263. m_ThreadInfo.pIDataCallback = pIWiaDataCallback;
  264. m_ThreadInfo.hEventStart = CreateEvent(NULL,FALSE,FALSE,NULL);
  265. m_ThreadInfo.hEventComplete = CreateEvent(NULL,FALSE,TRUE,NULL);
  266. if ((m_ThreadInfo.hEventStart == NULL) || ((m_ThreadInfo.hEventComplete == NULL))) {
  267. DBG_ERR(("CWiaMiniDrvCallBack::Initialize, failed to create event"));
  268. return E_FAIL;
  269. }
  270. //
  271. // create callback thread
  272. //
  273. m_ThreadInfo.bTerminateThread = FALSE;
  274. m_hThread = CreateThread(NULL,0,DataThreadProc,&m_ThreadInfo,0,&m_dwThreadID);
  275. if (m_hThread == NULL) {
  276. DBG_ERR(("CWiaMiniDrvCallBack::Initialize, failed to create thread"));
  277. return E_FAIL;
  278. }
  279. //
  280. // init first thread return
  281. //
  282. m_ThreadInfo.hr = S_OK;
  283. return S_OK;
  284. }
  285. /**************************************************************************\
  286. * CWiaMiniDrvCallBack::MiniDrvCallback
  287. *
  288. * This callback is used by itGetImage to respond to mini driver callbacks
  289. * during image transfers.
  290. *
  291. * Arguments:
  292. *
  293. * lReason - message to application
  294. * lStatus - status flags
  295. * lPercentComplete - operation percent complete
  296. * lOffset - buffer offset for data operation
  297. * lLength - length of this buffer operation
  298. * pmdtc - pointer to the mini driver context.
  299. * lReserved - reserved
  300. *
  301. * Return Value:
  302. *
  303. * Status
  304. *
  305. * History:
  306. *
  307. * 11/12/1998 Original Version
  308. *
  309. \**************************************************************************/
  310. HRESULT _stdcall CWiaMiniDrvCallBack::MiniDrvCallback(
  311. LONG lReason,
  312. LONG lStatus,
  313. LONG lPercentComplete,
  314. LONG lOffset,
  315. LONG lLength,
  316. PMINIDRV_TRANSFER_CONTEXT pmdtc,
  317. LONG lReserved)
  318. {
  319. DBG_FN(CMiniDrvCallback::MiniDrvCallback);
  320. HRESULT hr = S_OK;
  321. //
  322. // verify driver hasn't changed active buffer
  323. //
  324. LONG ActiveBuffer = 0;
  325. PBYTE pBuffer = NULL;
  326. LONG lMarshalLength = 0;
  327. BOOL bOOBData = FALSE;
  328. //
  329. // If the application didn't provide a callback, then nothing left to do.
  330. //
  331. if (!m_ThreadInfo.pIDataCallback) {
  332. return S_OK;
  333. }
  334. if ((lReason == IT_MSG_DATA) ||
  335. (lReason == IT_MSG_DATA_HEADER) ||
  336. (lReason == IT_MSG_NEW_PAGE)) {
  337. if (!pmdtc) {
  338. DBG_ERR(("MiniDrvCallback::MiniDrvCallback, transfer context is NULL!"));
  339. return E_POINTER;
  340. }
  341. if (pmdtc == NULL) {
  342. DBG_ERR(("NULL Minidriver context handed to us by driver!"));
  343. return E_POINTER;
  344. }
  345. if (pmdtc->lActiveBuffer != m_mdtc.lActiveBuffer) {
  346. DBG_TRC(("MiniDrvCallback, Active Buffers have been changed. This OK if the driver meant to do this. Possible repurcussion will be exception thrown on proxy/stub if buffer or length is incorrect"));
  347. }
  348. if (pmdtc->pTransferBuffer != m_mdtc.pTransferBuffer) {
  349. DBG_TRC(("MiniDrvCallback, Transfer Buffers have been changed. This OK if the driver meant to do this. Possible repurcussion will be exception thrown on proxy/stub if buffer or length is incorrect"));
  350. }
  351. //
  352. // get currently active buffer from driver, use member function
  353. // for all other information
  354. //
  355. // for mapped case, no buffer to copy
  356. //
  357. // for remote case, must copy buffer
  358. //
  359. ActiveBuffer = pmdtc->lActiveBuffer;
  360. if (m_mdtc.lClientAddress == 0) {
  361. pBuffer = pmdtc->pTransferBuffer;
  362. lMarshalLength = lLength;
  363. }
  364. } else if ((lReason == IT_MSG_FILE_PREVIEW_DATA) ||
  365. (lReason == IT_MSG_FILE_PREVIEW_DATA_HEADER)) {
  366. //
  367. // This is an OOB Data message, so mark bOOBData as TRUE
  368. //
  369. bOOBData = TRUE;
  370. //
  371. // NOTE: OOBData is stored in the mini driver transfer context's
  372. // pBaseBuffer member. So, if pBaseBuffer is non-zero, then some
  373. // OOBData is being sent, so set pBuffer and the MarshalLength.
  374. //
  375. if (pmdtc->pBaseBuffer) {
  376. pBuffer = pmdtc->pBaseBuffer;
  377. lMarshalLength = lLength;
  378. }
  379. }
  380. //
  381. // Check whether we are using single or double buffering for
  382. // banded data callbacks
  383. //
  384. if ((m_mdtc.lNumBuffers == 1 && m_mdtc.bTransferDataCB) || bOOBData) {
  385. //
  386. // NOTE: this section is a hack to get around the fact that
  387. // the transfer was hard-coded to use double buffering. This hack
  388. // fixes the case when an App. specifies not to use double buffering.
  389. // This whole data transfer section should be re-written to handle
  390. // N buffers at some later stage.
  391. //
  392. //
  393. // 64bit fix. XP client code:
  394. // hr = m_ThreadInfo.pIDataCallback->BandedDataCallback(lReason,
  395. // lStatus,
  396. // lPercentComplete,
  397. // lOffset,
  398. // lLength,
  399. // m_mdtc.lClientAddress,
  400. // lMarshalLength,
  401. // pBuffer);
  402. //
  403. // We set ClientAddress to NULL to force COM marshalling.
  404. // That way we avoid using the shared memory window we
  405. // set up. It is the shared memory window that
  406. // messes things up for us, since only a 32bit value
  407. // was being used to store the shared buffer pointer
  408. // in the Client's address space.
  409. //
  410. hr = m_ThreadInfo.pIDataCallback->BandedDataCallback(
  411. lReason,
  412. lStatus,
  413. lPercentComplete,
  414. lOffset,
  415. lLength,
  416. 0,
  417. lMarshalLength,
  418. pBuffer);
  419. if(FAILED(hr)) {
  420. DBG_ERR(("MiniDrvCallback, BandedDataCallback returned 0x%lx", hr));
  421. }
  422. } else {
  423. //
  424. // wait for CB thread to be ready, check old status
  425. //
  426. DWORD dwRet = WaitForSingleObject(m_ThreadInfo.hEventComplete, 30000);
  427. if (dwRet == WAIT_TIMEOUT) {
  428. DBG_ERR(("MiniDrvCallback, callback timeout, cancel data transfer"));
  429. hr = S_FALSE;
  430. } else if (dwRet == WAIT_OBJECT_0) {
  431. hr = m_ThreadInfo.hr;
  432. } else {
  433. DBG_ERR(("MiniDrvCallback, error in callback wait, ret = 0x%lx",dwRet));
  434. hr = E_FAIL;
  435. }
  436. //
  437. // error messages
  438. //
  439. if (hr == S_FALSE) {
  440. DBG_WRN(("MiniDrvCallback, client canceled scan (0x%X)", hr));
  441. //
  442. // set the start event so that DataThreadProc will still be able to
  443. // send IT_MSG_TERMINATION etc. to client.
  444. //
  445. SetEvent(m_ThreadInfo.hEventStart);
  446. } else if (hr == S_OK) {
  447. //
  448. // If this is a IT_MSG_TERMINATION message, call it directly
  449. //
  450. if (lReason == IT_MSG_TERMINATION) {
  451. //
  452. // 64bit fix. XP client code:
  453. // hr = m_ThreadInfo.pIDataCallback->BandedDataCallback(lReason,
  454. // lStatus,
  455. // lPercentComplete,
  456. // lOffset,
  457. // lLength,
  458. // m_mdtc.lClientAddress,
  459. // lMarshalLength,
  460. // pBuffer);
  461. //
  462. // We set ClientAddress to NULL to force COM marshalling.
  463. // That way we avoid using the shared memory window we
  464. // set up. It is the shared memory window that
  465. // messes things up for us, since only a 32bit value
  466. // was being used to store the shared buffer pointer
  467. // in the Client's address space.
  468. //
  469. hr = m_ThreadInfo.pIDataCallback->BandedDataCallback(
  470. lReason,
  471. lStatus,
  472. lPercentComplete,
  473. lOffset,
  474. lLength,
  475. 0,
  476. lMarshalLength,
  477. pBuffer);
  478. } else {
  479. //
  480. // send new request to callback thread
  481. //
  482. m_ThreadInfo.lReason = lReason;
  483. m_ThreadInfo.lStatus = lStatus;
  484. m_ThreadInfo.lPercentComplete = lPercentComplete;
  485. m_ThreadInfo.lOffset = lOffset;
  486. m_ThreadInfo.lLength = lLength;
  487. //
  488. // if remote, client address is 0
  489. //
  490. if (m_mdtc.lClientAddress == 0) {
  491. m_ThreadInfo.lClientAddress = 0;
  492. } else {
  493. m_ThreadInfo.lClientAddress = m_mdtc.lClientAddress +
  494. m_mdtc.lActiveBuffer * m_mdtc.lBufferSize;
  495. }
  496. m_ThreadInfo.lMarshalLength = lMarshalLength;
  497. m_ThreadInfo.pBuffer = pBuffer;
  498. //
  499. // kick off callback thread
  500. //
  501. SetEvent(m_ThreadInfo.hEventStart);
  502. //
  503. // switch to next transfer buffers
  504. //
  505. if ((lReason == IT_MSG_DATA) ||
  506. (lReason == IT_MSG_DATA_HEADER) ||
  507. (lReason == IT_MSG_NEW_PAGE)) {
  508. //
  509. // use next buffer
  510. //
  511. pmdtc->lActiveBuffer++;
  512. if (pmdtc->lActiveBuffer >= m_mdtc.lNumBuffers) {
  513. pmdtc->lActiveBuffer = 0;
  514. }
  515. m_mdtc.lActiveBuffer = pmdtc->lActiveBuffer;
  516. //
  517. // calc new tran buffer
  518. //
  519. m_mdtc.pTransferBuffer = m_mdtc.pBaseBuffer +
  520. m_mdtc.lActiveBuffer * m_mdtc.lBufferSize;
  521. pmdtc->pTransferBuffer = m_mdtc.pTransferBuffer;
  522. }
  523. }
  524. }
  525. }
  526. return hr;
  527. }
  528. /**************************************************************************\
  529. * CWiaItem::idtGetBandedData
  530. *
  531. * Use shared memory window and data callbacks to transfer image to
  532. * client
  533. *
  534. * Arguments:
  535. *
  536. * pWiaDataTransInfo - sharded buffer information
  537. * pIWiaDataCallback - client callback interface
  538. *
  539. * Return Value:
  540. *
  541. * Status
  542. *
  543. * History:
  544. *
  545. * 11/6/1998 Original Version
  546. *
  547. \**************************************************************************/
  548. HRESULT _stdcall CWiaItem::idtGetBandedData(
  549. PWIA_DATA_TRANSFER_INFO pWiaDataTransInfo,
  550. IWiaDataCallback *pIWiaDataCallback)
  551. {
  552. DBG_FN(CWiaItem::idtGetBandedData);
  553. HRESULT hr;
  554. //
  555. // Check whether item properties have been initialized
  556. //
  557. if (!m_bInitialized) {
  558. hr = InitLazyProps();
  559. if (FAILED(hr)) {
  560. DBG_ERR(("CWiaItem::idtGetBandedData, InitLazyProps failed"));
  561. return hr;
  562. }
  563. }
  564. return CommonGetData(NULL, pWiaDataTransInfo, pIWiaDataCallback);
  565. }
  566. /**************************************************************************\
  567. * CWiaItem::idtGetData
  568. *
  569. * Uses normal IDATAOBJECT transfer mechanisms but provides callback
  570. * status for the transfer
  571. *
  572. * Arguments:
  573. *
  574. * pstm - data storage
  575. * pIWiaDataCallback - optional callback routine
  576. *
  577. * Return Value:
  578. *
  579. * Status
  580. *
  581. * History:
  582. *
  583. * 10/28/1998 Original Version
  584. *
  585. \**************************************************************************/
  586. HRESULT _stdcall CWiaItem::idtGetData(
  587. LPSTGMEDIUM pMedium,
  588. IWiaDataCallback *pIWiaDataCallback)
  589. {
  590. DBG_FN(CWiaItem::idtGetData);
  591. HRESULT hr;
  592. WIA_DATA_TRANSFER_INFO WiaDataTransInfo;
  593. memset(&WiaDataTransInfo, 0, sizeof(WiaDataTransInfo));
  594. //
  595. // Fill out the necessary transfer info. to be used for OOB Data.
  596. //
  597. WiaDataTransInfo.ulSize = sizeof(WiaDataTransInfo);
  598. WiaDataTransInfo.bDoubleBuffer = FALSE;
  599. WiaDataTransInfo.ulReserved3 = 1;
  600. //
  601. // Check whether item properties have been initialized
  602. //
  603. if (!m_bInitialized) {
  604. hr = InitLazyProps();
  605. if (FAILED(hr)) {
  606. DBG_ERR(("CWiaItem::idtGetData, InitLazyProps failed"));
  607. return hr;
  608. }
  609. }
  610. return CommonGetData(pMedium, &WiaDataTransInfo, pIWiaDataCallback);
  611. }
  612. /**************************************************************************\
  613. * CWiaItem::idtAllocateTransferBuffer
  614. *
  615. * Allocate a transfer buffer for the banded transfer methods.
  616. *
  617. * Arguments:
  618. *
  619. * pWiaDataTransInfo - buffer information
  620. *
  621. * Return Value:
  622. *
  623. * Status
  624. *
  625. * History:
  626. *
  627. * 11/12/1998 Original Version
  628. *
  629. \**************************************************************************/
  630. HRESULT _stdcall CWiaItem::idtAllocateTransferBuffer(
  631. PWIA_DATA_TRANSFER_INFO pWiaDataTransInfo)
  632. {
  633. DBG_FN(CWiaItem::idtAllocTransferBuffer);
  634. LONG lSize = m_dcbInfo.ulBufferSize; /*pWiaDataTransInfo->ulBufferSize;*/
  635. HANDLE hSection = (HANDLE)m_dcbInfo.pMappingHandle; /*pWiaDataTransInfo->ulSection;*/
  636. ULONG ulProcessID = m_dcbInfo.ulClientProcessId; /*pWiaDataTransInfo->ulReserved2;*/
  637. LONG lNumBuffers = pWiaDataTransInfo->ulReserved3;
  638. //
  639. // NOTE: This will be a problem in 64-bit!! We do this here because
  640. // padtc->ulReserved1 is packed into a MiniDrvTransferContext later, which
  641. // uses a 32-bit ULONG for the client address.
  642. //
  643. //
  644. // 64bit fix. XP client code:
  645. // pWiaDataTransInfo->ulReserved1 = m_dcbInfo.pTransferBuffer;
  646. //
  647. // We set this to NULL to force COM marshalling.
  648. // That way we avoid using the shared memory window we
  649. // set up. It is the shared memory window that
  650. // messes things up for us, since only a 32bit value
  651. // was being used to store the shared buffer pointer
  652. // in the Client's address space.
  653. //
  654. pWiaDataTransInfo->ulReserved1 = 0;
  655. //
  656. // Corresponding driver item must be valid.
  657. //
  658. HRESULT hr = ValidateWiaDrvItemAccess(m_pWiaDrvItem);
  659. if (FAILED(hr)) {
  660. DBG_ERR(("CWiaItem::idtAllocateTransferBuffer, ValidateWiaDrvItemAccess failed"));
  661. return hr;
  662. }
  663. //
  664. // exclusive access for entire transfer
  665. //
  666. //
  667. // if section is NULL, alloc buffer
  668. //
  669. if (hSection == 0) {
  670. m_pBandBuffer = (PBYTE)LocalAlloc(0,lSize);
  671. if (m_pBandBuffer == NULL) {
  672. DBG_ERR(("CWiaItem::idtAllocateTransferBuffer failed mem alloc"));
  673. return E_OUTOFMEMORY;
  674. }
  675. //
  676. // Use m_lBandBufferLength = lSize / lNumBuffers if we want
  677. // the ulBufferSize to be the entire size instead of the
  678. // chunk size.
  679. //
  680. m_lBandBufferLength = lSize / lNumBuffers;
  681. m_bMapSection = FALSE;
  682. return S_OK;
  683. }
  684. //
  685. // map client's section
  686. //
  687. HANDLE TokenHandle;
  688. //
  689. // Check for open token.
  690. //
  691. if (OpenThreadToken(GetCurrentThread(),
  692. TOKEN_READ,
  693. TRUE,
  694. &TokenHandle)) {
  695. DBG_ERR(("itAllocateTransferBuffer, Open token on entry, last error: %d", GetLastError()));
  696. CloseHandle(TokenHandle);
  697. }
  698. //
  699. // Do we need max sector size?
  700. //
  701. if (lSize > 0) {
  702. //
  703. // transfer buffer for this device must not already exist
  704. //
  705. if (m_hBandSection == NULL) {
  706. //
  707. // duplicate hSection handle
  708. //
  709. HANDLE hClientProcess = NULL;
  710. HANDLE hServerProcess = GetCurrentProcess();
  711. hClientProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, ulProcessID);
  712. if (hClientProcess) {
  713. BOOL bRet = DuplicateHandle(hClientProcess,
  714. hSection,
  715. hServerProcess,
  716. &m_hBandSection,
  717. 0,
  718. FALSE,
  719. DUPLICATE_SAME_ACCESS);
  720. CloseHandle(hClientProcess);
  721. if (m_hBandSection != NULL) {
  722. hr = S_OK;
  723. m_pBandBuffer = (PBYTE) MapViewOfFileEx(m_hBandSection,
  724. FILE_MAP_READ | FILE_MAP_WRITE,
  725. 0,
  726. 0,
  727. lSize,
  728. NULL);
  729. //
  730. // Use m_lBandBufferLength = lSize / lNumBuffers if we want
  731. // the ulBufferSize to be the entire size instead of the
  732. // chunk size.
  733. //
  734. m_lBandBufferLength = lSize / lNumBuffers;
  735. if (m_pBandBuffer == NULL) {
  736. DBG_ERR(("CWiaItem::itAllocateTransferBuffer, failed MapViewOfFileEx"));
  737. CloseHandle(m_hBandSection);
  738. m_hBandSection = NULL;
  739. hr = E_OUTOFMEMORY;
  740. } else {
  741. m_bMapSection = TRUE;
  742. }
  743. }
  744. else {
  745. DBG_ERR(("CWiaItem::itAllocateTransferBuffer, failed DuplicateHandle"));
  746. hr = E_OUTOFMEMORY;
  747. }
  748. }
  749. else {
  750. LONG lRet = GetLastError();
  751. DBG_ERR(("CWiaItem::itAllocateTransferBuffer, OpenProcess failed, GetLastError = 0x%X", lRet));
  752. hr = HRESULT_FROM_WIN32(lRet);
  753. }
  754. if (OpenThreadToken(GetCurrentThread(),
  755. TOKEN_READ,
  756. TRUE,
  757. &TokenHandle)) {
  758. DBG_ERR(("itAllocateTransferBufferEx, Open token after revert, last error: %d", GetLastError()));
  759. CloseHandle(TokenHandle);
  760. }
  761. }
  762. else {
  763. DBG_ERR(("CWiaItem::itAllocateTransferBuffer failed , buffer already allocated"));
  764. hr = E_INVALIDARG;
  765. }
  766. }
  767. else {
  768. hr = E_INVALIDARG;
  769. }
  770. return (hr);
  771. }
  772. /**************************************************************************\
  773. * CWiaItem::idtFreeTransferBufferEx
  774. *
  775. * Free a transfer buffer allocated by idtAllocateTransferBuffer.
  776. *
  777. * Arguments:
  778. *
  779. * None
  780. *
  781. * Return Value:
  782. *
  783. * Status
  784. *
  785. * History:
  786. *
  787. * 10/28/1998 Original Version
  788. *
  789. \**************************************************************************/
  790. HRESULT _stdcall CWiaItem::idtFreeTransferBufferEx(void)
  791. {
  792. DBG_FN(CWiaItem::idtFreeTransferBufferEx);
  793. if (m_pBandBuffer != NULL) {
  794. if (m_bMapSection) {
  795. UnmapViewOfFile(m_pBandBuffer);
  796. }
  797. else {
  798. LocalFree(m_pBandBuffer);
  799. }
  800. m_pBandBuffer = NULL;
  801. }
  802. if (m_hBandSection != NULL) {
  803. CloseHandle(m_hBandSection);
  804. m_hBandSection = NULL;
  805. }
  806. m_lBandBufferLength = 0;
  807. return S_OK;
  808. }
  809. /**************************************************************************\
  810. * CWiaItem::idtQueryGetData
  811. *
  812. * find out if the tymed/format pair is supported
  813. *
  814. * Arguments:
  815. *
  816. * pwfi - format and tymed info
  817. *
  818. * Return Value:
  819. *
  820. * Status
  821. *
  822. * History:
  823. *
  824. * 11/17/1998 Original Version
  825. *
  826. \**************************************************************************/
  827. HRESULT _stdcall CWiaItem::idtQueryGetData(WIA_FORMAT_INFO *pwfi)
  828. {
  829. DBG_FN(CWiaItem::idtQueryGetData);
  830. //
  831. // Do parameter validation
  832. //
  833. if (!pwfi) {
  834. DBG_ERR(("CWiaItem::idtQueryGetData, WIA_FORMAT_INFO arg is NULL!"));
  835. return E_INVALIDARG;
  836. }
  837. if (IsBadReadPtr(pwfi, sizeof(WIA_FORMAT_INFO))) {
  838. DBG_ERR(("CWiaItem::idtQueryGetData, WIA_FORMAT_INFO arg is a bad read pointer!"));
  839. return E_INVALIDARG;
  840. }
  841. //
  842. // Corresponding driver item must be valid.
  843. //
  844. HRESULT hr = ValidateWiaDrvItemAccess(m_pWiaDrvItem);
  845. if (FAILED(hr)) {
  846. return hr;
  847. }
  848. //
  849. // Check whether item properties have been initialized
  850. //
  851. if (!m_bInitialized) {
  852. hr = InitLazyProps();
  853. if (FAILED(hr)) {
  854. DBG_ERR(("CWiaItem::idtQueryGetData, InitLazyProps failed"));
  855. return hr;
  856. }
  857. }
  858. //
  859. // A tymed must be provided.
  860. //
  861. if (pwfi->lTymed == TYMED_NULL) {
  862. return DV_E_TYMED;
  863. }
  864. LONG lnumFormatInfo;
  865. WIA_FORMAT_INFO *pwfiDriver;
  866. //
  867. // Call the mini driver to see if this format is supported.
  868. //
  869. {
  870. LOCK_WIA_DEVICE _LWD(this, &hr);
  871. if(SUCCEEDED(hr)) {
  872. hr = m_pActiveDevice->m_DrvWrapper.WIA_drvGetWiaFormatInfo((BYTE*)this,
  873. 0,
  874. &lnumFormatInfo,
  875. &pwfiDriver,
  876. &m_lLastDevErrVal);
  877. }
  878. }
  879. if (SUCCEEDED(hr)) {
  880. //
  881. // Make sure we can read the array that was given to us.
  882. //
  883. if (IsBadReadPtr(pwfiDriver, sizeof(WIA_FORMAT_INFO) * lnumFormatInfo)) {
  884. DBG_ERR(("CWiaItem::idtQueryGetData, Bad pointer from driver (array of WIA_FORMAT_INFO)"));
  885. return E_FAIL;
  886. }
  887. //
  888. // Look for the requested Tymed/Format pair. Return S_OK if found.
  889. //
  890. for (LONG lIndex = 0; lIndex < lnumFormatInfo; lIndex++) {
  891. if ((IsEqualGUID(pwfiDriver[lIndex].guidFormatID, pwfi->guidFormatID)) &&
  892. (pwfiDriver[lIndex].lTymed == pwfi->lTymed)) {
  893. return S_OK;
  894. }
  895. }
  896. DBG_ERR(("CWiaItem::idtQueryGetData, Tymed and Format pair not supported"));
  897. hr = E_INVALIDARG;
  898. }
  899. return hr;
  900. }
  901. /**************************************************************************\
  902. * CWiaItem::idtEnumWIA_FORMAT_INFO
  903. *
  904. * Format enumeration for the banded transfer methods.
  905. *
  906. * Arguments:
  907. *
  908. * dwDir - Data transfer direction flag.
  909. * ppIEnum - Pointer to returned enumerator.
  910. *
  911. * Return Value:
  912. *
  913. * Status
  914. *
  915. * History:
  916. *
  917. * 11/17/1998 Original Version
  918. *
  919. \**************************************************************************/
  920. HRESULT _stdcall CWiaItem::idtEnumWIA_FORMAT_INFO(
  921. IEnumWIA_FORMAT_INFO **ppIEnum)
  922. {
  923. DBG_FN(CWiaItem::idtEnumWIA_FORMAT_INFO);
  924. HRESULT hr = E_FAIL;
  925. if (!ppIEnum)
  926. {
  927. return E_POINTER;
  928. }
  929. *ppIEnum = NULL;
  930. //
  931. // Check whether item properties have been initialized
  932. //
  933. if (!m_bInitialized) {
  934. hr = InitLazyProps();
  935. if (FAILED(hr)) {
  936. DBG_ERR(("CWiaItem::idtEnumWIA_FORMAT_INFO, InitLazyProps failed"));
  937. return hr;
  938. }
  939. }
  940. CEnumWiaFormatInfo *pIEnum;
  941. pIEnum = new CEnumWiaFormatInfo();
  942. if (pIEnum == NULL)
  943. {
  944. return E_OUTOFMEMORY;
  945. }
  946. hr = pIEnum->Initialize(this);
  947. if (SUCCEEDED(hr))
  948. {
  949. pIEnum->AddRef();
  950. *ppIEnum = pIEnum;
  951. }
  952. else
  953. {
  954. delete pIEnum;
  955. pIEnum = NULL;
  956. }
  957. return hr;
  958. }
  959. /**************************************************************************\
  960. * CWiaItem::idtGetExtendedTransferInfo
  961. *
  962. * Returns extended transfer information such as optimal buffer size for
  963. * the transfer, number of buffers server will use etc.
  964. *
  965. * Arguments:
  966. *
  967. * pExtendedTransferInfo - Pointer to a structure which will hold the
  968. * transfer info on return.
  969. *
  970. * Return Value:
  971. *
  972. * Status
  973. *
  974. * History:
  975. *
  976. * 01/23/2000 Original Version
  977. *
  978. \**************************************************************************/
  979. HRESULT CWiaItem::idtGetExtendedTransferInfo(
  980. PWIA_EXTENDED_TRANSFER_INFO pExtendedTransferInfo)
  981. {
  982. DBG_FN(CWiaItem::idtGetExtendedTransferInfo);
  983. HRESULT hr = S_OK;
  984. //
  985. // Clear the structure and set the size
  986. //
  987. memset(pExtendedTransferInfo, 0, sizeof(*pExtendedTransferInfo));
  988. pExtendedTransferInfo->ulSize = sizeof(*pExtendedTransferInfo);
  989. //
  990. // Set the number of buffers. This number is the number of buffers
  991. // that the server will use during callback data transfers. Each buffer
  992. // will be WIA_DATA_TRANSFER_INFO->ulBufferSize large specified in the
  993. // call to idtGetBandedData.
  994. //
  995. pExtendedTransferInfo->ulNumBuffers = WIA_NUM_TRANS_BUFFERS;
  996. //
  997. // Set the buffer size values. The assumption is that the
  998. // WIA_IPA_BUFFER_SIZE valid values will be set as follows:
  999. // min - will specify the minimum value for buffer size
  1000. // max - will specify the maxium buffer size
  1001. // nom - will specify the optimal buffer size
  1002. //
  1003. hr = GetBufferValues(this, pExtendedTransferInfo);
  1004. if (FAILED(hr)) {
  1005. DBG_ERR(("CWiaItem::idtGetExtendedTransferInfo, Failed to get buffer size information!"));
  1006. }
  1007. return hr;
  1008. }
  1009. /**************************************************************************\
  1010. * AllocBufferFile
  1011. *
  1012. * Open file for data transfer. If cbItemSize == 0, just create
  1013. * a file, don't memory map.
  1014. *
  1015. * Arguments:
  1016. *
  1017. * pstm - in/out stream
  1018. * cbItemSize - size of image, 0 means driver doesn't know size.
  1019. * phBuffer - file handle
  1020. * ppImage - buffer pointer
  1021. *
  1022. * Return Value:
  1023. *
  1024. * Status
  1025. *
  1026. * History:
  1027. *
  1028. * 4/6/1999 Original Version
  1029. *
  1030. \**************************************************************************/
  1031. HRESULT AllocBufferFile(
  1032. IN OUT STGMEDIUM* pstm,
  1033. IN LONG cbItemSize,
  1034. OUT HANDLE* phBuffer,
  1035. OUT BYTE** ppImage)
  1036. {
  1037. DBG_FN(::AllocBufferFile);
  1038. HRESULT hr = S_OK;
  1039. USES_CONVERSION;
  1040. *phBuffer = NULL;
  1041. *ppImage = NULL;
  1042. pstm->pUnkForRelease = NULL;
  1043. //
  1044. // NOTE: This file should already have been created on the proxy side.
  1045. // We only want to open it here. This is so the file is created
  1046. // with the client credentials, with the client as owner.
  1047. //
  1048. *phBuffer = CreateFile(W2T(pstm->lpszFileName),
  1049. GENERIC_READ | GENERIC_WRITE,
  1050. FILE_SHARE_WRITE,
  1051. NULL,
  1052. OPEN_EXISTING,
  1053. FILE_ATTRIBUTE_NORMAL | SECURITY_ANONYMOUS | SECURITY_SQOS_PRESENT,
  1054. NULL);
  1055. if (*phBuffer == INVALID_HANDLE_VALUE) {
  1056. LONG lRet = GetLastError();
  1057. DBG_ERR(("AllocBufferFile, CreateFile on %S failed, GetLastError = 0x%X",
  1058. pstm->lpszFileName,
  1059. lRet));
  1060. hr = HRESULT_FROM_WIN32(lRet);
  1061. }
  1062. else if (GetFileType(*phBuffer) != FILE_TYPE_DISK)
  1063. {
  1064. CloseHandle(*phBuffer);
  1065. *phBuffer = INVALID_HANDLE_VALUE;
  1066. DBG_ERR(("AllocBufferFile, WIA will only transfer to files of type FILE_TYPE_DISK"));
  1067. hr = E_INVALIDARG;
  1068. }
  1069. //
  1070. // If file size is 0, mini driver can't determine size yet. Just create
  1071. // file. If size is not 0, then memory map the file
  1072. //
  1073. if ((cbItemSize != 0) && SUCCEEDED(hr)) {
  1074. HANDLE hMapped = CreateFileMapping(*phBuffer,
  1075. NULL,
  1076. PAGE_READWRITE,
  1077. 0,
  1078. cbItemSize,
  1079. NULL);
  1080. if (hMapped) {
  1081. *ppImage = (PBYTE) MapViewOfFileEx(hMapped,
  1082. FILE_MAP_READ | FILE_MAP_WRITE,
  1083. 0,
  1084. 0,
  1085. cbItemSize,
  1086. NULL);
  1087. }
  1088. //
  1089. // hMapped is not needed any more in our code, so close the user mode
  1090. // handle. The Section will be destroyed when UnMapViewOfFileEx called.
  1091. //
  1092. CloseHandle(hMapped);
  1093. if (!ppImage) {
  1094. DBG_ERR(("AllocBufferFile, unable to map file, size: %d", cbItemSize));
  1095. CloseHandle(*phBuffer);
  1096. *phBuffer = INVALID_HANDLE_VALUE;
  1097. hr = E_OUTOFMEMORY;
  1098. }
  1099. }
  1100. if (FAILED(hr)) {
  1101. CoTaskMemFree(pstm->lpszFileName);
  1102. pstm->lpszFileName = NULL;
  1103. }
  1104. return hr;
  1105. }
  1106. /**************************************************************************\
  1107. * CloseBufferFile
  1108. *
  1109. * Close file/mapping. NOTE: Don't use tymed from STGMEDIUM!!!
  1110. *
  1111. * Arguments:
  1112. *
  1113. * tymed - media type - will be TYMED_FILE or TYMED_MULTIPAGE_FILE
  1114. * pstm - stream
  1115. * pBuffer - memory mapped buffer
  1116. * hImage - File Handle
  1117. * hrTransfer - Indicated whether data transfer is successful, if not,
  1118. * delete the temporary file when TYMED_FILE is used or
  1119. * memory buffer when tyme_hglobal is used.
  1120. *
  1121. * Return Value:
  1122. *
  1123. * Status
  1124. *
  1125. * History:
  1126. *
  1127. * 4/6/1999 Original Version
  1128. *
  1129. \**************************************************************************/
  1130. void CloseBufferFile(
  1131. LONG lTymed,
  1132. STGMEDIUM *pstm,
  1133. PBYTE pBuffer,
  1134. HANDLE hImage,
  1135. HRESULT hrTransfer)
  1136. {
  1137. DBG_FN(::CloseBufferFile);
  1138. if (pBuffer) {
  1139. UnmapViewOfFile(pBuffer);
  1140. }
  1141. if (hImage != INVALID_HANDLE_VALUE) {
  1142. CloseHandle(hImage);
  1143. }
  1144. if(lTymed == TYMED_MULTIPAGE_FILE) {
  1145. if(hrTransfer == WIA_ERROR_PAPER_JAM ||
  1146. hrTransfer == WIA_ERROR_PAPER_EMPTY ||
  1147. hrTransfer == WIA_ERROR_PAPER_PROBLEM)
  1148. {
  1149. // any of these are good reason not to delete the file
  1150. return ;
  1151. }
  1152. }
  1153. if (hrTransfer != S_OK) {
  1154. #ifdef UNICODE
  1155. DeleteFile(pstm->lpszFileName);
  1156. #else
  1157. char szFileName[MAX_PATH];
  1158. WideCharToMultiByte(CP_ACP,
  1159. 0,
  1160. pstm->lpszFileName,
  1161. -1,
  1162. szFileName,
  1163. sizeof(szFileName),
  1164. NULL,
  1165. NULL);
  1166. DeleteFile(szFileName);
  1167. #endif
  1168. }
  1169. }
  1170. /**************************************************************************\
  1171. * PrepCallback
  1172. *
  1173. * Prepares a callback for use during data transfer.
  1174. *
  1175. * Arguments:
  1176. *
  1177. * pIWiaDataCallback - optional callback routine
  1178. * pmdtc - pointer to mini driver data transfer context
  1179. * ppIcb - pointer to returned mini driver callback interface.
  1180. *
  1181. * Return Value:
  1182. *
  1183. * Status
  1184. *
  1185. * History:
  1186. *
  1187. * 10/28/1998 Original Version
  1188. *
  1189. \**************************************************************************/
  1190. HRESULT _stdcall PrepCallback(
  1191. IWiaDataCallback *pIWiaDataCallback,
  1192. PMINIDRV_TRANSFER_CONTEXT pmdtc,
  1193. IWiaMiniDrvCallBack **ppIcb)
  1194. {
  1195. DBG_FN(::PrepCallback);
  1196. *ppIcb = NULL;
  1197. pmdtc->pIWiaMiniDrvCallBack = NULL;
  1198. //
  1199. // Always create the callback object so drivers don't have to deal
  1200. // with NULLs
  1201. //
  1202. //if (pIWiaDataCallback) {
  1203. HRESULT hr;
  1204. CWiaMiniDrvCallBack *pCMiniDrvCB = new CWiaMiniDrvCallBack();
  1205. if (pCMiniDrvCB) {
  1206. hr = pCMiniDrvCB->Initialize(pmdtc, pIWiaDataCallback);
  1207. if (SUCCEEDED(hr)) {
  1208. hr = pCMiniDrvCB->QueryInterface(IID_IWiaMiniDrvCallBack,
  1209. (void **)ppIcb);
  1210. if (SUCCEEDED(hr)) {
  1211. pmdtc->pIWiaMiniDrvCallBack = *ppIcb;
  1212. }
  1213. else {
  1214. DBG_ERR(("PrepCallback, failed QI of pCMiniDrvCB"));
  1215. }
  1216. }
  1217. else {
  1218. delete pCMiniDrvCB;
  1219. }
  1220. }
  1221. else {
  1222. DBG_ERR(("PrepCallback, failed memory alloc of pCMiniDrvCB"));
  1223. hr = E_OUTOFMEMORY;
  1224. }
  1225. return hr;
  1226. //}
  1227. //else {
  1228. // return S_FALSE;
  1229. //}
  1230. }
  1231. /**************************************************************************\
  1232. * CWiaItem::GetData
  1233. *
  1234. * Handles TYMED_FILE specific portion of the data transfer.
  1235. *
  1236. * Arguments:
  1237. *
  1238. * lDataSize - size of image data, zero if mini driver doesn't know.
  1239. * pstm - data storage
  1240. * pIWiaDataCallback - optional callback routine
  1241. * pmdtc - pointer to mini driver data transfer context
  1242. *
  1243. * Return Value:
  1244. *
  1245. * Status
  1246. *
  1247. * History:
  1248. *
  1249. * 10/28/1998 Original Version
  1250. *
  1251. \**************************************************************************/
  1252. HRESULT _stdcall CWiaItem::GetData(
  1253. STGMEDIUM *pstm,
  1254. IWiaDataCallback *pIWiaDataCallback,
  1255. PMINIDRV_TRANSFER_CONTEXT pmdtc)
  1256. {
  1257. DBG_FN(CWiaItem::GetData);
  1258. if(pstm->tymed != TYMED_FILE && pstm->tymed != TYMED_MULTIPAGE_FILE) {
  1259. DBG_ERR(("Invalid tymed on storage medium passed to GetData() : %d", pstm->tymed));
  1260. return HRESULT_FROM_WIN32(E_INVALIDARG);
  1261. }
  1262. //
  1263. // Allocate file for transfer. If the mini driver knows the size,
  1264. // lDataSize != 0, the file will be memory mapped.
  1265. //
  1266. HANDLE hImage;
  1267. PBYTE pImage;
  1268. HRESULT hr = AllocBufferFile(pstm, pmdtc->lItemSize, &hImage, &pImage);
  1269. if (SUCCEEDED(hr)) {
  1270. //
  1271. // Fill in the mini driver transfer context.
  1272. //
  1273. if (pImage) {
  1274. pmdtc->lBufferSize = pmdtc->lItemSize;
  1275. pmdtc->pTransferBuffer = pImage;
  1276. pmdtc->pBaseBuffer = pImage;
  1277. }
  1278. pmdtc->hFile = (LONG_PTR)hImage;
  1279. pmdtc->lNumBuffers = 1;
  1280. pmdtc->bTransferDataCB = FALSE;
  1281. //
  1282. // Prepare the IWiaMiniDrvCallBack for status messages only.
  1283. // Mini driver can write to structure so save an interface
  1284. // ptr for release.
  1285. //
  1286. IWiaMiniDrvCallBack *pIcb;
  1287. hr = PrepCallback(pIWiaDataCallback, pmdtc, &pIcb);
  1288. if (SUCCEEDED(hr)) {
  1289. hr = SendOOBDataHeader(0, pmdtc);
  1290. if (SUCCEEDED(hr)) {
  1291. //
  1292. // Call the device mini driver to accquire the device item data.
  1293. //
  1294. hr = AcquireMiniDrvItemData(pmdtc);
  1295. } else {
  1296. DBG_ERR(("GetData, SendOOBDataHeader failed..."));
  1297. }
  1298. }
  1299. //
  1300. // Release the Mini Driver Callback, if any.
  1301. //
  1302. if (pIcb) {
  1303. //
  1304. // send the termination message
  1305. //
  1306. pIcb->MiniDrvCallback(IT_MSG_TERMINATION,
  1307. IT_STATUS_TRANSFER_TO_CLIENT,
  1308. 0,
  1309. 0,
  1310. 0,
  1311. pmdtc,
  1312. 0);
  1313. pIcb->Release();
  1314. }
  1315. CloseBufferFile(pmdtc->tymed, pstm, pImage, hImage, hr);
  1316. }
  1317. else {
  1318. hr = STG_E_MEDIUMFULL;
  1319. }
  1320. return hr;
  1321. }
  1322. /**************************************************************************\
  1323. * CWiaItem::GetDataBanded
  1324. *
  1325. * Handles TYMED_CALLBACK specific portion of the data transfer.
  1326. *
  1327. * Arguments:
  1328. *
  1329. * lDataSize - size of image data, zero if mini driver doesn't know.
  1330. * padtc - pointer to application data transfer context
  1331. * pIWiaDataCallback - callback routine
  1332. * pmdtc - pointer to mini driver data transfer context
  1333. *
  1334. * Return Value:
  1335. *
  1336. * Status
  1337. *
  1338. * History:
  1339. *
  1340. * 10/28/1998 Original Version
  1341. *
  1342. \**************************************************************************/
  1343. HRESULT _stdcall CWiaItem::GetDataBanded(
  1344. PWIA_DATA_TRANSFER_INFO padtc,
  1345. IWiaDataCallback *pIWiaDataCallback,
  1346. PMINIDRV_TRANSFER_CONTEXT pmdtc)
  1347. {
  1348. DBG_FN(::GetDataBanded);
  1349. HRESULT hr = E_FAIL;
  1350. //
  1351. // A callback must be supplied.
  1352. //
  1353. if (!pIWiaDataCallback) {
  1354. DBG_ERR(("GetDataBanded, NULL input pointers"));
  1355. return E_INVALIDARG;
  1356. }
  1357. //
  1358. // allocate transfer buffer
  1359. //
  1360. hr = idtAllocateTransferBuffer(padtc);
  1361. if (hr != S_OK) {
  1362. DBG_ERR(("GetDataBanded, idtAllocateTransferBuffer failed"));
  1363. return hr;
  1364. }
  1365. //
  1366. // Fill in the mini driver transfer context.
  1367. //
  1368. pmdtc->lBufferSize = m_lBandBufferLength;
  1369. pmdtc->lNumBuffers = padtc->ulReserved3;
  1370. pmdtc->pBaseBuffer = m_pBandBuffer;
  1371. pmdtc->pTransferBuffer = m_pBandBuffer;
  1372. //
  1373. // 64bit fix. XP client code:
  1374. // pmdtc->lClientAddress = padtc->ulReserved1;
  1375. //
  1376. // We set this to NULL to force COM marshalling.
  1377. // That way we avoid using the shared memory window we
  1378. // set up. It is the shared memory window that
  1379. // messes things up for us, since only a 32bit value
  1380. // was being used to store the shared buffer pointer
  1381. // in the Client's address space.
  1382. //
  1383. pmdtc->lClientAddress = NULL;
  1384. pmdtc->bTransferDataCB = TRUE;
  1385. //
  1386. // Setup the mini driver callback. Mini driver can write to
  1387. // structure so save an interface ptr for release.
  1388. //
  1389. IWiaMiniDrvCallBack *pIcb;
  1390. hr = PrepCallback(pIWiaDataCallback, pmdtc, &pIcb);
  1391. if (hr == S_OK) {
  1392. //
  1393. // transfer data header to client
  1394. //
  1395. hr = SendDataHeader(pmdtc->lItemSize, pmdtc);
  1396. //
  1397. // data transfer may have been canceled by client
  1398. //
  1399. if (hr == S_OK) {
  1400. //
  1401. // Call the device mini driver to accquire the device item data.
  1402. //
  1403. hr = AcquireMiniDrvItemData(pmdtc);
  1404. }
  1405. //
  1406. // terminate data transfer even if transfer is cancelled
  1407. //
  1408. pIcb->MiniDrvCallback(IT_MSG_TERMINATION,
  1409. IT_STATUS_TRANSFER_TO_CLIENT,
  1410. 0,
  1411. 0,
  1412. 0,
  1413. pmdtc,
  1414. 0);
  1415. //
  1416. // Release the call back.
  1417. //
  1418. pIcb->Release();
  1419. }
  1420. else {
  1421. DBG_ERR(("CWiaItem::GetDataBanded, PrepCallback failed"));
  1422. }
  1423. //
  1424. // free mapped transfer buffer
  1425. //
  1426. idtFreeTransferBufferEx();
  1427. return hr;
  1428. }
  1429. /**************************************************************************\
  1430. * CWiaItem::CommonGetData
  1431. *
  1432. * Helper function used by both idtGetData and idtGetBandedData.
  1433. *
  1434. * Arguments:
  1435. *
  1436. * pstm - data storage
  1437. * padtc - pointer to application data transfer context
  1438. * pIWiaDataCallback - optional callback routine
  1439. *
  1440. * Return Value:
  1441. *
  1442. * Status
  1443. *
  1444. * History:
  1445. *
  1446. * 10/28/1998 Original Version
  1447. *
  1448. \**************************************************************************/
  1449. HRESULT _stdcall CWiaItem::CommonGetData(
  1450. STGMEDIUM *pstm,
  1451. PWIA_DATA_TRANSFER_INFO padtc,
  1452. IWiaDataCallback *pIWiaDataCallback)
  1453. {
  1454. DBG_FN(CWiaItem::CommonGetData);
  1455. //
  1456. // Corresponding driver item must be valid to talk with hardware.
  1457. //
  1458. HRESULT hr = ValidateWiaDrvItemAccess(m_pWiaDrvItem);
  1459. if (FAILED(hr)) {
  1460. return hr;
  1461. }
  1462. //
  1463. // Data transfers are only allowed on items that are type Transfer.
  1464. // Fix: For now, look for either file or transfer.
  1465. //
  1466. LONG lFlags = 0;
  1467. GetItemType(&lFlags);
  1468. if (!((lFlags & WiaItemTypeTransfer) || (lFlags & WiaItemTypeFile))) {
  1469. DBG_ERR(("CWiaItem::CommonGetData, Item is not of File type"));
  1470. return E_INVALIDARG;
  1471. }
  1472. //
  1473. // Setup the minidriver transfer context. Fill in transfer context
  1474. // members which derive from item properties.
  1475. //
  1476. MINIDRV_TRANSFER_CONTEXT mdtc;
  1477. hr = InitMiniDrvContext(this, &mdtc);
  1478. if (FAILED(hr)) {
  1479. return hr;
  1480. }
  1481. //
  1482. // Verify the device supports the requested format/media type.
  1483. //
  1484. WIA_FORMAT_INFO wfi;
  1485. wfi.lTymed = mdtc.tymed;
  1486. wfi.guidFormatID = mdtc.guidFormatID;
  1487. hr = idtQueryGetData(&wfi);
  1488. if (hr != S_OK) {
  1489. DBG_ERR(("CWiaItem::CommonGetData, idtQueryGetData failed, format not supported"));
  1490. return hr;
  1491. }
  1492. //
  1493. // lock device
  1494. //
  1495. if(SUCCEEDED(hr)) {
  1496. LOCK_WIA_DEVICE _LWD(this, &hr);
  1497. if(SUCCEEDED(hr)) {
  1498. //
  1499. // Call the device mini driver to set the device item properties
  1500. // to the device some device may update mini driver context.
  1501. //
  1502. hr = SetMiniDrvItemProperties(&mdtc);
  1503. if (SUCCEEDED(hr)) {
  1504. if (pstm) {
  1505. //
  1506. // Do a file based transfer.
  1507. //
  1508. hr = GetData(pstm, pIWiaDataCallback, &mdtc);
  1509. }
  1510. else {
  1511. //
  1512. // Do a callback based transfer.
  1513. //
  1514. hr = GetDataBanded(padtc, pIWiaDataCallback, &mdtc);
  1515. }
  1516. }
  1517. }
  1518. }
  1519. return hr;
  1520. }
  1521. /**************************************************************************\
  1522. * CWiaItem::SendDataHeader
  1523. *
  1524. * call client with total transfer size
  1525. *
  1526. * Arguments:
  1527. *
  1528. * pmdtc - destination information
  1529. *
  1530. * Return Value:
  1531. *
  1532. * Status
  1533. *
  1534. * History:
  1535. *
  1536. * 11/6/1998 Original Version
  1537. *
  1538. \**************************************************************************/
  1539. HRESULT _stdcall CWiaItem::SendDataHeader(
  1540. LONG lDataSize,
  1541. MINIDRV_TRANSFER_CONTEXT *pmdtc)
  1542. {
  1543. DBG_FN(CWiaItem::SendDataHeader);
  1544. HRESULT hr = S_OK;
  1545. BYTE *pSavedPtr;
  1546. ASSERT(pmdtc != NULL);
  1547. ASSERT(pmdtc->tymed == TYMED_CALLBACK || pmdtc->tymed == TYMED_MULTIPAGE_CALLBACK);
  1548. ASSERT(pmdtc->pIWiaMiniDrvCallBack != NULL);
  1549. //
  1550. // All formats must first send a WIA_DATA_CALLBACK_HEADER
  1551. //
  1552. WIA_DATA_CALLBACK_HEADER wiaHeader;
  1553. wiaHeader.lSize = sizeof(WIA_DATA_CALLBACK_HEADER);
  1554. wiaHeader.guidFormatID = pmdtc->guidFormatID;
  1555. wiaHeader.lBufferSize = lDataSize;
  1556. wiaHeader.lPageCount = 0;
  1557. pSavedPtr = pmdtc->pTransferBuffer;
  1558. pmdtc->pTransferBuffer = (BYTE *) &wiaHeader;
  1559. //
  1560. // note: the data transfer cbOffset element is not changed by
  1561. // sending the data transfer header (pcbWritten not changed)
  1562. //
  1563. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_DATA_HEADER,
  1564. IT_STATUS_TRANSFER_TO_CLIENT,
  1565. 0,
  1566. 0,
  1567. wiaHeader.lSize,
  1568. pmdtc,
  1569. 0);
  1570. pmdtc->pTransferBuffer = pSavedPtr;
  1571. return hr;
  1572. }
  1573. HRESULT _stdcall CWiaItem::SendOOBDataHeader(
  1574. LONG lDataSize,
  1575. MINIDRV_TRANSFER_CONTEXT *pmdtc)
  1576. {
  1577. DBG_FN(CWiaItem::SendOOBDataHeader);
  1578. HRESULT hr = S_OK;
  1579. ASSERT(pmdtc != NULL);
  1580. ASSERT(pmdtc->tymed == TYMED_FILE || pmdtc->tymed == TYMED_MULTIPAGE_FILE);
  1581. if (pmdtc->pIWiaMiniDrvCallBack == NULL) {
  1582. return S_OK;
  1583. }
  1584. //
  1585. // All formats must first send a WIA_DATA_CALLBACK_HEADER
  1586. //
  1587. WIA_DATA_CALLBACK_HEADER wiaHeader;
  1588. wiaHeader.lSize = sizeof(WIA_DATA_CALLBACK_HEADER);
  1589. wiaHeader.guidFormatID = pmdtc->guidFormatID;
  1590. wiaHeader.lBufferSize = lDataSize;
  1591. wiaHeader.lPageCount = 0;
  1592. pmdtc->pBaseBuffer = (BYTE*)&wiaHeader;
  1593. //
  1594. // note: the data transfer cbOffset element is not changed by
  1595. // sending the data transfer header (pcbWritten not changed)
  1596. //
  1597. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_FILE_PREVIEW_DATA_HEADER,
  1598. IT_STATUS_TRANSFER_TO_CLIENT,
  1599. 0,
  1600. 0,
  1601. wiaHeader.lSize,
  1602. pmdtc,
  1603. 0);
  1604. if(FAILED(hr)) {
  1605. DBG_ERR(("CWiaItem::SendOOBDataHeader failed with %x", hr));
  1606. }
  1607. return hr;
  1608. }
  1609. /**************************************************************************\
  1610. * CWiaItem::SendEndOfPage
  1611. *
  1612. * Call client with total page count.
  1613. *
  1614. * Arguments:
  1615. *
  1616. * lPageCount - Zero based count of total pages.
  1617. * pmdtc - Pointer to mini driver transfer context.
  1618. *
  1619. * Return Value:
  1620. *
  1621. * Status
  1622. *
  1623. * History:
  1624. *
  1625. * 11/6/1998 Original Version
  1626. *
  1627. \**************************************************************************/
  1628. HRESULT _stdcall CWiaItem::SendEndOfPage(
  1629. LONG lPageCount,
  1630. MINIDRV_TRANSFER_CONTEXT *pmdtc)
  1631. {
  1632. DBG_FN(CWiaItem::SendEndOfPage);
  1633. HRESULT hr = S_OK;
  1634. PBYTE pSavedPtr;
  1635. ASSERT(pmdtc != NULL);
  1636. ASSERT(pmdtc->pIWiaMiniDrvCallBack != NULL);
  1637. //
  1638. // Set up the header for page count.
  1639. //
  1640. WIA_DATA_CALLBACK_HEADER wiaHeader;
  1641. wiaHeader.lSize = sizeof(WIA_DATA_CALLBACK_HEADER);
  1642. wiaHeader.guidFormatID = pmdtc->guidFormatID;
  1643. wiaHeader.lBufferSize = 0;
  1644. wiaHeader.lPageCount = lPageCount;
  1645. pSavedPtr = pmdtc->pTransferBuffer;
  1646. pmdtc->pTransferBuffer = (BYTE *) &wiaHeader;
  1647. //
  1648. // note: the data transfer cbOffset element is not changed by
  1649. // sending the data transfer header (pcbWritten not changed)
  1650. //
  1651. hr = pmdtc->pIWiaMiniDrvCallBack->MiniDrvCallback(IT_MSG_NEW_PAGE,
  1652. IT_STATUS_TRANSFER_TO_CLIENT,
  1653. 0,
  1654. 0,
  1655. wiaHeader.lSize,
  1656. pmdtc,
  1657. 0);
  1658. pmdtc->pTransferBuffer = pSavedPtr;
  1659. return hr;
  1660. }
  1661. /**************************************************************************\
  1662. * CWiaItem::AcquireMiniDrvItemData
  1663. *
  1664. * Call mini driver to capture item data.
  1665. *
  1666. * Arguments:
  1667. *
  1668. * pmdtc - transfer data context
  1669. *
  1670. * Return Value:
  1671. *
  1672. * Status
  1673. *
  1674. * History:
  1675. *
  1676. * 11/17/1998 Original Version
  1677. *
  1678. \**************************************************************************/
  1679. HRESULT _stdcall CWiaItem::AcquireMiniDrvItemData(
  1680. PMINIDRV_TRANSFER_CONTEXT pmdtc)
  1681. {
  1682. DBG_FN(CWiaItem::AcquireMiniDrvItemData);
  1683. //
  1684. // Set flag to indicate if class driver allocated the
  1685. // data transfer buffer or not.
  1686. //
  1687. if (pmdtc->pTransferBuffer) {
  1688. pmdtc->bClassDrvAllocBuf = TRUE;
  1689. }
  1690. else {
  1691. pmdtc->bClassDrvAllocBuf = FALSE;
  1692. }
  1693. HRESULT hr = S_OK;
  1694. LONG lFlags = 0;
  1695. InterlockedIncrement(&g_NumberOfActiveTransfers);
  1696. hr = m_pActiveDevice->m_DrvWrapper.WIA_drvAcquireItemData((BYTE*)this,
  1697. lFlags,
  1698. pmdtc,
  1699. &m_lLastDevErrVal);
  1700. InterlockedDecrement(&g_NumberOfActiveTransfers);
  1701. return hr;
  1702. }
  1703. /*******************************************************************************
  1704. *
  1705. * SetMiniDrvItemProperties
  1706. *
  1707. * DESCRIPTION:
  1708. * Call the device mini driver to set the device item properties to the device.
  1709. *
  1710. * PARAMETERS:
  1711. *
  1712. *******************************************************************************/
  1713. HRESULT _stdcall CWiaItem::SetMiniDrvItemProperties(
  1714. PMINIDRV_TRANSFER_CONTEXT pmdtc)
  1715. {
  1716. DBG_FN(CWiaItem::SetMiniDrvItemProperties);
  1717. HRESULT hr = S_OK;
  1718. LONG lFlags = 0;
  1719. InterlockedIncrement(&g_NumberOfActiveTransfers);
  1720. hr = m_pActiveDevice->m_DrvWrapper.WIA_drvWriteItemProperties((BYTE*)this,
  1721. lFlags,
  1722. pmdtc,
  1723. &m_lLastDevErrVal);
  1724. InterlockedDecrement(&g_NumberOfActiveTransfers);
  1725. return hr;
  1726. }
  1727. /**************************************************************************\
  1728. * CWiaItem::SetCallbackBufferInfo
  1729. *
  1730. *
  1731. * Arguments:
  1732. *
  1733. *
  1734. * Return Value:
  1735. *
  1736. * Status
  1737. *
  1738. * History:
  1739. *
  1740. * 07/21/2000 Original Version
  1741. *
  1742. \**************************************************************************/
  1743. HRESULT _stdcall CWiaItem::SetCallbackBufferInfo(WIA_DATA_CB_BUF_INFO DataCBBufInfo)
  1744. {
  1745. //
  1746. // Store the data callback information
  1747. //
  1748. m_dcbInfo.ulSize = DataCBBufInfo.ulSize;
  1749. m_dcbInfo.pMappingHandle = DataCBBufInfo.pMappingHandle;
  1750. m_dcbInfo.pTransferBuffer = DataCBBufInfo.pTransferBuffer;
  1751. m_dcbInfo.ulBufferSize = DataCBBufInfo.ulBufferSize;
  1752. m_dcbInfo.ulClientProcessId = DataCBBufInfo.ulClientProcessId;
  1753. return S_OK;
  1754. }
  1755. /**************************************************************************\
  1756. * CWiaItem::SetCallbackBufferInfo
  1757. *
  1758. *
  1759. * Arguments:
  1760. *
  1761. *
  1762. * Return Value:
  1763. *
  1764. * Status
  1765. *
  1766. * History:
  1767. *
  1768. * 07/21/2000 Original Version
  1769. *
  1770. \**************************************************************************/
  1771. HRESULT _stdcall CWiaItem::GetCallbackBufferInfo(WIA_DATA_CB_BUF_INFO *pDataCBBufInfo)
  1772. {
  1773. //
  1774. // Return the data callback information
  1775. //
  1776. if (IsBadWritePtr(pDataCBBufInfo, sizeof(WIA_DATA_CB_BUF_INFO))) {
  1777. DBG_ERR(("CWiaItem::GetCallbackBufferInfo, parameter is a bad write pointer"));
  1778. return E_INVALIDARG;
  1779. }
  1780. pDataCBBufInfo->ulSize = m_dcbInfo.ulSize;
  1781. pDataCBBufInfo->pMappingHandle = m_dcbInfo.pMappingHandle;
  1782. pDataCBBufInfo->pTransferBuffer = m_dcbInfo.pTransferBuffer;
  1783. pDataCBBufInfo->ulBufferSize = m_dcbInfo.ulBufferSize;
  1784. pDataCBBufInfo->ulClientProcessId = m_dcbInfo.ulClientProcessId;
  1785. return S_OK;
  1786. }
  1787. class CWiaRemoteTransfer : public IWiaMiniDrvCallBack
  1788. {
  1789. ULONG m_cRef;
  1790. LONG m_lMessage;
  1791. LONG m_lStatus;
  1792. LONG m_lPercentComplete;
  1793. LONG m_lOffset;
  1794. LONG m_lTransferOffset;
  1795. LONG m_lLength;
  1796. BYTE *m_pBuffer;
  1797. BOOL m_bTransferCancelled;
  1798. BOOL m_bDeviceLocked;
  1799. HRESULT m_savedHr;
  1800. HANDLE m_hThread;
  1801. HANDLE m_hMessagePickedUp;
  1802. HANDLE m_hMessageAvailable;
  1803. LONG m_MessageWaitTimeout;
  1804. public:
  1805. STGMEDIUM m_Medium;
  1806. WCHAR m_szTransferFile[MAX_PATH];
  1807. MINIDRV_TRANSFER_CONTEXT m_mdtc;
  1808. CWiaItem *m_pWiaItem;
  1809. CWiaRemoteTransfer() :
  1810. m_cRef(1),
  1811. m_pBuffer(0),
  1812. m_bTransferCancelled(FALSE),
  1813. m_bDeviceLocked(FALSE),
  1814. m_hThread(0),
  1815. m_savedHr(S_OK),
  1816. m_hMessagePickedUp(NULL),
  1817. m_hMessageAvailable(NULL),
  1818. m_MessageWaitTimeout(30000L)
  1819. {
  1820. ZeroMemory(&m_mdtc, sizeof(m_mdtc));
  1821. }
  1822. ~CWiaRemoteTransfer();
  1823. // IWiaMiniDrvCallback messages
  1824. HRESULT __stdcall QueryInterface(REFIID riid, LPVOID * ppv);
  1825. ULONG __stdcall AddRef()
  1826. {
  1827. return InterlockedIncrement((LPLONG)&m_cRef);
  1828. }
  1829. ULONG __stdcall Release();
  1830. HRESULT __stdcall MiniDrvCallback(
  1831. LONG lReason,
  1832. LONG lStatus,
  1833. LONG lPercentComplete,
  1834. LONG lOffset,
  1835. LONG lLength,
  1836. PMINIDRV_TRANSFER_CONTEXT pmdtc,
  1837. LONG lReserved);
  1838. HRESULT Init(CWiaItem *pItem, LPSTGMEDIUM pMedium);
  1839. HRESULT ThreadInit();
  1840. HRESULT GetWiaMessage(
  1841. ULONG nNumberOfBytesToRead,
  1842. ULONG *pNumberOfBytesRead,
  1843. BYTE *pBuffer,
  1844. LONG *pOffset,
  1845. LONG *pMessage,
  1846. LONG *pStatus,
  1847. LONG *pPercentComplete);
  1848. void SaveHR(HRESULT hr)
  1849. {
  1850. m_savedHr = hr;
  1851. }
  1852. void CancelTransfer()
  1853. {
  1854. m_bTransferCancelled = TRUE;
  1855. }
  1856. };
  1857. CWiaRemoteTransfer::~CWiaRemoteTransfer()
  1858. {
  1859. if(m_hMessagePickedUp) {
  1860. SetEvent(m_hMessagePickedUp);
  1861. }
  1862. if(m_hThread) {
  1863. WaitForSingleObject(m_hThread, INFINITE);
  1864. CloseHandle(m_hThread);
  1865. }
  1866. if(m_hMessagePickedUp) {
  1867. CloseHandle(m_hMessagePickedUp);
  1868. m_hMessagePickedUp = NULL;
  1869. }
  1870. if(m_hMessageAvailable) {
  1871. CloseHandle(m_hMessageAvailable);
  1872. m_hMessageAvailable = NULL;
  1873. }
  1874. HANDLE hFile = (HANDLE) m_mdtc.hFile;
  1875. if(hFile != INVALID_HANDLE_VALUE && hFile != NULL)
  1876. {
  1877. if(m_mdtc.pTransferBuffer) {
  1878. UnmapViewOfFile(m_mdtc.pTransferBuffer);
  1879. }
  1880. CloseHandle(hFile);
  1881. m_mdtc.hFile = NULL;
  1882. }
  1883. //
  1884. // If this was a Callback transfer and we allocated the buffer, we should
  1885. // free it now.
  1886. //
  1887. if((m_mdtc.bTransferDataCB == TRUE) && (m_mdtc.bClassDrvAllocBuf == TRUE))
  1888. {
  1889. if (m_mdtc.pBaseBuffer)
  1890. {
  1891. LocalFree(m_mdtc.pBaseBuffer);
  1892. m_mdtc.pBaseBuffer = NULL;
  1893. }
  1894. }
  1895. if(m_bDeviceLocked) {
  1896. UnLockWiaDevice(m_pWiaItem);
  1897. }
  1898. }
  1899. HRESULT __stdcall CWiaRemoteTransfer::QueryInterface(REFIID riid, LPVOID * ppv)
  1900. {
  1901. *ppv = NULL;
  1902. if (riid == IID_IUnknown || riid == IID_IWiaMiniDrvCallBack) {
  1903. *ppv = (IWiaMiniDrvCallBack*) this;
  1904. }
  1905. else {
  1906. return E_NOINTERFACE;
  1907. }
  1908. AddRef();
  1909. return S_OK;
  1910. }
  1911. ULONG __stdcall CWiaRemoteTransfer::Release()
  1912. {
  1913. ULONG lresult;
  1914. lresult = InterlockedDecrement((LPLONG)&m_cRef);
  1915. if(lresult == 0) {
  1916. delete this;
  1917. }
  1918. return lresult;
  1919. }
  1920. void _stdcall CleanupRemoteTransfer(CWiaRemoteTransfer *p)
  1921. {
  1922. p->CancelTransfer();
  1923. delete p;
  1924. }
  1925. DWORD WINAPI RemoteTransferDriverThread(LPVOID param)
  1926. {
  1927. HRESULT hr;
  1928. CWiaRemoteTransfer *pTransferObject = (CWiaRemoteTransfer *)param;
  1929. WIA_DATA_CALLBACK_HEADER Header;
  1930. LONG lFlags = 0;
  1931. LONG lDevErrVal = 0;
  1932. BYTE *pSavedPointer;
  1933. hr = CoInitializeEx(0,COINIT_MULTITHREADED);
  1934. if (FAILED(hr)) {
  1935. pTransferObject->SaveHR(hr);
  1936. DBG_ERR(("Thread callback, CoInitializeEx failed (0x%X)", hr));
  1937. goto Cleanup;
  1938. }
  1939. hr = pTransferObject->ThreadInit();
  1940. if(FAILED(hr)) {
  1941. pTransferObject->SaveHR(hr);
  1942. DBG_ERR(("Thread callback, ThreadInit() failed (0x%X)", hr));
  1943. goto Cleanup;
  1944. }
  1945. //
  1946. // For callback transfers, fill out WIA_DATA_CALLBACK_HEADER
  1947. // structure in the transfer buffer
  1948. // structure in the transfer buffer.
  1949. // For file transfers, send the OOB data header. CLients that
  1950. // dont understand OOB data will ignore it.
  1951. //
  1952. if(pTransferObject->m_mdtc.bTransferDataCB) {
  1953. Header.lSize = sizeof(Header);
  1954. Header.guidFormatID = pTransferObject->m_mdtc.guidFormatID;
  1955. Header.lBufferSize = pTransferObject->m_mdtc.lItemSize;
  1956. Header.lPageCount = 0;
  1957. //
  1958. // Save transfer buffer pointer and prepare to transfer our header
  1959. //
  1960. pSavedPointer = pTransferObject->m_mdtc.pTransferBuffer;
  1961. pTransferObject->m_mdtc.pTransferBuffer = (BYTE *)&Header;
  1962. //
  1963. // Let client app to pick up IT_MSG_DATA_HEADER
  1964. //
  1965. hr = pTransferObject->MiniDrvCallback(IT_MSG_DATA_HEADER,
  1966. IT_STATUS_TRANSFER_TO_CLIENT, 0, 0,
  1967. Header.lSize, &pTransferObject->m_mdtc, 0);
  1968. //
  1969. // Restore transfer buffer pointer
  1970. //
  1971. pTransferObject->m_mdtc.pTransferBuffer = pSavedPointer;
  1972. if(hr != S_OK) {
  1973. pTransferObject->SaveHR(hr);
  1974. DBG_ERR(("CWiaRemoteTransfer::Start() MinDrvCallback failed (0x%X)", hr));
  1975. goto Cleanup;
  1976. }
  1977. } else {
  1978. Header.lSize = sizeof(Header);
  1979. Header.guidFormatID = pTransferObject->m_mdtc.guidFormatID;
  1980. Header.lBufferSize = 0; // Force clients to allocate as needed since we don't know the size
  1981. Header.lPageCount = 0;
  1982. //
  1983. // Save transfer buffer pointer and prepare to transfer our header
  1984. //
  1985. pSavedPointer = pTransferObject->m_mdtc.pTransferBuffer;
  1986. pTransferObject->m_mdtc.pTransferBuffer = (BYTE *)&Header;
  1987. //
  1988. // Let client app to pick up IT_MSG_FILE_PREVIEW_DATA_HEADER
  1989. //
  1990. hr = pTransferObject->MiniDrvCallback(IT_MSG_FILE_PREVIEW_DATA_HEADER,
  1991. IT_STATUS_TRANSFER_TO_CLIENT, 0, 0,
  1992. Header.lSize, &pTransferObject->m_mdtc, 0);
  1993. //
  1994. // Restore transfer buffer pointer
  1995. //
  1996. pTransferObject->m_mdtc.pTransferBuffer = pSavedPointer;
  1997. if(hr != S_OK) {
  1998. pTransferObject->SaveHR(hr);
  1999. DBG_ERR(("CWiaRemoteTransfer::Start() MinDrvCallback failed (0x%X)", hr));
  2000. goto Cleanup;
  2001. }
  2002. }
  2003. InterlockedIncrement(&g_NumberOfActiveTransfers);
  2004. // Call into mini-driver and don't return until transfer is complete
  2005. hr = pTransferObject->m_pWiaItem->m_pActiveDevice->m_DrvWrapper.WIA_drvAcquireItemData(
  2006. (BYTE *) pTransferObject->m_pWiaItem,
  2007. lFlags, &pTransferObject->m_mdtc,
  2008. &lDevErrVal);
  2009. InterlockedDecrement(&g_NumberOfActiveTransfers);
  2010. if(FAILED(hr)) {
  2011. pTransferObject->SaveHR(hr);
  2012. DBG_ERR(("RemoteTransferDriverThread, drvAcquireItemData failed (Minidriver Error %d)", lDevErrVal));
  2013. }
  2014. Cleanup:
  2015. //
  2016. // Make sure IT_MSG_TERMINATION is send in any case
  2017. //
  2018. hr = pTransferObject->MiniDrvCallback(IT_MSG_TERMINATION,
  2019. IT_STATUS_TRANSFER_TO_CLIENT, 0, 0,
  2020. 0, &pTransferObject->m_mdtc, 0);
  2021. if(hr != S_OK) {
  2022. DBG_ERR(("RemoteTransferDriverThread MinDrvCallback failed (0x%X)", hr));
  2023. }
  2024. CoUninitialize();
  2025. return 0;
  2026. }
  2027. HRESULT CWiaRemoteTransfer::MiniDrvCallback(
  2028. LONG lReason,
  2029. LONG lStatus,
  2030. LONG lPercentComplete,
  2031. LONG lOffset,
  2032. LONG lLength,
  2033. PMINIDRV_TRANSFER_CONTEXT pmdtc,
  2034. LONG lReserved)
  2035. {
  2036. HRESULT hr = S_OK;
  2037. //
  2038. // Copy message content
  2039. //
  2040. m_lMessage = lReason;
  2041. m_lStatus = lStatus;
  2042. m_lPercentComplete = lPercentComplete;
  2043. m_lOffset = lOffset;
  2044. m_lTransferOffset = 0;
  2045. m_lLength = lLength;
  2046. // Make sure we reference the correct buffer. Out-of-band-data (or "File Preview" data)
  2047. // comes from the MiniDriver Transfer Context's pBaseBuffer pointer, while all other
  2048. // data comes from its pTransferBuffer.
  2049. if (pmdtc) {
  2050. if (m_lMessage == IT_MSG_FILE_PREVIEW_DATA) {
  2051. m_pBuffer = pmdtc->pBaseBuffer;
  2052. } else {
  2053. m_pBuffer = pmdtc->pTransferBuffer;
  2054. }
  2055. } else {
  2056. m_pBuffer = NULL;
  2057. }
  2058. //
  2059. // Let the incoming thread from remote app to pick up the message
  2060. //
  2061. SetEvent(m_hMessageAvailable);
  2062. //
  2063. // Wait until all the data message is picked up by app
  2064. //
  2065. if(WaitForSingleObject(m_hMessagePickedUp, m_MessageWaitTimeout) != WAIT_OBJECT_0) {
  2066. DBG_ERR(("CWiaRemoteTransfer::MiniDrvCallback timed out"));
  2067. // avoid long waits if message timed out once
  2068. m_MessageWaitTimeout = 1;
  2069. hr = S_FALSE;
  2070. }
  2071. ResetEvent(m_hMessagePickedUp);
  2072. if(m_bTransferCancelled) {
  2073. hr = S_FALSE;
  2074. }
  2075. return hr;
  2076. }
  2077. HRESULT CWiaRemoteTransfer::Init(CWiaItem *pItem, LPSTGMEDIUM pMedium)
  2078. {
  2079. HRESULT hr = S_OK;
  2080. DWORD dwThread;
  2081. m_pWiaItem = pItem;
  2082. m_Medium = *pMedium;
  2083. m_MessageWaitTimeout = 30000L;
  2084. if(pMedium->tymed == TYMED_FILE) {
  2085. m_Medium.lpszFileName = m_szTransferFile;
  2086. wcsncpy(m_szTransferFile, pMedium->lpszFileName, MAX_PATH - 1);
  2087. m_szTransferFile[MAX_PATH - 1] = 0;
  2088. }
  2089. //
  2090. // Create events. No messages are posted yet.
  2091. //
  2092. m_hMessageAvailable = CreateEvent(NULL, TRUE, FALSE, NULL);
  2093. m_hMessagePickedUp = CreateEvent(NULL, TRUE, FALSE, NULL);
  2094. if(!m_hMessageAvailable || !m_hMessagePickedUp) {
  2095. LONG lRet = GetLastError();
  2096. hr = HRESULT_FROM_WIN32(lRet);
  2097. DBG_ERR(("CWiaRemoteTransfer::Init, CreateEvent failed, GetLastError() = 0x%X", lRet));
  2098. goto Cleanup;
  2099. }
  2100. //
  2101. // Create driver thread
  2102. //
  2103. m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) RemoteTransferDriverThread, (LPVOID) this, 0, &dwThread);
  2104. if(!m_hThread) {
  2105. LONG lRet = GetLastError();
  2106. hr = HRESULT_FROM_WIN32(lRet);
  2107. DBG_ERR(("CWiaRemoteTransfer::Init, CreateThread failed, GetLastError() = 0x%X", lRet));
  2108. goto Cleanup;
  2109. }
  2110. Cleanup:
  2111. return hr;
  2112. }
  2113. HRESULT CWiaRemoteTransfer::ThreadInit()
  2114. {
  2115. HRESULT hr = S_OK;
  2116. WIA_EXTENDED_TRANSFER_INFO exti = { 0 };
  2117. DWORD dwWidthInBytes;
  2118. if(m_Medium.tymed == TYMED_FILE) {
  2119. m_mdtc.lBufferSize = 0;
  2120. HANDLE hImage;
  2121. PBYTE pImage;
  2122. hr = AllocBufferFile(&m_Medium, m_mdtc.lItemSize, &hImage, &pImage);
  2123. if (FAILED(hr)) {
  2124. DBG_ERR(("CWiaRemoteTransfer::ThreadInit, AllocateBufferFile failed, hr = 0x%X", hr));
  2125. goto Cleanup;
  2126. }
  2127. //
  2128. // Fill in the mini driver transfer context.
  2129. //
  2130. if (pImage) {
  2131. m_mdtc.lBufferSize = m_mdtc.lItemSize;
  2132. m_mdtc.pTransferBuffer = pImage;
  2133. m_mdtc.pBaseBuffer = pImage;
  2134. m_mdtc.bClassDrvAllocBuf = TRUE;
  2135. } else {
  2136. m_mdtc.bClassDrvAllocBuf = FALSE;
  2137. }
  2138. m_mdtc.hFile = (LONG_PTR)hImage;
  2139. m_mdtc.lNumBuffers = 1;
  2140. m_mdtc.bTransferDataCB = FALSE;
  2141. } else {
  2142. // callback case
  2143. hr = GetBufferValues(m_pWiaItem, &exti);
  2144. if(FAILED(hr)) {
  2145. DBG_ERR(("CWiaRemoteTransfer::ThreadInit, GetBufferValues() failed, hr = %X", hr));
  2146. goto Cleanup;
  2147. }
  2148. m_mdtc.lBufferSize = exti.ulMinBufferSize;
  2149. m_mdtc.lNumBuffers = 1;
  2150. if(m_mdtc.lBufferSize) {
  2151. m_mdtc.pBaseBuffer = (BYTE *) LocalAlloc(LPTR, m_mdtc.lBufferSize);
  2152. if(m_mdtc.pBaseBuffer == NULL) {
  2153. hr = E_OUTOFMEMORY;
  2154. DBG_ERR(("CWiaRemoteTransfer::ThreadInit, failed to allocate %ld bytes", m_mdtc.lBufferSize));
  2155. goto Cleanup;
  2156. }
  2157. m_mdtc.pTransferBuffer = m_mdtc.pBaseBuffer;
  2158. m_mdtc.bClassDrvAllocBuf = TRUE;
  2159. } else {
  2160. m_mdtc.bClassDrvAllocBuf = FALSE;
  2161. }
  2162. m_mdtc.lClientAddress = NULL;
  2163. m_mdtc.bTransferDataCB = TRUE;
  2164. }
  2165. hr = QueryInterface(IID_IWiaMiniDrvCallBack, (void **)&m_mdtc.pIWiaMiniDrvCallBack);
  2166. if(hr != S_OK) {
  2167. DBG_ERR(("CWiaRemoteTransfer::ThreadInit this::QI(IWiaMiniDrvCallback) failed (0x%X)", hr));
  2168. goto Cleanup;
  2169. }
  2170. hr = LockWiaDevice(m_pWiaItem);
  2171. if(FAILED(hr)) {
  2172. DBG_ERR(("CWiaRemoteTransfer::ThreadInit LockWiaDevice failed (0x%X)", hr));
  2173. goto Cleanup;
  2174. }
  2175. m_bDeviceLocked = TRUE;
  2176. //
  2177. // Call the device mini driver to set the device item properties
  2178. // to the device some other device may update mini driver context.
  2179. //
  2180. hr = m_pWiaItem->SetMiniDrvItemProperties(&m_mdtc);
  2181. if(FAILED(hr)) {
  2182. DBG_ERR(("CWiaRemoteTransfer::ThreadInit, SetMiniDrvItemProperties failed (0x%X)", hr));
  2183. goto Cleanup;
  2184. }
  2185. Cleanup:
  2186. return hr;
  2187. }
  2188. HRESULT CWiaRemoteTransfer::GetWiaMessage(
  2189. ULONG nNumberOfBytesToRead,
  2190. ULONG *pNumberOfBytesRead,
  2191. BYTE *pBuffer,
  2192. LONG *pOffset,
  2193. LONG *pMessage,
  2194. LONG *pStatus,
  2195. LONG *pPercentComplete)
  2196. {
  2197. HRESULT hr = S_OK;
  2198. //
  2199. // Wait until data is available
  2200. //
  2201. if(WaitForSingleObject(m_hMessageAvailable, INFINITE) != WAIT_OBJECT_0) {
  2202. DBG_ERR(("CWiaRemoteTransfer::GetMessage() timed out"));
  2203. hr = HRESULT_FROM_WIN32(GetLastError());
  2204. goto Cleanup;
  2205. }
  2206. //
  2207. // Copy message data to client space
  2208. //
  2209. *pMessage = m_lMessage;
  2210. *pStatus = m_lStatus;
  2211. *pPercentComplete = m_lPercentComplete;
  2212. *pOffset = m_lOffset + m_lTransferOffset;
  2213. //
  2214. // Copy data bytes
  2215. //
  2216. *pNumberOfBytesRead = min(nNumberOfBytesToRead, (ULONG)m_lLength);
  2217. if(*pNumberOfBytesRead) {
  2218. // adjust image size, if necessary
  2219. if(m_mdtc.lImageSize) {
  2220. *pPercentComplete = MulDiv(*pOffset + *pNumberOfBytesRead, 100, m_mdtc.lImageSize);
  2221. }
  2222. if(m_pBuffer && pBuffer) {
  2223. __try {
  2224. memcpy(pBuffer, m_pBuffer + m_lTransferOffset, *pNumberOfBytesRead);
  2225. m_lLength -= *pNumberOfBytesRead;
  2226. m_lTransferOffset += *pNumberOfBytesRead;
  2227. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2228. DBG_ERR(("CWiaRemoteTransfer::GetMessage caught exception copying data"));
  2229. }
  2230. }
  2231. }
  2232. //
  2233. // If this was a data message and some data still left,
  2234. // we need to keep entry open and don't release driver
  2235. //
  2236. if(m_lLength != 0 &&
  2237. (m_lMessage == IT_MSG_DATA || m_lMessage == IT_MSG_FILE_PREVIEW_DATA))
  2238. {
  2239. //
  2240. // keep hMessageAvailable set and hMessagePickedUp reset
  2241. // so repeat calls from app would work and
  2242. // the driver thread would be blocked
  2243. //
  2244. } else {
  2245. //
  2246. // It was not a data message or all data was consumed --
  2247. // prevent reentry and release the driver thread
  2248. //
  2249. ResetEvent(m_hMessageAvailable);
  2250. SetEvent(m_hMessagePickedUp);
  2251. }
  2252. hr = m_savedHr;
  2253. Cleanup:
  2254. return hr;
  2255. }
  2256. /**************************************************************************\
  2257. * CWiaItem::idtStartRemoteDataTransfer
  2258. *
  2259. *
  2260. *
  2261. * Arguments:
  2262. *
  2263. *
  2264. *
  2265. * Return Value:
  2266. *
  2267. * Status:
  2268. *
  2269. * History:
  2270. *
  2271. *
  2272. *
  2273. \**************************************************************************/
  2274. HRESULT _stdcall CWiaItem::idtStartRemoteDataTransfer(LPSTGMEDIUM pMedium)
  2275. {
  2276. HRESULT hr = S_OK;
  2277. LONG lFlags = 0;
  2278. LONG lDevErrVal = 0;
  2279. //
  2280. // Prepare remote transfer object
  2281. //
  2282. CWiaRemoteTransfer *pRemoteTransfer = new CWiaRemoteTransfer();
  2283. if(!pRemoteTransfer) {
  2284. hr = E_OUTOFMEMORY;
  2285. DBG_ERR(("CWiaItem::idtStartRemoteDataTransfer, new CWiaRemoteTransfer() failed"));
  2286. goto Cleanup;
  2287. }
  2288. //
  2289. // Acquire remote transfer lock
  2290. //
  2291. if(InterlockedCompareExchangePointer((PVOID *)&m_pRemoteTransfer, pRemoteTransfer, NULL) != NULL) {
  2292. hr = E_FAIL;
  2293. DBG_ERR(("CWiaItem::idtStartRemoteDataTransfer, transfer already in progress"));
  2294. goto Cleanup;
  2295. }
  2296. //
  2297. // Check whether item properties have been initialized
  2298. //
  2299. if(!m_bInitialized) {
  2300. hr = InitLazyProps();
  2301. if(hr != S_OK) {
  2302. DBG_ERR(("CWiaItem::idtStartRemoteDataTransfer, InitLazyProps() failed (0x%X)", hr));
  2303. goto Cleanup;
  2304. }
  2305. }
  2306. //
  2307. // Corresponding driver item must be valid to talk with hardware.
  2308. //
  2309. hr = ValidateWiaDrvItemAccess(m_pWiaDrvItem);
  2310. if (hr != S_OK) {
  2311. DBG_ERR(("CWiaItem::idtStartRemoteDataTransfer, ValidateWiaDrvItemAccess() failed (0x%X)", hr));
  2312. goto Cleanup;
  2313. }
  2314. //
  2315. // Data transfers are only allowed on items that are type Transfer.
  2316. // Fix: For now, look for either file or transfer.
  2317. //
  2318. GetItemType(&lFlags);
  2319. if (!(lFlags & WiaItemTypeTransfer) && !(lFlags & WiaItemTypeFile)) {
  2320. hr = E_INVALIDARG;
  2321. DBG_ERR(("CWiaItem::idtStartRemoteDataTransfer, Item is not of File type"));
  2322. goto Cleanup;
  2323. }
  2324. //
  2325. // Setup the minidriver transfer context. Fill in transfer context
  2326. // members which derive from item properties.
  2327. //
  2328. hr = InitMiniDrvContext(this, &pRemoteTransfer->m_mdtc);
  2329. if (FAILED(hr)) {
  2330. DBG_ERR(("CWiaItem::idtStartRemoteDataTransfer, InitMiniDrvContext() failed (0x%X)", hr));
  2331. goto Cleanup;
  2332. }
  2333. //
  2334. // Verify the device supports the requested format/media type.
  2335. //
  2336. WIA_FORMAT_INFO wfi;
  2337. wfi.lTymed = pRemoteTransfer->m_mdtc.tymed;
  2338. wfi.guidFormatID = pRemoteTransfer->m_mdtc.guidFormatID;
  2339. hr = idtQueryGetData(&wfi);
  2340. if (hr != S_OK) {
  2341. DBG_ERR(("CWiaItem::idtStartRemoteDataTransfer, idtQueryGetData failed, format not supported (0x%X)", hr));
  2342. goto Cleanup;
  2343. }
  2344. //
  2345. // Initiate transfer, wait for it to start or fail
  2346. //
  2347. hr = m_pRemoteTransfer->Init(this, pMedium);
  2348. if(hr != S_OK) {
  2349. DBG_ERR(("CWiaItem::idtStartRemoteDataTransfer, CWiaRemoteTransfer::Start() failed (0x%X)", hr));
  2350. goto Cleanup;
  2351. }
  2352. Cleanup:
  2353. if(hr != S_OK && pRemoteTransfer) {
  2354. //
  2355. // If we managed to acquire transfer lock, release it
  2356. //
  2357. InterlockedCompareExchangePointer((PVOID *)&m_pRemoteTransfer, NULL, pRemoteTransfer);
  2358. delete pRemoteTransfer;
  2359. }
  2360. return hr;
  2361. }
  2362. /**************************************************************************\
  2363. * CWiaItem::idtStopRemoteDataTransfer
  2364. *
  2365. *
  2366. *
  2367. * Arguments:
  2368. *
  2369. *
  2370. *
  2371. * Return Value:
  2372. *
  2373. * Status:
  2374. *
  2375. * History:
  2376. *
  2377. *
  2378. *
  2379. \**************************************************************************/
  2380. HRESULT _stdcall CWiaItem::idtStopRemoteDataTransfer()
  2381. {
  2382. HRESULT hr = S_OK;
  2383. //
  2384. // we are garanteed to have device lock at this point
  2385. // (we are here only if idtStartRemoteTransfer succeded)
  2386. //
  2387. CWiaRemoteTransfer *pTransfer =
  2388. (CWiaRemoteTransfer *)InterlockedExchangePointer((PVOID *)&m_pRemoteTransfer, NULL);
  2389. delete pTransfer;
  2390. return hr;
  2391. }
  2392. HRESULT _stdcall CWiaItem::idtCancelRemoteDataTransfer()
  2393. {
  2394. HRESULT hr = S_OK;
  2395. m_pRemoteTransfer->CancelTransfer();
  2396. return hr;
  2397. }
  2398. /**************************************************************************\
  2399. * CWiaItem::idtRemoteDataTransfer
  2400. *
  2401. *
  2402. *
  2403. * Arguments:
  2404. *
  2405. *
  2406. *
  2407. * Return Value:
  2408. *
  2409. * Status:
  2410. *
  2411. * History:
  2412. *
  2413. *
  2414. *
  2415. \**************************************************************************/
  2416. HRESULT _stdcall CWiaItem::idtRemoteDataTransfer(
  2417. ULONG nNumberOfBytesToRead,
  2418. ULONG *pNumberOfBytesRead,
  2419. BYTE *pBuffer,
  2420. LONG *pOffset,
  2421. LONG *pMessage,
  2422. LONG *pStatus,
  2423. LONG *pPercentComplete)
  2424. {
  2425. //
  2426. // Let the remote transfer object wait until the message is ready and
  2427. // return the message
  2428. //
  2429. return m_pRemoteTransfer->GetWiaMessage(nNumberOfBytesToRead, pNumberOfBytesRead,
  2430. pBuffer, pOffset, pMessage, pStatus, pPercentComplete);
  2431. }