Source code of Windows XP (NT5)
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.

2271 lines
57 KiB

  1. /*****************************************************************************
  2. *
  3. * Device.c
  4. *
  5. * Copyright (C) Microsoft Corporation, 1996 - 2000 All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * The standard implementation of IStiDevice.
  10. *
  11. * Contents:
  12. *
  13. * CStiDevice_New
  14. *
  15. *****************************************************************************/
  16. /*
  17. #include <windows.h>
  18. #include <windowsx.h>
  19. #include <objbase.h>
  20. #include <regstr.h>
  21. #include <setupapi.h>
  22. #include <cfgmgr32.h>
  23. #include <devguid.h>
  24. #include <stdio.h>
  25. #include <stilog.h>
  26. #include <stiregi.h>
  27. #include <sti.h>
  28. #include <stierr.h>
  29. #include <stiusd.h>
  30. #include "stipriv.h"
  31. #include "stiapi.h"
  32. #include "stirc.h"
  33. #include "debug.h"
  34. */
  35. #define INITGUID
  36. #include "initguid.h"
  37. #include "sti.h"
  38. #include "stiusd.h"
  39. #include "sticomm.h"
  40. #include "enum.h"
  41. //#define COBJMACROS
  42. //
  43. // Using CreateInstance
  44. //
  45. // #define USE_REAL_OLE32 1
  46. //
  47. // Private define
  48. //
  49. #define DbgFl DbgFlDevice
  50. /*****************************************************************************
  51. *
  52. * Declare the interfaces we will be providing.
  53. *
  54. *****************************************************************************/
  55. Primary_Interface(CStiDevice, IStiDevice);
  56. Interface_Template_Begin(CStiDevice)
  57. Primary_Interface_Template(CStiDevice, IStiDevice)
  58. Interface_Template_End(CStiDevice)
  59. /*****************************************************************************
  60. *
  61. * @doc INTERNAL
  62. *
  63. * @struct CStiDevice |
  64. *
  65. * The <i CStiDevice> device object
  66. *
  67. *
  68. * @field IStiDevice | stidev |
  69. *
  70. * Device interface
  71. *
  72. * @comm
  73. *
  74. *
  75. *****************************************************************************/
  76. typedef struct CStiDevice {
  77. /* Supported interfaces */
  78. IStiDevice stidev;
  79. DWORD dwVersion;
  80. RD(LONG cCrit;)
  81. D(DWORD thidCrit;)
  82. BOOL fCritInited;
  83. CRITICAL_SECTION crst;
  84. BOOL fLocked;
  85. HANDLE hNotify;
  86. PSTIDEVICECONTROL pDevCtl;
  87. IStiUSD *pUsd;
  88. LPUNKNOWN punkUsd;
  89. HKEY hkeyDeviceParameters;
  90. STI_USD_CAPS sUsdCaps;
  91. LPWSTR pszDeviceInternalName;
  92. HANDLE hDeviceStiHandle;
  93. HINSTANCE hUsdInstance;
  94. BOOL fCreateForMonitor;
  95. } CStiDevice, *PCStiDevice;
  96. #define ThisClass CStiDevice
  97. #define ThisInterface IStiDevice
  98. STDMETHODIMP
  99. LockDeviceHelper(
  100. PCStiDevice pThisDevice,
  101. DWORD dwTimeOut);
  102. STDMETHODIMP
  103. UnLockDeviceHelper(
  104. PCStiDevice pThisDevice);
  105. /*****************************************************************************
  106. *
  107. * @doc EXTERNAL
  108. *
  109. * @method HRESULT | IStiDevice | QueryInterface |
  110. *
  111. * Gives a client access to other interfaces on an object.
  112. *
  113. * @cwrap LPStiDevice | lpStiDevice
  114. *
  115. * @parm IN REFIID | riid |
  116. *
  117. * The requested interface's IID.
  118. *
  119. * @parm OUT LPVOID * | ppvObj |
  120. *
  121. * Receives a pointer to the obtained interface.
  122. *
  123. * @returns
  124. *
  125. * Returns a COM error code.
  126. *
  127. * @xref OLE documentation for <mf IUnknown::QueryInterface>.
  128. *
  129. *****************************************************************************
  130. *
  131. * @doc EXTERNAL
  132. *
  133. * @method HRESULT | IStiDevice | AddRef |
  134. *
  135. * Increments the reference count for the interface.
  136. *
  137. * @cwrap LPStiDevice | lpStiDevice
  138. *
  139. * @returns
  140. *
  141. * Returns the object reference count.
  142. *
  143. * @xref OLE documentation for <mf IUnknown::AddRef>.
  144. *
  145. *****************************************************************************
  146. *
  147. * @doc EXTERNAL
  148. *
  149. * @method HRESULT | IStiDevice | Release |
  150. *
  151. * Decrements the reference count for the interface.
  152. * If the reference count on the object falls to zero,
  153. * the object is freed from memory.
  154. *
  155. * @cwrap LPStiDevice | lpStiDevice
  156. *
  157. * @returns
  158. *
  159. * Returns the object reference count.
  160. *
  161. * @xref OLE documentation for <mf IUnknown::Release>.
  162. *
  163. *****************************************************************************
  164. *
  165. * @doc INTERNAL
  166. *
  167. * @method HRESULT | IStiDevice | QIHelper |
  168. *
  169. * We don't have any dynamic interfaces and simply forward
  170. * to <f Common_QIHelper>.
  171. *
  172. * @parm IN REFIID | riid |
  173. *
  174. * The requested interface's IID.
  175. *
  176. * @parm OUT LPVOID * | ppvObj |
  177. *
  178. * Receives a pointer to the obtained interface.
  179. *
  180. *****************************************************************************
  181. */
  182. #ifdef DEBUG
  183. //Default_QueryInterface(CStiDevice)
  184. Default_AddRef(CStiDevice)
  185. Default_Release(CStiDevice)
  186. #else
  187. //#define CStiDevice_QueryInterface Common_QueryInterface
  188. #define CStiDevice_AddRef Common_AddRef
  189. #define CStiDevice_Release Common_Release
  190. #endif
  191. #define CStiDevice_QIHelper Common_QIHelper
  192. #pragma BEGIN_CONST_DATA
  193. #pragma END_CONST_DATA
  194. /*****************************************************************************
  195. *
  196. * @doc INTERNAL
  197. *
  198. * @method void | IStiDevice | EnterCrit |
  199. *
  200. * Enter the object critical section.
  201. *
  202. * @cwrap LPStiDevice | lpStiDevice
  203. *
  204. *****************************************************************************/
  205. void EXTERNAL
  206. CStiDevice_EnterCrit(PCStiDevice this)
  207. {
  208. EnterCriticalSection(&this->crst);
  209. D(this->thidCrit = GetCurrentThreadId());
  210. RD(InterlockedIncrement(&this->cCrit));
  211. }
  212. /*****************************************************************************
  213. *
  214. * @doc INTERNAL
  215. *
  216. * @method void | IStiDevice | LeaveCrit |
  217. *
  218. * Leave the object critical section.
  219. *
  220. * @cwrap LPStiDevice | lpStiDevice
  221. *
  222. *****************************************************************************/
  223. void EXTERNAL
  224. CStiDevice_LeaveCrit(PCStiDevice this)
  225. {
  226. #ifdef MAXDEBUG
  227. AssertF(this->cCrit);
  228. AssertF(this->thidCrit == GetCurrentThreadId());
  229. if (InterlockedDecrement(&this->cCrit) == 0) {
  230. D(this->thidCrit = 0);
  231. }
  232. #endif
  233. LeaveCriticalSection(&this->crst);
  234. }
  235. /*****************************************************************************
  236. *
  237. * Verify device is locked
  238. *
  239. *****************************************************************************
  240. */
  241. BOOL
  242. CStiDevice_IsLocked(PCStiDevice this)
  243. {
  244. BOOL fRet ;
  245. CStiDevice_EnterCrit(this);
  246. fRet = this->fLocked;
  247. CStiDevice_LeaveCrit(this);
  248. return fRet;
  249. }
  250. void
  251. CStiDevice_MarkLocked(PCStiDevice this,BOOL fNewState)
  252. {
  253. CStiDevice_EnterCrit(this);
  254. this->fLocked = fNewState;
  255. CStiDevice_LeaveCrit(this);
  256. }
  257. /*****************************************************************************
  258. *
  259. * @doc INTERNAL
  260. *
  261. * @method void | IStiDevice | NotifyEvent |
  262. *
  263. * Set the event associated with the device, if any.
  264. *
  265. * @cwrap LPStiDevice | lpStiDevice
  266. *
  267. *****************************************************************************/
  268. void EXTERNAL
  269. CStiDevice_NotifyEvent(PCStiDevice this)
  270. {
  271. if (this->hNotify) {
  272. SetEvent(this->hNotify);
  273. }
  274. }
  275. /*****************************************************************************
  276. *
  277. * @doc INTERNAL
  278. *
  279. * @method void | CStiDevice | LoadInitUSD |
  280. *
  281. *
  282. * @cwrap LPStiDevice | lpStiDevice
  283. *
  284. *****************************************************************************/
  285. STDMETHODIMP
  286. LoadInitUSD(
  287. CStiDevice *this,
  288. HKEY hkeyDeviceParameters
  289. )
  290. {
  291. HRESULT hres = STI_OK;
  292. IStiUSD *pNewUsd = NULL;
  293. BOOL fExternalUSD = FALSE;
  294. LPWSTR pwszCLSID = NULL;
  295. LPUNKNOWN this_punk;
  296. //
  297. // Load and initialize command translator (USD)
  298. //
  299. // We always create USD object as aggregated, so first we get Unknown
  300. // pointer and then query it for needed interfaces
  301. //
  302. this->punkUsd = NULL;
  303. IStiDevice_QueryInterface(&this->stidev,&IID_IUnknown,&this_punk);
  304. StiLogTrace(STI_TRACE_INFORMATION,MSG_LOADING_USD);
  305. //
  306. // First read CLSID for USD from the device registry key
  307. //
  308. pwszCLSID = NULL;
  309. hres = ReadRegistryString(hkeyDeviceParameters,
  310. REGSTR_VAL_USD_CLASS_W,
  311. L"",FALSE,&pwszCLSID);
  312. if (SUCCEEDED(hres) && *pwszCLSID) {
  313. if (DllInitializeCOM()) {
  314. #ifdef USE_REAL_OLE32
  315. CLSID clsidUSD;
  316. hres = CLSIDFromString(pwszCLSID,&clsidUSD);
  317. if (SUCCEEDED(hres)) {
  318. hres = CoCreateInstance(&clsidUSD,this_punk,CLSCTX_INPROC,&IID_IUnknown,&this->punkUsd);
  319. }
  320. #else
  321. CHAR *pszAnsi;
  322. if (SUCCEEDED(OSUtil_GetAnsiString(&pszAnsi,pwszCLSID)) ) {
  323. hres = MyCoCreateInstanceA(pszAnsi,this_punk,&IID_IUnknown,&this->punkUsd,&this->hUsdInstance);
  324. FreePpv(&pszAnsi);
  325. }
  326. #endif
  327. }
  328. }
  329. else {
  330. // No class ID in registry - resort to pass through provider
  331. StiLogTrace(STI_TRACE_WARNING,MSG_LOADING_PASSTHROUGH_USD,hres);
  332. hres = CStiEmptyUSD_New(this_punk, &IID_IUnknown,&this->punkUsd);
  333. }
  334. // Free Class name
  335. FreePpv(&pwszCLSID);
  336. //
  337. // If USD object had been created - initialize it
  338. //
  339. if (SUCCEEDED(hres)) {
  340. hres = OLE_QueryInterface(this->punkUsd,&IID_IStiUSD,&pNewUsd );
  341. if (SUCCEEDED(hres) && pNewUsd) {
  342. StiLogTrace(STI_TRACE_INFORMATION,MSG_INITIALIZING_USD);
  343. //
  344. // Initialize newly created USD object
  345. //
  346. __try {
  347. hres = IStiUSD_Initialize(pNewUsd,
  348. this->pDevCtl,
  349. STI_VERSION_REAL,
  350. hkeyDeviceParameters);
  351. }
  352. __except(EXCEPTION_EXECUTE_HANDLER ) {
  353. hres = GetExceptionCode();
  354. }
  355. //
  356. if (SUCCEEDED(hres)) {
  357. HRESULT hResCaps;
  358. //
  359. // Now get capabilities of the USD and verify version
  360. //
  361. ZeroX(this->sUsdCaps);
  362. __try {
  363. hResCaps = IStiUSD_GetCapabilities(pNewUsd,&this->sUsdCaps);
  364. }
  365. __except (EXCEPTION_EXECUTE_HANDLER) {
  366. hResCaps = GetExceptionCode();
  367. }
  368. if (SUCCEEDED(hResCaps) &&
  369. STI_VERSION_MIN_ALLOWED <= this->sUsdCaps.dwVersion) {
  370. //
  371. // Hurray we loaded USD.
  372. //
  373. this->pUsd = pNewUsd;
  374. StiLogTrace(STI_TRACE_INFORMATION,MSG_SUCCESS_USD);
  375. }
  376. else {
  377. StiLogTrace(STI_TRACE_ERROR,MSG_OLD_USD);
  378. hres = STIERR_OLD_VERSION;
  379. }
  380. }
  381. else {
  382. StiLogTrace(STI_TRACE_ERROR,MSG_FAILED_INIT_USD,hres);
  383. }
  384. // Free original pointer to USD object
  385. //OLE_Release(this->punkUsd);
  386. //
  387. // Rules of aggregation require us to release outer object ( because it was
  388. // AddRef'd by inner object inside delegating QueryInterface
  389. // Only do it if SUCCEEDED, since the outer component wont be addref'd on
  390. // failure.
  391. //
  392. // Attention: first version of USD did not properly support aggregation, but claimed
  393. // they did, so check our internal ref counter to see if it is too low already.
  394. //
  395. if (SUCCEEDED(hres)) {
  396. {
  397. ULONG ulRC = OLE_AddRef(this_punk);
  398. OLE_Release(this_punk);
  399. if (ulRC > 1) {
  400. OLE_Release(this_punk);
  401. }
  402. }
  403. }
  404. }
  405. }
  406. else {
  407. ReportStiLogMessage(g_hStiFileLog,
  408. STI_TRACE_WARNING,
  409. TEXT("Failed to create instance of USD object ")
  410. );
  411. }
  412. //
  413. // Free unknown interface we got to aggreagte USD object
  414. //
  415. OLE_Release(this_punk);
  416. return hres;
  417. }
  418. /*****************************************************************************
  419. *
  420. * @doc INTERNAL
  421. *
  422. * @method void | CStiDevice | QueryInterface |
  423. *
  424. * @cwrap LPStiDevice | lpStiDevice
  425. *
  426. *****************************************************************************/
  427. STDMETHODIMP
  428. CStiDevice_QueryInterface(
  429. PSTIDEVICE pDev,
  430. RIID riid,
  431. PPV ppvObj
  432. )
  433. {
  434. HRESULT hres;
  435. EnterProcR(IStiDevice::QueryInterface,(_ "p", pDev ));
  436. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  437. PCStiDevice this = _thisPv(pDev);
  438. //
  439. // If we are asked for STI Device interface - return it. All other requests are
  440. // blindly passed to USD object
  441. //
  442. if (IsEqualIID(riid, &IID_IStiDevice) ||
  443. IsEqualIID(riid, &IID_IUnknown)) {
  444. hres = Common_QueryInterface(pDev, riid, ppvObj);
  445. }
  446. /*else (IsEqualIID(riid, &IID_IStiUSD)) {
  447. //
  448. // We are asked for native USD interface - return it
  449. //
  450. if (this->pUsd) {
  451. *ppvObj= this->pUsd;
  452. OLE_AddRef(*ppvObj);
  453. hres = STI_OK;
  454. }
  455. else {
  456. hres = STIERR_NOT_INITIALIZED;
  457. }
  458. }
  459. */
  460. else {
  461. if (this->punkUsd) {
  462. hres = IStiUSD_QueryInterface(this->punkUsd,riid,ppvObj);
  463. }
  464. else {
  465. hres = STIERR_NOINTERFACE;
  466. }
  467. }
  468. }
  469. ExitOleProc();
  470. return hres;
  471. }
  472. /*****************************************************************************
  473. *
  474. * @doc EXTERNAL
  475. *
  476. * @method HRESULT | IStiDevice | GetCapabilities |
  477. *
  478. * @parm PSTI_DEV_CAPS | pDevCaps |
  479. *
  480. * @returns
  481. *
  482. * Returns a COM error code.
  483. *
  484. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  485. *
  486. *****************************************************************************/
  487. STDMETHODIMP
  488. CStiDevice_GetCapabilities(
  489. PSTIDEVICE pDev,
  490. PSTI_DEV_CAPS pDevCaps
  491. )
  492. {
  493. HRESULT hres;
  494. EnterProcR(IStiDevice::GetCapabilities,(_ "pp", pDev, pDevCaps));
  495. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  496. PCStiDevice this = _thisPv(pDev);
  497. STI_USD_CAPS sUsdCaps;
  498. __try {
  499. hres = IStiUSD_GetCapabilities(this->pUsd,&sUsdCaps);
  500. }
  501. __except (EXCEPTION_EXECUTE_HANDLER) {
  502. hres = GetExceptionCode();
  503. }
  504. if (SUCCEEDED(hres)) {
  505. pDevCaps->dwGeneric = sUsdCaps.dwGenericCaps;
  506. }
  507. }
  508. return hres;
  509. }
  510. /*****************************************************************************
  511. *
  512. * @doc EXTERNAL
  513. *
  514. * @method HRESULT | IStiDevice | GetStatus |
  515. *
  516. * @parm PSTI_DEVICE_STATUS | PSTI_DEVICE_STATUS pDevStatus) |
  517. *
  518. * @returns
  519. *
  520. * Returns a COM error code.
  521. *
  522. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  523. *
  524. *****************************************************************************/
  525. STDMETHODIMP
  526. CStiDevice_GetStatus(
  527. PSTIDEVICE pDev,
  528. PSTI_DEVICE_STATUS pDevStatus
  529. )
  530. {
  531. HRESULT hres;
  532. EnterProcR(IStiDevice::GetStatus,(_ "pp", pDev, pDevStatus));
  533. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  534. PCStiDevice this = _thisPv(pDev);
  535. ReportStiLogMessage(g_hStiFileLog,
  536. STI_TRACE_INFORMATION,
  537. TEXT("Called GetStatus on a device")
  538. );
  539. if (CStiDevice_IsLocked(this)) {
  540. __try {
  541. hres = IStiUSD_GetStatus(this->pUsd,pDevStatus);
  542. }
  543. __except (EXCEPTION_EXECUTE_HANDLER) {
  544. hres = GetExceptionCode();
  545. }
  546. }
  547. else {
  548. hres = STIERR_NEEDS_LOCK;
  549. }
  550. }
  551. ExitOleProc();
  552. return hres;
  553. }
  554. /*****************************************************************************
  555. *
  556. * @doc EXTERNAL
  557. *
  558. * @method HRESULT | IStiDevice | DeviceReset |
  559. *
  560. * @parm
  561. *
  562. * @returns
  563. *
  564. * Returns a COM error code.
  565. *
  566. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  567. *
  568. *****************************************************************************/
  569. STDMETHODIMP
  570. CStiDevice_InternalReset(
  571. PCStiDevice this
  572. )
  573. {
  574. HRESULT hres = S_OK;
  575. //
  576. // Free original pointer to USD object
  577. //
  578. CStiDevice_EnterCrit(this);
  579. //
  580. // Disconnect from monitor if connected
  581. //
  582. if ( INVALID_HANDLE_VALUE!= this->hDeviceStiHandle) {
  583. RpcStiApiCloseDevice(NULL,this->hDeviceStiHandle);
  584. this->hDeviceStiHandle = INVALID_HANDLE_VALUE;
  585. }
  586. if (this->pUsd) {
  587. CStiDevice_AddRef(this);
  588. IStiUSD_Release(this->pUsd );
  589. this->pUsd = NULL;
  590. }
  591. if (this->punkUsd) {
  592. IStiUSD_Release(this->punkUsd );
  593. this->punkUsd = NULL;
  594. }
  595. if (this->pDevCtl) {
  596. IStiDeviceControl_Release(this->pDevCtl);
  597. this->pDevCtl = NULL;
  598. }
  599. if (this->hNotify) {
  600. CloseHandle(this->hNotify);
  601. }
  602. if (!(this->fCreateForMonitor)) {
  603. // Unlock device if it was locked
  604. UnLockDeviceHelper(this);
  605. }
  606. // Free device name
  607. if(this->pszDeviceInternalName) {
  608. FreePpv(&this->pszDeviceInternalName);
  609. this->pszDeviceInternalName = NULL;
  610. }
  611. if(this->hUsdInstance) {
  612. //
  613. // Should do it only after last interface ptr deleted
  614. //
  615. #ifdef NOT_IMPL
  616. // FreeLibrary(this->hUsdInstance);
  617. #endif
  618. this->hUsdInstance = NULL;
  619. }
  620. CStiDevice_LeaveCrit(this);
  621. return hres;
  622. }
  623. STDMETHODIMP
  624. CStiDevice_DeviceReset(
  625. PSTIDEVICE pDev
  626. )
  627. {
  628. HRESULT hres;
  629. EnterProcR(IStiDevice::DeviceReset,(_ "p", pDev));
  630. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  631. PCStiDevice this = _thisPv(pDev);
  632. if (CStiDevice_IsLocked(this)) {
  633. __try {
  634. hres = IStiUSD_DeviceReset(this->pUsd);
  635. }
  636. __except (EXCEPTION_EXECUTE_HANDLER) {
  637. hres = GetExceptionCode();
  638. }
  639. }
  640. else {
  641. hres = STIERR_NEEDS_LOCK;
  642. }
  643. }
  644. ExitOleProc();
  645. return hres;
  646. }
  647. /*****************************************************************************
  648. *
  649. * @doc EXTERNAL
  650. *
  651. * @method HRESULT | IStiDevice | Diagnostic |
  652. *
  653. * @parm LPDIAG | pBuffer |
  654. *
  655. * @returns
  656. *
  657. * Returns a COM error code.
  658. *
  659. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  660. *
  661. *****************************************************************************/
  662. STDMETHODIMP
  663. CStiDevice_Diagnostic(
  664. PSTIDEVICE pDev,
  665. LPSTI_DIAG pBuffer
  666. )
  667. {
  668. HRESULT hres;
  669. EnterProcR(IStiDevice::Diagnostic,(_ "p", pDev, pBuffer ));
  670. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  671. PCStiDevice this = _thisPv(pDev);
  672. if (CStiDevice_IsLocked(this)) {
  673. __try {
  674. hres = IStiUSD_Diagnostic(this->pUsd,pBuffer);
  675. }
  676. __except (EXCEPTION_EXECUTE_HANDLER) {
  677. hres = GetExceptionCode();
  678. }
  679. }
  680. else {
  681. hres = STIERR_NEEDS_LOCK;
  682. }
  683. }
  684. ExitOleProc();
  685. return hres;
  686. }
  687. /*****************************************************************************
  688. *
  689. * @doc EXTERNAL
  690. *
  691. * @method HRESULT | IStiDevice | LockDevice |
  692. *
  693. * @returns
  694. *
  695. * Returns a COM error code.
  696. *
  697. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  698. *
  699. *****************************************************************************/
  700. STDMETHODIMP
  701. LockDeviceHelper(
  702. PCStiDevice pThisDevice,
  703. DWORD dwTimeOut
  704. )
  705. {
  706. HRESULT hres;
  707. PCStiDevice this = _thisPv(pThisDevice);
  708. hres = (HRESULT) RpcStiApiLockDevice(this->pszDeviceInternalName,
  709. dwTimeOut,
  710. this->fCreateForMonitor);
  711. if (!pThisDevice->fCreateForMonitor) {
  712. if (SUCCEEDED(hres)) {
  713. //
  714. // Call USD to lock (i.e. open any ports etc.)
  715. //
  716. __try {
  717. hres = IStiUSD_LockDevice(this->pUsd);
  718. if (SUCCEEDED(hres)) {
  719. CStiDevice_MarkLocked(this, TRUE);
  720. }
  721. else
  722. {
  723. //
  724. // The device is locked for mutally exclusive access but failed
  725. // to open port. Make sure we release the mutally exclusive lock.
  726. //
  727. UnLockDeviceHelper(this);
  728. }
  729. }
  730. __except (EXCEPTION_EXECUTE_HANDLER) {
  731. hres = HRESULT_FROM_WIN32(GetExceptionCode());
  732. }
  733. }
  734. }
  735. return hres;
  736. }
  737. STDMETHODIMP
  738. CStiDevice_LockDevice(
  739. PSTIDEVICE pDev,
  740. DWORD dwTimeOut
  741. )
  742. {
  743. HRESULT hres;
  744. EnterProcR(IStiDevice::LockDevice,(_ "p", pDev));
  745. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  746. PCStiDevice this = _thisPv(pDev);
  747. hres = LockDeviceHelper(this, dwTimeOut);
  748. }
  749. ExitOleProc();
  750. return hres;
  751. }
  752. /*****************************************************************************
  753. *
  754. * @doc EXTERNAL
  755. *
  756. * @method HRESULT | IStiDevice | UnLockDevice |
  757. *
  758. * @returns
  759. *
  760. * Returns a COM error code.
  761. *
  762. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  763. *
  764. *****************************************************************************/
  765. STDMETHODIMP
  766. UnLockDeviceHelper(
  767. PCStiDevice pThisDevice
  768. )
  769. {
  770. HRESULT hres;
  771. PCStiDevice this = _thisPv(pThisDevice);
  772. hres = (HRESULT) RpcStiApiUnlockDevice(this->pszDeviceInternalName,
  773. this->fCreateForMonitor);
  774. if (!pThisDevice->fCreateForMonitor) {
  775. if (this->pUsd) {
  776. //
  777. // Call USD to unlock (i.e. close any open ports etc.)
  778. //
  779. __try {
  780. hres = IStiUSD_UnLockDevice(this->pUsd);
  781. if (SUCCEEDED(hres)) {
  782. CStiDevice_MarkLocked(this, FALSE);
  783. }
  784. }
  785. __except (EXCEPTION_EXECUTE_HANDLER) {
  786. hres = HRESULT_FROM_WIN32(GetExceptionCode());
  787. }
  788. }
  789. }
  790. return hres;
  791. }
  792. STDMETHODIMP
  793. CStiDevice_UnLockDevice(
  794. PSTIDEVICE pDev
  795. )
  796. {
  797. HRESULT hres;
  798. EnterProcR(IStiDevice::UnLockDevice,(_ "p", pDev));
  799. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  800. PCStiDevice this = _thisPv(pDev);
  801. hres = UnLockDeviceHelper(this);
  802. }
  803. ExitOleProc();
  804. return hres;
  805. }
  806. /*****************************************************************************
  807. *
  808. * @doc EXTERNAL
  809. *
  810. * @method HRESULT | IStiDevice | SetNotificationEvent |
  811. * Specify the event that should be set when the device
  812. * state changes, or turns off such notifications.
  813. *
  814. * "It is an error" to call <f CloseHandle> on the event
  815. * while it has been selected into an <i IStiDevice>
  816. * object. You must call
  817. * <mf IStiDevice::SetEventNotification> with the
  818. * <p hEvent> parameter set to NULL before closing the
  819. * event handle.
  820. *
  821. * If the function is successful, then the application can
  822. * use the event handle in the same manner as any other
  823. * Win32 event handle.
  824. *
  825. * @cwrap LPSTIDEVICE | lpStiDevice
  826. *
  827. * @parm IN HANDLE | hEvent |
  828. *
  829. * Specifies the event handle which will be set when the
  830. * device state changes. It "must" be an event
  831. * handle. DirectInput will <f SetEvent> the handle when
  832. * the state of the device changes.
  833. *
  834. * The application should create the handle via the
  835. * <f CreateEvent> function. If the event is created as
  836. * an automatic-reset event, then the operating system will
  837. * automatically reset the event once a wait has been
  838. * satisfied. If the event is created as a manual-reset
  839. * event, then it is the application's responsibility to
  840. * call <f ResetEvent> to reset it. We put will not
  841. * call <f ResetEvent> for event notification handles.
  842. *
  843. * If the <p hEvent> is zero, then notification is disabled.
  844. *
  845. * @returns
  846. *
  847. * Returns a COM error code.
  848. *
  849. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  850. * <c E_INVALIDARG>: The thing isn't an event handle.
  851. *
  852. *
  853. *****************************************************************************/
  854. STDMETHODIMP
  855. CStiDevice_SetNotificationEvent(
  856. PSTIDEVICE pDev,
  857. HANDLE hEvent
  858. )
  859. {
  860. HRESULT hres;
  861. EnterProcR(IStiDevice::SetNotificationEvent,(_ "px", pDev, hEvent ));
  862. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  863. PCStiDevice this = _thisPv(pDev);
  864. // Must protect with the critical section to prevent somebody from
  865. // acquiring or setting a new event handle while we're changing it.
  866. CStiDevice_EnterCrit(this);
  867. //
  868. // Don't operate on the original handle because
  869. // the app might decide to do something strange to it
  870. // on another thread.
  871. hres = DupEventHandle(hEvent, &hEvent);
  872. if (SUCCEEDED(hres)) {
  873. //
  874. // Resetting the event serves two purposes.
  875. //
  876. // 1. It performs parameter validation for us, and
  877. // 2. The event must be reset while the device is
  878. // not acquired.
  879. if (fLimpFF(hEvent, ResetEvent(hEvent))) {
  880. if (!this->hNotify || !hEvent) {
  881. if (SUCCEEDED(hres)) {
  882. }
  883. } else {
  884. hres = STIERR_HANDLEEXISTS;
  885. }
  886. } else {
  887. hres = E_HANDLE;
  888. }
  889. CloseHandle(hEvent);
  890. }
  891. CStiDevice_LeaveCrit(this);
  892. }
  893. ExitOleProc();
  894. return hres;
  895. }
  896. /*****************************************************************************
  897. *
  898. * @doc EXTERNAL
  899. *
  900. * @method HRESULT | IStiDevice | Subscribe |
  901. *
  902. * @parm LPSUBSCRIBE | ppBuffer |
  903. *
  904. * @returns
  905. *
  906. * Returns a COM error code.
  907. *
  908. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  909. *
  910. *****************************************************************************/
  911. STDMETHODIMP
  912. CStiDevice_Subscribe(
  913. PSTIDEVICE pDev,
  914. LPSTISUBSCRIBE pBuffer
  915. )
  916. {
  917. HRESULT hres;
  918. DWORD dwError = NOERROR;
  919. EnterProcR(IStiDevice::Subscribe,(_ "pp", pDev, pBuffer));
  920. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  921. PCStiDevice this = _thisPv(pDev);
  922. dwError = RpcStiApiSubscribe(this->hDeviceStiHandle,pBuffer);
  923. }
  924. hres = (dwError == NOERROR) ? S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,dwError);
  925. ExitOleProc();
  926. return hres;
  927. }
  928. /*****************************************************************************
  929. *
  930. * @doc EXTERNAL
  931. *
  932. * @method HRESULT | IStiDevice | UnSubscribe |
  933. *
  934. * @returns
  935. *
  936. * Returns a COM error code.
  937. *
  938. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  939. *
  940. *****************************************************************************/
  941. STDMETHODIMP
  942. CStiDevice_UnSubscribe(
  943. PSTIDEVICE pDev
  944. )
  945. {
  946. HRESULT hres;
  947. DWORD dwError = NOERROR;
  948. EnterProcR(IStiDevice::UnSubscribe,(_ "p", pDev));
  949. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  950. PCStiDevice this = _thisPv(pDev);
  951. dwError = RpcStiApiUnSubscribe(this->hDeviceStiHandle);
  952. }
  953. hres = (dwError == NOERROR) ? S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,dwError);
  954. ExitOleProc();
  955. return hres;
  956. }
  957. /*****************************************************************************
  958. *
  959. * @doc EXTERNAL
  960. *
  961. * @method HRESULT | IStiDevice | GetNotificationData |
  962. *
  963. * @parm LPNOTIFY | ppBuffer |
  964. *
  965. * @returns
  966. *
  967. * Returns a COM error code.
  968. *
  969. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  970. *
  971. *****************************************************************************/
  972. STDMETHODIMP
  973. CStiDevice_GetNotificationData(
  974. PSTIDEVICE pDev,
  975. LPSTINOTIFY pBuffer
  976. )
  977. {
  978. HRESULT hres;
  979. DWORD dwError = NOERROR;
  980. EnterProcR(IStiDevice::GetNotificationData,(_ "p", pDev, pBuffer));
  981. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  982. PCStiDevice this = _thisPv(pDev);
  983. dwError = RpcStiApiGetLastNotificationData(this->hDeviceStiHandle,pBuffer);
  984. }
  985. hres = (dwError == NOERROR) ? S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,dwError);
  986. ExitOleProc();
  987. return hres;
  988. }
  989. /*****************************************************************************
  990. *
  991. * @doc EXTERNAL
  992. *
  993. * @method HRESULT | IStiDevice | Escape |
  994. *
  995. * @parm
  996. *
  997. * @returns
  998. *
  999. * Returns a COM error code.
  1000. *
  1001. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  1002. *
  1003. *****************************************************************************/
  1004. STDMETHODIMP
  1005. CStiDevice_Escape(
  1006. PSTIDEVICE pDev,
  1007. STI_RAW_CONTROL_CODE EscapeFunction,
  1008. LPVOID lpInData,
  1009. DWORD cbInDataSize,
  1010. LPVOID lpOutData,
  1011. DWORD cbOutDataSize,
  1012. LPDWORD pcbActualData
  1013. )
  1014. {
  1015. HRESULT hres;
  1016. EnterProcR(IStiDevice::Escape,(_ "pxpxp", pDev, EscapeFunction,lpInData,cbInDataSize,lpOutData ));
  1017. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  1018. PCStiDevice this = _thisPv(pDev);
  1019. if (CStiDevice_IsLocked(this)) {
  1020. __try {
  1021. hres = IStiUSD_Escape(this->pUsd,
  1022. EscapeFunction,
  1023. lpInData,
  1024. cbInDataSize,
  1025. lpOutData,
  1026. cbOutDataSize,
  1027. pcbActualData
  1028. );
  1029. }
  1030. __except (EXCEPTION_EXECUTE_HANDLER) {
  1031. hres = GetExceptionCode();
  1032. }
  1033. }
  1034. else {
  1035. hres = STIERR_NEEDS_LOCK;
  1036. }
  1037. }
  1038. ExitOleProc();
  1039. return hres;
  1040. }
  1041. /*****************************************************************************
  1042. *
  1043. * @doc EXTERNAL
  1044. *
  1045. * @method HRESULT | IStiDevice | RawReadData |
  1046. *
  1047. * @parm
  1048. *
  1049. * @returns
  1050. *
  1051. * Returns a COM error code.
  1052. *
  1053. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  1054. *
  1055. *****************************************************************************/
  1056. STDMETHODIMP
  1057. CStiDevice_RawReadData(
  1058. PSTIDEVICE pDev,
  1059. LPVOID lpBuffer,
  1060. LPDWORD lpdwNumberOfBytes,
  1061. LPOVERLAPPED lpOverlapped
  1062. )
  1063. {
  1064. HRESULT hres;
  1065. EnterProcR(IStiDevice::RawReadData,(_ "p", pDev ));
  1066. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  1067. PCStiDevice this = _thisPv(pDev);
  1068. if (CStiDevice_IsLocked(this)) {
  1069. __try {
  1070. hres = IStiUSD_RawReadData(this->pUsd,lpBuffer,lpdwNumberOfBytes,lpOverlapped);
  1071. }
  1072. __except (EXCEPTION_EXECUTE_HANDLER) {
  1073. hres = GetExceptionCode();
  1074. }
  1075. }
  1076. else {
  1077. hres = STIERR_NEEDS_LOCK;
  1078. }
  1079. }
  1080. ExitOleProc();
  1081. return hres;
  1082. }
  1083. /*****************************************************************************
  1084. *
  1085. * @doc EXTERNAL
  1086. *
  1087. * @method HRESULT | IStiDevice | RawWriteData |
  1088. *
  1089. * @parm
  1090. *
  1091. * @returns
  1092. *
  1093. * Returns a COM error code.
  1094. *
  1095. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  1096. *
  1097. *****************************************************************************/
  1098. STDMETHODIMP
  1099. CStiDevice_RawWriteData(
  1100. PSTIDEVICE pDev,
  1101. LPVOID lpBuffer,
  1102. DWORD dwNumberOfBytes,
  1103. LPOVERLAPPED lpOverlapped
  1104. )
  1105. {
  1106. HRESULT hres;
  1107. EnterProcR(IStiDevice::RawWriteData,(_ "p", pDev ));
  1108. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  1109. PCStiDevice this = _thisPv(pDev);
  1110. if (CStiDevice_IsLocked(this)) {
  1111. __try {
  1112. hres = IStiUSD_RawWriteData(this->pUsd,lpBuffer,dwNumberOfBytes,lpOverlapped);
  1113. }
  1114. __except (EXCEPTION_EXECUTE_HANDLER) {
  1115. hres = GetExceptionCode();
  1116. }
  1117. }
  1118. else {
  1119. hres = STIERR_NEEDS_LOCK;
  1120. }
  1121. }
  1122. ExitOleProc();
  1123. return hres;
  1124. }
  1125. /*****************************************************************************
  1126. *
  1127. * @doc EXTERNAL
  1128. *
  1129. * @method HRESULT | IStiDevice | RawReadCommand |
  1130. *
  1131. * @parm
  1132. *
  1133. * @returns
  1134. *
  1135. * Returns a COM error code.
  1136. *
  1137. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  1138. *
  1139. *****************************************************************************/
  1140. STDMETHODIMP
  1141. CStiDevice_RawReadCommand(
  1142. PSTIDEVICE pDev,
  1143. LPVOID lpBuffer,
  1144. LPDWORD lpdwNumberOfBytes,
  1145. LPOVERLAPPED lpOverlapped
  1146. )
  1147. {
  1148. HRESULT hres;
  1149. EnterProcR(IStiDevice::RawReadCommand,(_ "p", pDev ));
  1150. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  1151. PCStiDevice this = _thisPv(pDev);
  1152. if (CStiDevice_IsLocked(this)) {
  1153. __try {
  1154. hres = IStiUSD_RawReadCommand(this->pUsd,lpBuffer,lpdwNumberOfBytes,lpOverlapped);
  1155. }
  1156. __except (EXCEPTION_EXECUTE_HANDLER) {
  1157. hres = GetExceptionCode();
  1158. }
  1159. }
  1160. else {
  1161. hres = STIERR_NEEDS_LOCK;
  1162. }
  1163. }
  1164. ExitOleProc();
  1165. return hres;
  1166. }
  1167. /*****************************************************************************
  1168. *
  1169. * @doc EXTERNAL
  1170. *
  1171. * @method HRESULT | IStiDevice | RawWriteCommand |
  1172. *
  1173. * @parm
  1174. *
  1175. * @returns
  1176. *
  1177. * Returns a COM error code.
  1178. *
  1179. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  1180. *
  1181. *****************************************************************************/
  1182. STDMETHODIMP
  1183. CStiDevice_RawWriteCommand(
  1184. PSTIDEVICE pDev,
  1185. LPVOID lpBuffer,
  1186. DWORD dwNumberOfBytes,
  1187. LPOVERLAPPED lpOverlapped
  1188. )
  1189. {
  1190. HRESULT hres;
  1191. EnterProcR(IStiDevice::RawWriteCommand,(_ "p", pDev ));
  1192. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  1193. PCStiDevice this = _thisPv(pDev);
  1194. if (CStiDevice_IsLocked(this)) {
  1195. __try {
  1196. hres = IStiUSD_RawWriteCommand(this->pUsd,lpBuffer,dwNumberOfBytes,lpOverlapped);
  1197. }
  1198. __except (EXCEPTION_EXECUTE_HANDLER) {
  1199. hres = GetExceptionCode();
  1200. }
  1201. }
  1202. else {
  1203. hres = STIERR_NEEDS_LOCK;
  1204. }
  1205. }
  1206. ExitOleProc();
  1207. return hres;
  1208. }
  1209. /*****************************************************************************
  1210. *
  1211. * @doc EXTERNAL
  1212. *
  1213. * @method HRESULT | IStiDevice | GetLastError |
  1214. *
  1215. * @parm
  1216. *
  1217. * @returns
  1218. *
  1219. * Returns a COM error code.
  1220. *
  1221. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  1222. *
  1223. *****************************************************************************/
  1224. STDMETHODIMP
  1225. CStiDevice_GetLastError(
  1226. PSTIDEVICE pDev,
  1227. LPDWORD pdwLastDeviceError
  1228. )
  1229. {
  1230. HRESULT hres = STI_OK;
  1231. EnterProcR(IStiDevice::GetLastError,(_ "p", pDev ));
  1232. // Validate parameters
  1233. if (!pdwLastDeviceError) {
  1234. ExitOleProc();
  1235. return STIERR_INVALID_PARAM;
  1236. }
  1237. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  1238. PCStiDevice this = _thisPv(pDev);
  1239. if (this->pDevCtl ) {
  1240. //
  1241. // Call USD to obtain last error information on this device
  1242. //
  1243. __try {
  1244. hres = IStiUSD_GetLastError(this->pUsd,pdwLastDeviceError);
  1245. }
  1246. __except (EXCEPTION_EXECUTE_HANDLER) {
  1247. hres = GetExceptionCode();
  1248. }
  1249. }
  1250. }
  1251. ExitOleProc();
  1252. return hres;
  1253. }
  1254. /*****************************************************************************
  1255. *
  1256. * @doc EXTERNAL
  1257. *
  1258. * @method HRESULT | IStiDevice | GetLastError |
  1259. *
  1260. * @parm
  1261. *
  1262. * @returns
  1263. *
  1264. * Returns a COM error code.
  1265. *
  1266. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  1267. *
  1268. *****************************************************************************/
  1269. STDMETHODIMP
  1270. CStiDevice_GetLastErrorInfo(
  1271. PSTIDEVICE pDev,
  1272. STI_ERROR_INFO *pLastErrorInfo
  1273. )
  1274. {
  1275. HRESULT hres = STI_OK;
  1276. EnterProcR(IStiDevice::GetLastErrorInfo,(_ "p", pDev ));
  1277. // Validate parameters
  1278. if (!pLastErrorInfo) {
  1279. ExitOleProc();
  1280. return STIERR_INVALID_PARAM;
  1281. }
  1282. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  1283. PCStiDevice this = _thisPv(pDev);
  1284. //
  1285. // Call USD to obtain last error information on this device
  1286. //
  1287. __try {
  1288. hres = IStiUSD_GetLastErrorInfo(this->pUsd,pLastErrorInfo);
  1289. }
  1290. __except (EXCEPTION_EXECUTE_HANDLER) {
  1291. hres = GetExceptionCode();
  1292. }
  1293. }
  1294. ExitOleProc();
  1295. return hres;
  1296. }
  1297. /*****************************************************************************
  1298. *
  1299. * @doc EXTERNAL
  1300. *
  1301. * @mfunc HRESULT | IStiDevice | Initialize |
  1302. *
  1303. * Initialize a StiDevice object.
  1304. *
  1305. * Note that if this method fails, the underlying object should
  1306. * be considered to be an an indeterminate state and needs to
  1307. * be reinitialized before it can be subsequently used.
  1308. * The <i IStillImage::CreateDevice> method automatically
  1309. * initializes the device after creating it. Applications
  1310. * normally do not need to call this function.
  1311. *
  1312. * @cwrap LPStiDEVICE | lpStiDevice
  1313. *
  1314. * @parm IN REFGUID | rguid |
  1315. *
  1316. * Identifies the instance of the device for which the interface
  1317. * should be associated.
  1318. * The <mf IStillImage::EnumDevices> method
  1319. * can be used to determine which instance GUIDs are supported by
  1320. * the system.
  1321. *
  1322. * @returns
  1323. * Returns a COM error code. The following error codes are
  1324. * intended to be illustrative and not necessarily comprehensive.
  1325. *
  1326. * <c STI_OK> = <c S_OK>: The operation completed successfully.
  1327. *
  1328. * <c S_FALSE>: The device had already been initialized with
  1329. * the instance GUID passed in <p lpGUID>.
  1330. *
  1331. *
  1332. *****************************************************************************/
  1333. STDMETHODIMP
  1334. CStiDevice_Initialize(
  1335. PSTIDEVICE pDev,
  1336. HINSTANCE hinst,
  1337. LPCWSTR pwszDeviceName,
  1338. DWORD dwVersion,
  1339. DWORD dwMode
  1340. )
  1341. {
  1342. HRESULT hres = STI_OK;
  1343. DWORD dwControlTypeType;
  1344. DWORD dwBusType;
  1345. LPWSTR pwszPortName = NULL;
  1346. DWORD dwFlags = 0;
  1347. DWORD dwError = 0;
  1348. HKEY hkeyDeviceParameters = NULL;
  1349. EnterProcR(IStiDevice::Initialize,(_ "pxpxx", pDev, hinst, pwszDeviceName,dwVersion, dwMode));
  1350. //
  1351. // Validate parameters
  1352. //
  1353. if (!SUCCEEDED(hres = hresFullValidReadPvCb(pwszDeviceName,2,3)) ) {
  1354. goto Cleanup;
  1355. }
  1356. if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) {
  1357. PCStiDevice this = _thisPv(pDev);
  1358. if (SUCCEEDED(hres = hresValidInstanceVer(hinst, dwVersion)) ) {
  1359. //
  1360. // Open device key
  1361. //
  1362. hres = OpenDeviceRegistryKey(pwszDeviceName,NULL,&hkeyDeviceParameters);
  1363. if (!SUCCEEDED(hres)) {
  1364. DebugOutPtszV(DbgFl, TEXT("Cannot open device registry key"));
  1365. StiLogTrace(STI_TRACE_ERROR,MSG_FAILED_OPEN_DEVICE_KEY);
  1366. hres = STIERR_INVALID_PARAM;
  1367. goto Cleanup;
  1368. }
  1369. pwszPortName = NULL;
  1370. ReadRegistryString(hkeyDeviceParameters,
  1371. REGSTR_VAL_DEVICEPORT_W,
  1372. L"",FALSE,&pwszPortName);
  1373. dwBusType = ReadRegistryDwordW(hkeyDeviceParameters,
  1374. REGSTR_VAL_HARDWARE_W,
  1375. 0L);
  1376. if (!pwszPortName ) {
  1377. DebugOutPtszV(DbgFl, TEXT("Cannot read device name from registry"));
  1378. StiLogTrace(STI_TRACE_ERROR,MSG_FAILED_READ_DEVICE_NAME);
  1379. hres = STIERR_INVALID_PARAM;
  1380. goto Cleanup;
  1381. }
  1382. //
  1383. // Convert STI bit flags for device mode into HEL_ bit mask
  1384. //
  1385. dwFlags = 0L;
  1386. #if 0
  1387. if (dwMode & STI_DEVICE_CREATE_DATA) dwFlags |= STI_HEL_OPEN_DATA;
  1388. if (dwMode & STI_DEVICE_CREATE_STATUS) dwFlags |= STI_HEL_OPEN_CONTROL;
  1389. #endif
  1390. //
  1391. // Create device control object, establish connection to
  1392. // hardware layer
  1393. //
  1394. if (dwBusType & (STI_HW_CONFIG_USB | STI_HW_CONFIG_SCSI)) {
  1395. dwControlTypeType = HEL_DEVICE_TYPE_WDM;
  1396. }
  1397. else if (dwBusType & STI_HW_CONFIG_PARALLEL) {
  1398. dwControlTypeType = HEL_DEVICE_TYPE_PARALLEL;
  1399. }
  1400. else if (dwBusType & STI_HW_CONFIG_SERIAL) {
  1401. dwControlTypeType = HEL_DEVICE_TYPE_SERIAL;
  1402. }
  1403. else {
  1404. DebugOutPtszV(DbgFl, TEXT("Cannot determine device control type, resort to WDM"));
  1405. dwControlTypeType = HEL_DEVICE_TYPE_WDM;
  1406. }
  1407. hres = NewDeviceControl(dwControlTypeType,dwMode,pwszPortName,dwFlags,&this->pDevCtl);
  1408. if (SUCCEEDED(hres)) {
  1409. //
  1410. // We created device control block, now load and initialize USD
  1411. //
  1412. hres = LoadInitUSD(this,hkeyDeviceParameters);
  1413. if (!SUCCEEDED(hres)) {
  1414. //
  1415. // Failed to load USD - free device control object
  1416. //
  1417. IStiDeviceControl_Release(this->pDevCtl);
  1418. this->pDevCtl = NULL;
  1419. goto Cleanup;
  1420. }
  1421. }
  1422. else {
  1423. DebugOutPtszV(DbgFl, TEXT("Cannot create/allocate Device control object"));
  1424. StiLogTrace(STI_TRACE_ERROR,MSG_FAILED_CREATE_DCB,hres );
  1425. goto Cleanup;
  1426. }
  1427. // Store device name for future use
  1428. this->pszDeviceInternalName = NULL;
  1429. hres = AllocCbPpv(sizeof(WCHAR)*(OSUtil_StrLenW(pwszDeviceName)+1), &this->pszDeviceInternalName);
  1430. if (SUCCEEDED(hres)) {
  1431. OSUtil_lstrcpyW( this->pszDeviceInternalName, pwszDeviceName );
  1432. }
  1433. //
  1434. // Connect to STI monitor if we are running in data mode or in status mode with device supporintg
  1435. // notifications
  1436. //
  1437. if (SUCCEEDED(hres) ) {
  1438. if (!(dwMode & STI_DEVICE_CREATE_FOR_MONITOR)) {
  1439. if ((dwMode & STI_DEVICE_CREATE_DATA) ||
  1440. (this->sUsdCaps.dwGenericCaps & STI_USD_GENCAP_NATIVE_PUSHSUPPORT ) ) {
  1441. DWORD dwProcessID = GetCurrentProcessId();
  1442. dwError = RpcStiApiOpenDevice(NULL,
  1443. pwszDeviceName,
  1444. dwMode,
  1445. 0,
  1446. dwProcessID,
  1447. &(this->hDeviceStiHandle));
  1448. hres = (dwError == NOERROR) ? S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,dwError);
  1449. if (NOERROR != dwError) {
  1450. DebugOutPtszV(DbgFl, TEXT("Did not connect to monitor.Rpc status=%d"),dwError);
  1451. ReportStiLogMessage(g_hStiFileLog,
  1452. STI_TRACE_ERROR,
  1453. TEXT("Requested but failed to connect to STI monitor. "));
  1454. }
  1455. }
  1456. } else {
  1457. //
  1458. // Indicate that we are in the server process. This is
  1459. // used when locking/unlocking a device
  1460. //
  1461. this->fCreateForMonitor = TRUE;
  1462. }
  1463. //
  1464. // BUGBUG - Problems connecting to RPC server on Millenium . Fix IT !!!
  1465. // To allow STI TWAIN to continue working - ignore error now
  1466. //
  1467. hres = S_OK ;
  1468. // END
  1469. }
  1470. }
  1471. }
  1472. Cleanup:
  1473. //
  1474. // Free allocated buffers
  1475. //
  1476. FreePpv(&pwszPortName);
  1477. //
  1478. // If opened key - close it
  1479. //
  1480. if (hkeyDeviceParameters) {
  1481. RegCloseKey(hkeyDeviceParameters);
  1482. hkeyDeviceParameters = NULL;
  1483. }
  1484. // Did we Fail ?
  1485. if (!SUCCEEDED(hres)) {
  1486. DebugOutPtszV(DbgFl, TEXT("Cannot create device object."));
  1487. }
  1488. ExitOleProc();
  1489. return hres;
  1490. }
  1491. /*****************************************************************************
  1492. *
  1493. * @doc INTERNAL
  1494. *
  1495. * @mfunc void | IStiDevice | Init |
  1496. *
  1497. * Initialize the internal parts of the StiDevice object.
  1498. *
  1499. *****************************************************************************/
  1500. HRESULT INLINE
  1501. CStiDevice_Init(
  1502. PCStiDevice this
  1503. )
  1504. {
  1505. HRESULT hr = S_OK;
  1506. this->pUsd = NULL;
  1507. __try {
  1508. // The critical section must be the very first thing we do,
  1509. // because only Finalize checks for its existence.
  1510. #ifdef UNICODE
  1511. if(!InitializeCriticalSectionAndSpinCount(&this->crst, MINLONG)) {
  1512. #else
  1513. InitializeCriticalSection(&this->crst); if (TRUE) {
  1514. #endif
  1515. hr = HRESULT_FROM_WIN32(GetLastError());
  1516. }
  1517. else {
  1518. this->fLocked = FALSE;
  1519. this->hDeviceStiHandle = INVALID_HANDLE_VALUE;
  1520. this->fCritInited = TRUE;
  1521. this->hUsdInstance = NULL;
  1522. }
  1523. }
  1524. __except(EXCEPTION_EXECUTE_HANDLER) {
  1525. hr = E_OUTOFMEMORY;
  1526. }
  1527. return hr;
  1528. }
  1529. /*****************************************************************************
  1530. *
  1531. * @doc INTERNAL
  1532. *
  1533. * @func void | CStiDev_Finalize |
  1534. *
  1535. * Releases the resources of a generic device.
  1536. *
  1537. * @parm PV | pvObj |
  1538. *
  1539. * Object being released. Note that it may not have been
  1540. * completely initialized, so everything should be done
  1541. * carefully.
  1542. *
  1543. *****************************************************************************/
  1544. void INTERNAL
  1545. CStiDevice_Finalize(PV pvObj)
  1546. {
  1547. HRESULT hres;
  1548. PCStiDevice this = pvObj;
  1549. #ifdef MAXDEBUG
  1550. if (this->cCrit) {
  1551. DebugOutPtszV(DbgFl, TEXT("IStiDevice::Release: Another thread is using the object; crash soon!"));
  1552. }
  1553. #endif
  1554. hres = CStiDevice_InternalReset(this);
  1555. AssertF(SUCCEEDED(hres));
  1556. if (this->fCritInited) {
  1557. DeleteCriticalSection(&this->crst);
  1558. this->fCritInited = FALSE;
  1559. }
  1560. }
  1561. /*****************************************************************************
  1562. *
  1563. * @doc INTERNAL
  1564. *
  1565. * @mfunc HRESULT | IStiDevice | New |
  1566. *
  1567. * Create a new StiDevice object, uninitialized.
  1568. *
  1569. * @parm IN PUNK | punkOuter |
  1570. *
  1571. * Controlling unknown for aggregation.
  1572. *
  1573. * @parm IN RIID | riid |
  1574. *
  1575. * Desired interface to new object.
  1576. *
  1577. * @parm OUT PPV | ppvObj |
  1578. *
  1579. * Output pointer for new object.
  1580. *
  1581. *****************************************************************************/
  1582. STDMETHODIMP
  1583. CStiDevice_New(PUNK punkOuter, RIID riid, PPV ppvObj)
  1584. {
  1585. HRESULT hres;
  1586. EnterProcR(IStiDevice::<constructor>, (_ "Gp", riid, punkOuter));
  1587. hres = Common_NewRiid(CStiDevice, punkOuter, riid, ppvObj);
  1588. if (SUCCEEDED(hres)) {
  1589. PCStiDevice this = _thisPv(*ppvObj);
  1590. hres = CStiDevice_Init(this);
  1591. }
  1592. ExitOleProcPpvR(ppvObj);
  1593. return hres;
  1594. }
  1595. /*****************************************************************************
  1596. *
  1597. * Miscellaneous utility functions, specific for device processing
  1598. *
  1599. *****************************************************************************/
  1600. /*****************************************************************************
  1601. *
  1602. * @doc INTERNAL
  1603. *
  1604. * @mfunc OpenDeviceRegistryKey
  1605. *
  1606. * Opens registry key, associated with device instance to use for storing/retrieving
  1607. * instance information.
  1608. *
  1609. * Key is obtained from setup api ,based on the STI device name. We should never
  1610. * open device key by concatenating fixed name with device name, as it works on Memphis.
  1611. *
  1612. *****************************************************************************/
  1613. STDMETHODIMP
  1614. OpenDeviceRegistryKey(
  1615. LPCWSTR pwszDeviceName,
  1616. LPCWSTR pwszSubKeyName,
  1617. HKEY *phkeyDeviceParameters
  1618. )
  1619. {
  1620. DWORD dwErr;
  1621. WCHAR wszDeviceKeyName[MAX_PATH];
  1622. HRESULT hRes;
  1623. #ifdef WINNT
  1624. GUID Guid = GUID_DEVCLASS_IMAGE;
  1625. DWORD dwRequired;
  1626. DWORD Idx;
  1627. SP_DEVINFO_DATA spDevInfoData;
  1628. HKEY hKeyDevice;
  1629. WCHAR szDevDriver[STI_MAX_INTERNAL_NAME_LENGTH];
  1630. TCHAR sztDevClass[32];
  1631. ULONG cbData;
  1632. DWORD dwError;
  1633. BOOL fRet;
  1634. BOOL fFoundDriverNameMatch;
  1635. PWIA_DEVKEYLIST pWiaDevKeyList;
  1636. dwRequired = 0;
  1637. dwError = 0;
  1638. hKeyDevice = INVALID_HANDLE_VALUE;
  1639. *phkeyDeviceParameters = NULL;
  1640. pWiaDevKeyList = NULL;
  1641. //
  1642. // We need to open device registry key, navigating through Setup API set
  1643. // As we don't have reverse search to retrive device info handle , based on
  1644. // driver name, we do exsaustive search. Number of imaging devices for given class ID
  1645. // is never as large to make a problem.
  1646. //
  1647. //
  1648. hRes = STIERR_INVALID_DEVICE_NAME;
  1649. pWiaDevKeyList = WiaCreateDeviceRegistryList(TRUE);
  1650. fFoundDriverNameMatch = FALSE;
  1651. if (NULL != pWiaDevKeyList) {
  1652. for (Idx = 0; Idx < pWiaDevKeyList->dwNumberOfDevices; Idx++) {
  1653. //
  1654. // Compare driver name
  1655. //
  1656. cbData = sizeof(szDevDriver);
  1657. *szDevDriver = L'\0';
  1658. dwError = RegQueryValueExW(pWiaDevKeyList->Dev[Idx].hkDeviceRegistry,
  1659. REGSTR_VAL_DEVICE_ID_W,
  1660. // REGSTR_VAL_FRIENDLY_NAME_W,
  1661. NULL,
  1662. NULL,
  1663. (LPBYTE)szDevDriver,
  1664. &cbData);
  1665. if( (ERROR_SUCCESS == dwError)
  1666. && (!lstrcmpiW(szDevDriver,pwszDeviceName)) )
  1667. {
  1668. fFoundDriverNameMatch = TRUE;
  1669. hKeyDevice = pWiaDevKeyList->Dev[Idx].hkDeviceRegistry;
  1670. //
  1671. // Set INVALID_HANDLE_VALUE not to get closed on free.
  1672. //
  1673. pWiaDevKeyList->Dev[Idx].hkDeviceRegistry = INVALID_HANDLE_VALUE;
  1674. break;
  1675. }
  1676. } // for (Idx = 0; Idx < pWiaDevKeyList->dwNumberOfDevices; Idx++)
  1677. if(fFoundDriverNameMatch) {
  1678. //
  1679. // Open the software key and look for subclass.
  1680. //
  1681. if (hKeyDevice != INVALID_HANDLE_VALUE) {
  1682. cbData = sizeof(sztDevClass);
  1683. if ((RegQueryValueEx(hKeyDevice,
  1684. REGSTR_VAL_SUBCLASS,
  1685. NULL,
  1686. NULL,
  1687. (LPBYTE)sztDevClass,
  1688. &cbData) != ERROR_SUCCESS) ||
  1689. (lstrcmpi(sztDevClass, STILLIMAGE) != 0)) {
  1690. fFoundDriverNameMatch = FALSE;
  1691. hRes = STIERR_INVALID_DEVICE_NAME;
  1692. RegCloseKey(hKeyDevice);
  1693. }
  1694. else {
  1695. //
  1696. // Now open subkey if asked to.
  1697. //
  1698. if (pwszSubKeyName && *pwszSubKeyName) {
  1699. dwErr = OSUtil_RegCreateKeyExW(hKeyDevice,
  1700. (LPWSTR)pwszSubKeyName,
  1701. 0L,
  1702. NULL,
  1703. 0L,
  1704. KEY_READ | KEY_WRITE,
  1705. NULL,
  1706. phkeyDeviceParameters,
  1707. NULL
  1708. );
  1709. if ( ERROR_ACCESS_DENIED == dwErr ) {
  1710. dwErr = OSUtil_RegCreateKeyExW(hKeyDevice,
  1711. (LPWSTR)pwszSubKeyName,
  1712. 0L,
  1713. NULL,
  1714. 0L,
  1715. KEY_READ,
  1716. NULL,
  1717. phkeyDeviceParameters,
  1718. NULL
  1719. );
  1720. }
  1721. RegCloseKey(hKeyDevice);
  1722. }
  1723. else {
  1724. //
  1725. // No subkey given - device key will be returned - don't close it.
  1726. //
  1727. *phkeyDeviceParameters = hKeyDevice;
  1728. dwErr = NOERROR;
  1729. } // endif Subkey name passed
  1730. hRes = HRESULT_FROM_WIN32(dwErr); ;
  1731. } // Is StillImage subclass
  1732. } // endif Opened device registry key
  1733. } // endif Found matching driver name
  1734. } // if (NULL != pWiaDevKeyList)
  1735. //
  1736. // Free device registry list.
  1737. //
  1738. if(NULL != pWiaDevKeyList){
  1739. WiaDestroyDeviceRegistryList(pWiaDevKeyList);
  1740. }
  1741. return hRes;
  1742. #else
  1743. //
  1744. // Based on device name and optional subkey name, open requested key
  1745. //
  1746. wcscat(wcscpy(wszDeviceKeyName,
  1747. (g_NoUnicodePlatform) ? REGSTR_PATH_STIDEVICES_W : REGSTR_PATH_STIDEVICES_NT_W),
  1748. L"\\");
  1749. wcscat(wszDeviceKeyName,pwszDeviceName);
  1750. //
  1751. // Validate this is correct device name ?
  1752. //
  1753. dwErr = OSUtil_RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  1754. wszDeviceKeyName,
  1755. 0L,
  1756. KEY_READ ,
  1757. phkeyDeviceParameters
  1758. );
  1759. if (NOERROR != dwErr ) {
  1760. if ( (dwErr == ERROR_INVALID_NAME) || (dwErr == ERROR_FILE_NOT_FOUND)) {
  1761. return STIERR_INVALID_DEVICE_NAME;
  1762. }
  1763. return HRESULT_FROM_WIN32(dwErr);
  1764. }
  1765. else {
  1766. RegCloseKey(*phkeyDeviceParameters);
  1767. *phkeyDeviceParameters = NULL;
  1768. }
  1769. //
  1770. // Now open subkey
  1771. //
  1772. if (pwszSubKeyName && *pwszSubKeyName) {
  1773. wcscat(wszDeviceKeyName,L"\\");
  1774. wcscat(wszDeviceKeyName,pwszSubKeyName);
  1775. }
  1776. dwErr = OSUtil_RegCreateKeyExW(HKEY_LOCAL_MACHINE,
  1777. wszDeviceKeyName,
  1778. 0L,
  1779. NULL,
  1780. 0L,
  1781. KEY_READ | KEY_WRITE,
  1782. NULL,
  1783. phkeyDeviceParameters,
  1784. NULL
  1785. );
  1786. if ( ERROR_ACCESS_DENIED == dwErr ) {
  1787. dwErr = OSUtil_RegCreateKeyExW(HKEY_LOCAL_MACHINE,
  1788. wszDeviceKeyName,
  1789. 0L,
  1790. NULL,
  1791. 0L,
  1792. KEY_READ ,
  1793. NULL,
  1794. phkeyDeviceParameters,
  1795. NULL
  1796. );
  1797. }
  1798. return HRESULT_FROM_WIN32(dwErr);
  1799. #endif
  1800. }
  1801. /*****************************************************************************
  1802. *
  1803. * The long-awaited vtbls and templates
  1804. *
  1805. *****************************************************************************/
  1806. #pragma BEGIN_CONST_DATA
  1807. #define CStiDevice_Signature (DWORD)'DEV'
  1808. Primary_Interface_Begin(CStiDevice, IStiDevice)
  1809. CStiDevice_Initialize,
  1810. CStiDevice_GetCapabilities,
  1811. CStiDevice_GetStatus,
  1812. CStiDevice_DeviceReset,
  1813. CStiDevice_Diagnostic,
  1814. CStiDevice_Escape,
  1815. CStiDevice_GetLastError,
  1816. CStiDevice_LockDevice,
  1817. CStiDevice_UnLockDevice,
  1818. CStiDevice_RawReadData,
  1819. CStiDevice_RawWriteData,
  1820. CStiDevice_RawReadCommand,
  1821. CStiDevice_RawWriteCommand,
  1822. CStiDevice_Subscribe,
  1823. CStiDevice_GetNotificationData,
  1824. CStiDevice_UnSubscribe,
  1825. CStiDevice_GetLastErrorInfo,
  1826. Primary_Interface_End(CStiDevice, IStiDevice)