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.

1278 lines
33 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1999
  4. *
  5. * TITLE: WiaLock.Cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ByronC
  10. *
  11. * DATE: 15 November, 1999
  12. *
  13. * DESCRIPTION:
  14. * Implementation of Lock Manager.
  15. *
  16. *******************************************************************************/
  17. #include "precomp.h"
  18. #include "stiexe.h"
  19. //
  20. // Include Headers
  21. //
  22. #include <time.h>
  23. #include "device.h"
  24. #include "wiamonk.h"
  25. #include "wiapriv.h"
  26. #include "stiusd.h"
  27. #define DECLARE_LOCKMGR
  28. #include "lockmgr.h"
  29. /**************************************************************************\
  30. * StiLockMgr
  31. *
  32. * Constructor for the lock manager.
  33. *
  34. * Arguments:
  35. *
  36. * Return Value:
  37. *
  38. * History:
  39. *
  40. * 15/1/1999 Original Version
  41. *
  42. \**************************************************************************/
  43. StiLockMgr::StiLockMgr()
  44. {
  45. DBG_FN(StiLockMgr::StiLockMgr);
  46. m_cRef = 0;
  47. m_dwCookie = 0;
  48. m_bSched = FALSE;
  49. m_lSchedWaitTime = 0;
  50. }
  51. /**************************************************************************\
  52. * Initialize
  53. *
  54. * Initializes the lock manager and registers this instance in the ROT.
  55. *
  56. * Arguments:
  57. *
  58. * Return Value:
  59. *
  60. * Status
  61. *
  62. * History:
  63. *
  64. * 15/1/1999 Original Version
  65. *
  66. \**************************************************************************/
  67. HRESULT StiLockMgr::Initialize()
  68. {
  69. DBG_FN(StiLockMgr::Initialize);
  70. HRESULT hr = S_OK;
  71. //
  72. // Artificially set ref count too high to prevent destruction from inside Release()
  73. //
  74. m_cRef = 2;
  75. #ifdef USE_ROT
  76. CWiaInstMonk *pInstMonk = new CWiaInstMonk();
  77. CHAR szCookieName[MAX_PATH];
  78. IUnknown *pUnk;
  79. IMoniker *pIMoniker;
  80. IBindCtx *pCtx;
  81. IRunningObjectTable *pTable;
  82. USES_CONVERSION;
  83. //
  84. // Make up a cookie name. This will be stored in the registry. This
  85. // name uniquely identifies our lock manager on the system.
  86. //
  87. srand( (unsigned)time( NULL ) );
  88. sprintf(szCookieName, "%d_LockMgr_%d", rand(), rand());
  89. //
  90. // Get our IUnknown interface
  91. //
  92. hr = QueryInterface(IID_IUnknown, (VOID**) &pUnk);
  93. if (SUCCEEDED(hr)) {
  94. //
  95. // We need to register this object in the ROT, so that any STI clients
  96. // will connect to this Lock Manager. This way, we maintain consistent
  97. // device lock information amongst multiple STI and WIA clients.
  98. //
  99. // First create an instance Moniker. Then get a pointer to the ROT.
  100. // Register this named moniker with our Lock Manager. Store the
  101. // cookie so we can unregister upon destruction of the Lock Manager.
  102. //
  103. if (pInstMonk) {
  104. hr = pInstMonk->Initialize(A2W(szCookieName));
  105. if (SUCCEEDED(hr)) {
  106. hr = pInstMonk->QueryInterface(IID_IMoniker, (VOID**) &pIMoniker);
  107. }
  108. } else {
  109. hr = E_OUTOFMEMORY;
  110. }
  111. }
  112. if (SUCCEEDED(hr)) {
  113. hr = CreateBindCtx(0, &pCtx);
  114. if (SUCCEEDED(hr)) {
  115. hr = pCtx->GetRunningObjectTable(&pTable);
  116. if (SUCCEEDED(hr)) {
  117. //
  118. // Register ourselves in the ROT
  119. //
  120. hr = pTable->Register(ROTFLAGS_ALLOWANYCLIENT,
  121. pUnk,
  122. pIMoniker,
  123. &m_dwCookie);
  124. ASSERT(hr == S_OK);
  125. //
  126. // Write the cookie name to the registry, so clients will know
  127. // the name of our lock manager.
  128. //
  129. if (hr == S_OK) {
  130. hr = WriteCookieNameToRegistry(szCookieName);
  131. } else {
  132. DBG_ERR(("StiLockMgr::Initialize, could not register Moniker"));
  133. hr = (SUCCEEDED(hr)) ? E_FAIL : hr;
  134. }
  135. pTable->Release();
  136. } else {
  137. DBG_ERR(("StiLockMgr::Initialize, could not get Running Object Table"));
  138. }
  139. pCtx->Release();
  140. } else {
  141. DBG_ERR(("StiLockMgr::Initialize, could not create bind context"));
  142. }
  143. } else {
  144. DBG_ERR(("StiLockMgr::Initialize, problem creating Moniker"));
  145. }
  146. if (pInstMonk) {
  147. pInstMonk->Release();
  148. }
  149. #endif
  150. return hr;
  151. }
  152. /**************************************************************************\
  153. * ~StiLockMgr
  154. *
  155. * Destructor - removes instance from the ROT that was resgistered in
  156. * Initialize.
  157. *
  158. * Arguments:
  159. *
  160. * Return Value:
  161. *
  162. * History:
  163. *
  164. * 15/1/1999 Original Version
  165. *
  166. \**************************************************************************/
  167. StiLockMgr::~StiLockMgr()
  168. {
  169. DBG_FN(StiLockMgr::~StiLockMgr);
  170. m_cRef = 0;
  171. #ifdef USE_ROT
  172. if (m_dwCookie) {
  173. HRESULT hr;
  174. IBindCtx *pCtx;
  175. IRunningObjectTable *pTable;
  176. hr = CreateBindCtx(0, &pCtx);
  177. if (SUCCEEDED(hr)) {
  178. hr = pCtx->GetRunningObjectTable(&pTable);
  179. if (SUCCEEDED(hr)) {
  180. hr = pTable->Revoke(m_dwCookie);
  181. }
  182. }
  183. DeleteCookieFromRegistry();
  184. if (FAILED(hr)) {
  185. DBG_ERR(("StiLockMgr::~StiLockMgr, could not Unregister Moniker"));
  186. }
  187. m_dwCookie = 0;
  188. }
  189. #endif
  190. m_bSched = FALSE;
  191. m_lSchedWaitTime = 0;
  192. }
  193. /**************************************************************************\
  194. * IUnknown methods
  195. *
  196. * QueryInterface
  197. * AddRef
  198. * Release
  199. *
  200. * History:
  201. *
  202. * 15/1/1999 Original Version
  203. *
  204. \**************************************************************************/
  205. HRESULT _stdcall StiLockMgr::QueryInterface(
  206. const IID& iid,
  207. void** ppv)
  208. {
  209. if (iid == IID_IUnknown) {
  210. *ppv = (IUnknown*) this;
  211. } else if (iid == IID_IStiLockMgr) {
  212. *ppv = (IStiLockMgr*) this;
  213. } else {
  214. return E_NOINTERFACE;
  215. }
  216. AddRef();
  217. return S_OK;
  218. }
  219. ULONG _stdcall StiLockMgr::AddRef(void)
  220. {
  221. InterlockedIncrement(&m_cRef);
  222. return m_cRef;
  223. }
  224. ULONG _stdcall StiLockMgr::Release(void)
  225. {
  226. LONG ref;
  227. InterlockedDecrement(&m_cRef);
  228. ref = m_cRef;
  229. if (ref == 0) {
  230. delete this;
  231. }
  232. return ref;
  233. }
  234. /**************************************************************************\
  235. * RequestLock
  236. *
  237. * Attempt to acquire a device lock. NOTE: Do not attempt this call from
  238. * inside an ACTIVE_DEVICE - it may lead to dealock. Use
  239. * RequestLock(ACTIVE_DEVICE, ...) instead.
  240. *
  241. * Arguments:
  242. *
  243. * pszDeviceName - The STI internal name of the device (same as WIA
  244. * device ID)
  245. * ulTimeout - The max. amount of time to wait for a lock
  246. * bInServerProcess- Indicates whether we're being called from within the
  247. * server's process.
  248. *
  249. * Return Value:
  250. *
  251. * Status
  252. *
  253. * History:
  254. *
  255. * 15/1/1999 Original Version
  256. *
  257. \**************************************************************************/
  258. HRESULT _stdcall StiLockMgr::RequestLock(BSTR pszDeviceName, ULONG ulTimeout, BOOL bInServerProcess, DWORD dwClientThreadId)
  259. {
  260. DBG_FN(StiLockMgr::RequestLock);
  261. HRESULT hr = E_FAIL;
  262. ACTIVE_DEVICE *pDevice = NULL;
  263. USES_CONVERSION;
  264. //
  265. // Get the device specified by pszDeviceName
  266. //
  267. pDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_DEV_ID, pszDeviceName);
  268. if(pDevice) {
  269. hr = RequestLockHelper(pDevice, ulTimeout, bInServerProcess, dwClientThreadId);
  270. //
  271. // Release the device due to the AddRef made by the call to
  272. // IsInList
  273. //
  274. pDevice->Release();
  275. } else {
  276. //
  277. // Device not found, log error
  278. //
  279. DBG_ERR(("StiLockMgr::RequestLock, device name was not found"));
  280. hr = STIERR_INVALID_DEVICE_NAME;
  281. }
  282. return hr;
  283. }
  284. /**************************************************************************\
  285. * RequestLock
  286. *
  287. * Attempt to acquire a device lock. This method is always called from
  288. * the server.
  289. *
  290. * Arguments:
  291. *
  292. * pDevice - The STI ACTIVE_DEVICE object
  293. * ulTimeout - The max. amount of time to wait for a lock
  294. *
  295. * Return Value:
  296. *
  297. * Status
  298. *
  299. * History:
  300. *
  301. * 12/06/1999 Original Version
  302. *
  303. \**************************************************************************/
  304. HRESULT _stdcall StiLockMgr::RequestLock(ACTIVE_DEVICE *pDevice, ULONG ulTimeout, BOOL bOpenPort)
  305. {
  306. DBG_FN(StiLockMgr::RequestLock);
  307. return RequestLockHelper(pDevice, ulTimeout, bOpenPort, GetCurrentThreadId());
  308. }
  309. /**************************************************************************\
  310. * RequestLockHelper
  311. *
  312. * Helper used to acquire a device lock. It fills out the appropriate
  313. * lock information stored with the device.
  314. *
  315. * Arguments:
  316. *
  317. * pDevice - A pointer to the STI device
  318. * ulTimeout - The max. amount of time to wait for a lock
  319. * bInServerProcess- Indicates whether we're in the server process
  320. *
  321. * Return Value:
  322. *
  323. * Status
  324. *
  325. * History:
  326. *
  327. * 12/06/1999 Original Version
  328. *
  329. \**************************************************************************/
  330. HRESULT StiLockMgr::RequestLockHelper(ACTIVE_DEVICE *pDevice, ULONG ulTimeout, BOOL bInServerProcess, DWORD dwClientThreadId)
  331. {
  332. DBG_FN(StiLockMgr::RequestLockHelper);
  333. HRESULT hr = S_OK;
  334. DWORD dwWait = 0;
  335. LockInfo *pLockInfo = NULL;
  336. DWORD dwCurThread = 0;
  337. hr = CheckDeviceInfo(pDevice);
  338. if (FAILED(hr)) {
  339. return hr;
  340. }
  341. pLockInfo = (LockInfo*) pDevice->m_pLockInfo;
  342. //
  343. // Check whether this is the same thread re-acquiring an active lock.
  344. // If not, we must wait for device to become free.
  345. //
  346. dwCurThread = dwClientThreadId;
  347. if (InterlockedCompareExchange((LONG*)&pLockInfo->dwThreadId,
  348. dwCurThread,
  349. dwCurThread) == (LONG) dwCurThread) {
  350. pLockInfo->lInUse++;
  351. pLockInfo->lTimeLeft = pLockInfo->lHoldingTime;
  352. } else {
  353. dwWait = WaitForSingleObject(pLockInfo->hDeviceIsFree, ulTimeout);
  354. if (dwWait == WAIT_OBJECT_0) {
  355. //
  356. // Check whether the driver is still loaded.
  357. //
  358. if (pDevice->m_DrvWrapper.IsDriverLoaded()) {
  359. //
  360. // Update lock information
  361. //
  362. InterlockedExchange((LONG*) &pLockInfo->dwThreadId, dwCurThread);
  363. pLockInfo->lTimeLeft = pLockInfo->lHoldingTime;
  364. pLockInfo->lInUse++;
  365. //
  366. // Only ask USD to open port if we're in the server process.
  367. //
  368. if (bInServerProcess) {
  369. hr = LockDevice(pDevice);
  370. } else {
  371. pLockInfo->bDeviceIsLocked = TRUE;
  372. }
  373. } else {
  374. //
  375. // Driver not loaded, so clear the lock info. This is the
  376. // case where an application was sitting on a request to
  377. // lock the device, but the service's control thread
  378. // was busy unloading it. We want to stop it here, so
  379. // we don't make the bogus call down to the driver
  380. // which we know is not loaded.
  381. //
  382. ClearLockInfo(pLockInfo);
  383. hr = WIA_ERROR_OFFLINE;
  384. }
  385. } else {
  386. DBG_ERR(("StiLockMgr::RequestLockHelper, device is busy"));
  387. hr = WIA_ERROR_BUSY;
  388. }
  389. }
  390. return hr;
  391. }
  392. /**************************************************************************\
  393. * RequestUnlock
  394. *
  395. * Attempt to unlock a device. NOTE: Do not attempt this call from
  396. * inside an ACTIVE_DEVICE - it may lead to dealock. Use
  397. * RequestUnlock(ACTIVE_DEVICE, ...) instead.
  398. *
  399. * Arguments:
  400. *
  401. * pszDeviceName - The STI internal name of the device (same as WIA
  402. * device ID)
  403. * bInServerProcess- Indicates whether we're in the server process
  404. *
  405. * Return Value:
  406. *
  407. * Status
  408. *
  409. * History:
  410. *
  411. * 15/1/1999 Original Version
  412. *
  413. \**************************************************************************/
  414. HRESULT _stdcall StiLockMgr::RequestUnlock(BSTR bstrDeviceName, BOOL bInServerProcess, DWORD dwClientThreadId)
  415. {
  416. DBG_FN(StiLockMgr::RequestUnlock);
  417. HRESULT hr = E_FAIL;
  418. ACTIVE_DEVICE *pDevice = NULL;
  419. USES_CONVERSION;
  420. //
  421. // Get the device specified by pszDeviceName
  422. //
  423. pDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_DEV_ID, bstrDeviceName);
  424. if(pDevice) {
  425. hr = RequestUnlockHelper(pDevice, bInServerProcess, dwClientThreadId);
  426. //
  427. // Release the device due to the AddRef made by the call to
  428. // IsInList
  429. //
  430. pDevice->Release();
  431. } else {
  432. //
  433. // Device not found, log error
  434. //
  435. DBG_ERR(("StiLockMgr::RequestUnlock, device name was not found"));
  436. hr = STIERR_INVALID_DEVICE_NAME;
  437. }
  438. return hr;
  439. }
  440. /**************************************************************************\
  441. * RequestUnlock
  442. *
  443. * Attempt to unlock a device. This method is always called from within
  444. * the server.
  445. *
  446. * Arguments:
  447. *
  448. * pDevice - The STI ACTIVE_DEVICE object
  449. *
  450. * Return Value:
  451. *
  452. * Status
  453. *
  454. * History:
  455. *
  456. * 15/1/1999 Original Version
  457. *
  458. \**************************************************************************/
  459. HRESULT _stdcall StiLockMgr::RequestUnlock(ACTIVE_DEVICE *pDevice, BOOL bClosePort)
  460. {
  461. DBG_FN(StiLockMgr::RequestUnlock);
  462. return RequestUnlockHelper(pDevice, bClosePort, GetCurrentThreadId());
  463. }
  464. /**************************************************************************\
  465. * RequestUnlockHelper
  466. *
  467. * Helper used to unlock a device lock. It clears the appropriate
  468. * lock information stored with the device.
  469. *
  470. * Arguments:
  471. *
  472. * pDevice - A pointer to the STI device
  473. * ulTimeout - The max. amount of time to wait for a lock
  474. * bInServerProcess- Indicates whether we're in the server process
  475. *
  476. * Return Value:
  477. *
  478. * Status
  479. *
  480. * History:
  481. *
  482. * 12/06/1999 Original Version
  483. *
  484. \**************************************************************************/
  485. HRESULT StiLockMgr::RequestUnlockHelper(ACTIVE_DEVICE *pDevice, BOOL bInServerProcess, DWORD dwClientThreadId)
  486. {
  487. DBG_FN(StiLockMgr::RequestUnlockHelper);
  488. HRESULT hr = S_OK;
  489. LockInfo *pLockInfo = NULL;
  490. BOOL bDidNotUnlock = TRUE;
  491. hr = CheckDeviceInfo(pDevice);
  492. if (FAILED(hr)) {
  493. DBG_ERR(("StiLockMgr::RequestUnlockHelper, CheclDeviceInfo() failed with hr=%x", hr));
  494. return hr;
  495. }
  496. pLockInfo = (LockInfo*) pDevice->m_pLockInfo;
  497. //
  498. // Special case exists if device has been marked for removal. In this
  499. // case, we want to unlock now (definitely not schedule for later).
  500. //
  501. if (pDevice->QueryFlags() & STIMON_AD_FLAG_REMOVING) {
  502. if (pLockInfo) {
  503. if (pLockInfo->bDeviceIsLocked) {
  504. UnlockDevice(pDevice);
  505. }
  506. hr = ClearLockInfo(pLockInfo);
  507. if (FAILED(hr)) {
  508. DBG_ERR(("StiLockMgr::RequestUnlockHelper, could not clear lock information"));
  509. }
  510. }
  511. return hr;
  512. }
  513. //
  514. // Decrement the usage count. If usage count == 0, then reset the
  515. // lock information, but don't actually unlock. (To improve (burst)
  516. // performance, we will hold onto the lock for a maximum idle period
  517. // specified by pLockInfo->lHoldingTime). Only if lHoldingTime is 0,
  518. // do we unlock straightaway.
  519. //
  520. if (pLockInfo->lInUse > 0) {
  521. pLockInfo->lInUse--;
  522. }
  523. if (pLockInfo->lInUse <= 0) {
  524. //
  525. // Only unlock if holding is 0 and we're in the server process.
  526. //
  527. if ((pLockInfo->lHoldingTime == 0) && bInServerProcess) {
  528. UnlockDevice(pDevice);
  529. bDidNotUnlock = FALSE;
  530. }
  531. hr = ClearLockInfo(pLockInfo);
  532. if (FAILED(hr)) {
  533. DBG_ERR(("StiLockMgr::RequestUnlockHelper, failed to clear lock information"));
  534. }
  535. //
  536. // If we're not in the server process, nothing left to do,
  537. // so return.
  538. //
  539. if (!bInServerProcess) {
  540. pLockInfo->bDeviceIsLocked = FALSE;
  541. return hr;
  542. }
  543. }
  544. //
  545. // If we did not unlock the device, then schedule the unlock
  546. // callback to unlock it later.
  547. //
  548. if (bDidNotUnlock) {
  549. m_lSchedWaitTime = pLockInfo->lHoldingTime;
  550. if (!m_bSched) {
  551. if (ScheduleWorkItem((PFN_SCHED_CALLBACK) UnlockTimedCallback,
  552. this,
  553. m_lSchedWaitTime,
  554. NULL)) {
  555. m_bSched = TRUE;
  556. }
  557. }
  558. }
  559. return hr;
  560. }
  561. /**************************************************************************\
  562. * CreateLockInfo
  563. *
  564. * Allocates and initializes a new LockInfo struct.
  565. *
  566. * Arguments:
  567. *
  568. * pDevice - The STI ACTIVE_DEVICE object.
  569. *
  570. * Return Value:
  571. *
  572. * Status
  573. *
  574. * History:
  575. *
  576. * 15/1/1999 Original Version
  577. *
  578. \**************************************************************************/
  579. HRESULT StiLockMgr::CreateLockInfo(ACTIVE_DEVICE *pDevice)
  580. {
  581. DBG_FN(StiLockMgr::CreateLockInfo);
  582. HRESULT hr = S_OK;
  583. LockInfo *pLockInfo = NULL;
  584. USES_CONVERSION;
  585. //
  586. // Allocate memory for the structure
  587. //
  588. pLockInfo = (LockInfo*) LocalAlloc(LPTR, sizeof(LockInfo));
  589. if (pLockInfo) {
  590. memset(pLockInfo, 0, sizeof(LockInfo));
  591. pLockInfo->hDeviceIsFree = CreateEvent(NULL, FALSE, TRUE, NULL);
  592. if (pLockInfo->hDeviceIsFree) {
  593. //
  594. // Get any relevant lock information
  595. //
  596. pLockInfo->lHoldingTime = pDevice->m_DrvWrapper.getLockHoldingTime();
  597. DBG_TRC(("StiLockMgr::CreateLockInfo, Lock holding time set to %d for device %S",
  598. pLockInfo->lHoldingTime,
  599. pDevice->GetDeviceID()));
  600. pLockInfo->lTimeLeft = pLockInfo->lHoldingTime;
  601. //
  602. // Everything's OK, so set the device's lock information
  603. //
  604. pDevice->m_pLockInfo = pLockInfo;
  605. } else {
  606. DBG_ERR(("StiLockMgr::CreateLockInfo, could not create event"));
  607. LocalFree(pLockInfo);
  608. hr = E_FAIL;
  609. }
  610. } else {
  611. DBG_ERR(("StiLockMgr::CreateLockInfo, out of memory"));
  612. hr = E_OUTOFMEMORY;
  613. }
  614. return hr;
  615. }
  616. /**************************************************************************\
  617. * ClearLockInfo
  618. *
  619. * Clears information stored in a lockinfo struct. Also signals that the
  620. * device is free. Note: it does not unlock the device.
  621. *
  622. * Arguments:
  623. *
  624. * pLockInfo - a pointer to the device's LockInfo struct.
  625. *
  626. * Return Value:
  627. *
  628. * Status
  629. *
  630. * History:
  631. *
  632. * 15/1/1999 Original Version
  633. *
  634. \**************************************************************************/
  635. HRESULT StiLockMgr::ClearLockInfo(LockInfo *pLockInfo)
  636. {
  637. DBG_FN(StiLockMgr::ClearLockInfo);
  638. //
  639. // Note: As much lock information is reset as can be done without
  640. // unlocking the device. This method is only called when lInuse
  641. // is 0, indicating that the device is no longer being actively used.
  642. //
  643. InterlockedExchange((LONG*)&pLockInfo->dwThreadId, 0);
  644. pLockInfo->lInUse = 0;
  645. //
  646. // Signal the device is free.
  647. //
  648. if (SetEvent(pLockInfo->hDeviceIsFree)) {
  649. return S_OK;
  650. } else {
  651. DBG_ERR(("StiLockMgr::ClearLockInfo, could not signal event"));
  652. return E_FAIL;
  653. }
  654. }
  655. /**************************************************************************\
  656. * LockDevice
  657. *
  658. * Calls the USD to lock itsself and updates the relevant Lock information.
  659. *
  660. * Arguments:
  661. *
  662. * pDevice - pointer to the ACTIVE_DEVICE node
  663. *
  664. * Return Value:
  665. *
  666. * Status
  667. *
  668. * History:
  669. *
  670. * 15/1/1999 Original Version
  671. *
  672. \**************************************************************************/
  673. HRESULT StiLockMgr::LockDevice(ACTIVE_DEVICE *pDevice)
  674. {
  675. DBG_FN(StiLockMgr::LockDevice);
  676. HRESULT hr = S_OK;
  677. LockInfo *pLockInfo = (LockInfo*)pDevice->m_pLockInfo;
  678. IStiUSD *pIStiUSD = NULL;
  679. __try {
  680. //
  681. // Check whether device is currently locked. We know that the device
  682. // is not busy, so it is safe to simply keep the lock open. This is how
  683. // we improve "burst" performance.
  684. //
  685. if (!pLockInfo->bDeviceIsLocked) {
  686. hr = pDevice->m_DrvWrapper.STI_LockDevice();
  687. } else {
  688. DBG_TRC(("StiLockMgr::LockDevice, Device is already locked."));
  689. }
  690. if (hr == S_OK) {
  691. pLockInfo->bDeviceIsLocked = TRUE;
  692. } else {
  693. HRESULT hres = E_FAIL;
  694. pLockInfo->bDeviceIsLocked = FALSE;
  695. hres = ClearLockInfo(pLockInfo);
  696. DBG_ERR(("StiLockMgr::LockDevice, USD error locking the device (0x%X)", hr));
  697. }
  698. }
  699. __except (EXCEPTION_EXECUTE_HANDLER) {
  700. DBG_ERR(("StiLockMgr::LockDevice, exception"));
  701. hr = HRESULT_FROM_WIN32(GetExceptionCode());
  702. }
  703. return hr;
  704. }
  705. /**************************************************************************\
  706. * UnlockDevice
  707. *
  708. * Calls the USD to unlock itsself and updates the relevant Lock
  709. * information.
  710. *
  711. * Arguments:
  712. *
  713. * pDevice - pointer to the ACTIVE_DEVICE node
  714. *
  715. * Return Value:
  716. *
  717. * Status
  718. *
  719. * History:
  720. *
  721. * 15/1/1999 Original Version
  722. *
  723. \**************************************************************************/
  724. HRESULT StiLockMgr::UnlockDevice(ACTIVE_DEVICE *pDevice)
  725. {
  726. DBG_FN(StiLockMgr::UnlockDevice);
  727. HRESULT hr = S_OK;
  728. LockInfo *pLockInfo = (LockInfo*)pDevice->m_pLockInfo;
  729. IStiUSD *pIStiUSD = NULL;
  730. __try {
  731. //
  732. // Unlock the device and mark that device has been unlocked.
  733. //
  734. hr = pDevice->m_DrvWrapper.STI_UnLockDevice();
  735. if (SUCCEEDED(hr)) {
  736. pLockInfo->bDeviceIsLocked = FALSE;
  737. }
  738. if (hr != S_OK) {
  739. pLockInfo->bDeviceIsLocked = TRUE;
  740. DBG_ERR(("StiLockMgr::UnlockDevice, USD error unlocking the device"));
  741. }
  742. }
  743. __except (EXCEPTION_EXECUTE_HANDLER) {
  744. DBG_ERR(("StiLockMgr::UnlockDevice, exception"));
  745. hr = HRESULT_FROM_WIN32(GetExceptionCode());
  746. }
  747. return hr;
  748. }
  749. HRESULT StiLockMgr::CheckDeviceInfo(ACTIVE_DEVICE *pDevice)
  750. {
  751. HRESULT hr = E_FAIL;
  752. TAKE_ACTIVE_DEVICE _tad(pDevice);
  753. if (!pDevice) {
  754. DBG_ERR(("StiLockMgr::CheckDeviceInfo, pDevice is NULL!"));
  755. return E_POINTER;
  756. }
  757. //
  758. // Check whether the device is valid and is not being removed
  759. //
  760. if (pDevice->IsValid() && !(pDevice->QueryFlags() & STIMON_AD_FLAG_REMOVING)) {
  761. //
  762. // Check whether lock information for this device exists yet. If
  763. // not, create a new LockInfo struct for this device.
  764. //
  765. if (pDevice->m_pLockInfo) {
  766. hr = S_OK;
  767. } else {
  768. hr = CreateLockInfo(pDevice);
  769. }
  770. } else {
  771. DBG_ERR(("StiLockMgr::CheckDeviceInfo, ACTIVE_DEVICE is not valid!"));
  772. hr = E_FAIL;
  773. }
  774. return hr;
  775. }
  776. #ifdef USE_ROT
  777. /**************************************************************************\
  778. * WriteCookieNameToRegistry
  779. *
  780. * Writes the specified name to the registry. This is so clients know what
  781. * name to bind to when trying to get this instance of the Lock Manager
  782. * from the ROT (see Initialize).
  783. *
  784. * Arguments:
  785. *
  786. * szCookieName - string containing the cookie name
  787. *
  788. * Return Value:
  789. *
  790. * Status
  791. *
  792. * History:
  793. *
  794. * 15/1/1999 Original Version
  795. *
  796. \**************************************************************************/
  797. HRESULT StiLockMgr::WriteCookieNameToRegistry(CHAR *szCookieName)
  798. {
  799. HRESULT hr;
  800. HKEY hKey;
  801. LONG lErr;
  802. DWORD dwType = REG_SZ;
  803. DWORD dwSize = strlen(szCookieName) + 1;
  804. //
  805. // Write Lock Manager instance name to the registry.
  806. //
  807. lErr = ::RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  808. REGSTR_PATH_STICONTROL,
  809. 0,
  810. TEXT(""),
  811. REG_OPTION_VOLATILE,
  812. KEY_WRITE,
  813. NULL,
  814. &hKey,
  815. NULL);
  816. if (lErr == ERROR_SUCCESS) {
  817. lErr = ::RegSetValueExA(hKey,
  818. REGSTR_VAL_LOCK_MGR_COOKIE_A,
  819. 0,
  820. dwType,
  821. (BYTE*) szCookieName,
  822. dwSize);
  823. if (lErr != ERROR_SUCCESS) {
  824. DBG_ERR(("StiLockMgr::WriteCookieNameToRegistry, could not write to registry"));
  825. } else {
  826. return S_OK;
  827. }
  828. RegCloseKey(hKey);
  829. }
  830. return E_FAIL;
  831. }
  832. /**************************************************************************\
  833. * DeleteCookieFromRegistry
  834. *
  835. * Delete the cookie name from the registry. It is only needed while this
  836. * instance of the lock manager is running.
  837. *
  838. * Arguments:
  839. *
  840. * Return Value:
  841. *
  842. * Status
  843. *
  844. * History:
  845. *
  846. * 15/1/1999 Original Version
  847. *
  848. \**************************************************************************/
  849. VOID StiLockMgr::DeleteCookieFromRegistry()
  850. {
  851. HRESULT hr;
  852. HKEY hKey;
  853. LONG lErr;
  854. //
  855. // Remove Lock Manager instance name from registry.
  856. //
  857. lErr = ::RegOpenKeyEx(HKEY_DYN_DATA,
  858. REGSTR_PATH_STICONTROL,
  859. 0,
  860. KEY_WRITE,
  861. &hKey);
  862. if (lErr == ERROR_SUCCESS) {
  863. lErr = ::RegDeleteValue(hKey,
  864. REGSTR_VAL_LOCK_MGR_COOKIE);
  865. RegCloseKey(hKey);
  866. }
  867. }
  868. #endif
  869. /**************************************************************************\
  870. * AutoUnlock
  871. *
  872. * Scans the device list to check whether any device's idle time has
  873. * expired and needs to be unlocked.
  874. *
  875. * Arguments:
  876. *
  877. * Return Value:
  878. *
  879. * History:
  880. *
  881. * 15/1/1999 Original Version
  882. *
  883. \**************************************************************************/
  884. VOID StiLockMgr::AutoUnlock()
  885. {
  886. EnumContext Ctx;
  887. m_bSched = FALSE;
  888. //
  889. // Enumerate through device list. At each locked device, update it's
  890. // lTimeLeft. If lTimeLeft has expired, unlock the device.
  891. // If not, mark that unlock callback needs to be scheduled.
  892. //
  893. // This logic is done in the UpdateLockInfoStatus method called by the
  894. // EnumDeviceCallback function on each device.
  895. //
  896. Ctx.This = this;
  897. Ctx.lShortestWaitTime = LONG_MAX;
  898. Ctx.bMustSchedule = FALSE;
  899. g_pDevMan->EnumerateActiveDevicesWithCallback(EnumDeviceCallback, &Ctx);
  900. //
  901. // Schedule next callback, if needed
  902. //
  903. if (Ctx.bMustSchedule && !m_bSched) {
  904. m_bSched = TRUE;
  905. m_lSchedWaitTime = Ctx.lShortestWaitTime;
  906. if (ScheduleWorkItem((PFN_SCHED_CALLBACK) UnlockTimedCallback,
  907. this,
  908. m_lSchedWaitTime,
  909. NULL)) {
  910. return;
  911. } else {
  912. DBG_ERR(("StiLockMgr::AutoUnlock, failed to schedule UnlockTimedCallback"));
  913. }
  914. }
  915. }
  916. /**************************************************************************\
  917. * UpdateLockInfoStatus
  918. *
  919. * Updates a device's lock information. If the device's idle time has
  920. * expired, it is unlocked. If it is still busy, it's amount of idle time
  921. * left is updated.
  922. *
  923. * Arguments:
  924. *
  925. * pDevice - A pointer to the ACTIVE_DEVICE node.
  926. * pWaitTime - This is a pointer to the shortest wait time left.
  927. * This is used as the time the AutoUnlock() method
  928. * needs to re-schedule itsself.
  929. * pbMustSchedule - A pointer to a BOOL indicating whether the
  930. * AutoUnlock() needs to be re-scheduled.
  931. *
  932. * Return Value:
  933. *
  934. * History:
  935. *
  936. * 15/1/1999 Original Version
  937. *
  938. \**************************************************************************/
  939. VOID StiLockMgr::UpdateLockInfoStatus(ACTIVE_DEVICE *pDevice, LONG *pWaitTime, BOOL *pbMustSchedule)
  940. {
  941. DBG_FN(UpdateLockInfoStatus);
  942. LockInfo *pLockInfo = NULL;
  943. DWORD dwWait;
  944. HRESULT hr = S_OK;;
  945. //
  946. // NOTE: Do not modify pWaitTime or pbMustSchedule unless a new wait
  947. // time is scheduled (see where pLockInfo->lTimeLeft < *pWaitTime)
  948. //
  949. //
  950. // Get a pointer to the lock information
  951. //
  952. if (pDevice) {
  953. pLockInfo = (LockInfo*) pDevice->m_pLockInfo;
  954. }
  955. if (!pLockInfo) {
  956. return;
  957. }
  958. //
  959. // Check whether device is free. If the device is busy, don't bother
  960. // scheduling a callback, since it will be rescheduled if needed when
  961. // the call to RequestUnlock is made.
  962. //
  963. dwWait = WaitForSingleObject(pLockInfo->hDeviceIsFree, 0);
  964. if (dwWait == WAIT_OBJECT_0) {
  965. //
  966. // Check whether device is locked (we're only interested in devices
  967. // that are locked).
  968. //
  969. if (pLockInfo->bDeviceIsLocked) {
  970. //
  971. // Decrease the amount of time left. If lTimeLeft <= 0, then no
  972. // idle time remains and device should be unlocked.
  973. //
  974. // If time does remain, check whether it is smaller than
  975. // the current wait time (pWaitTime). If it is smaller, mark
  976. // that this is the new wait time, and that the unlock callback
  977. // must be scheduled to unlock this later.
  978. //
  979. pLockInfo->lTimeLeft -= m_lSchedWaitTime;
  980. if (pLockInfo->lTimeLeft <= 0) {
  981. pLockInfo->lTimeLeft = 0;
  982. hr = UnlockDevice(pDevice);
  983. if (SUCCEEDED(hr)) {
  984. hr = ClearLockInfo(pLockInfo);
  985. return;
  986. }
  987. } else {
  988. if (pLockInfo->lTimeLeft < *pWaitTime) {
  989. *pWaitTime = pLockInfo->lTimeLeft;
  990. }
  991. *pbMustSchedule = TRUE;
  992. }
  993. }
  994. //
  995. // We are finished updating the information, so re-signal
  996. // that device is free.
  997. //
  998. SetEvent(pLockInfo->hDeviceIsFree);
  999. }
  1000. }
  1001. /**************************************************************************\
  1002. * EnumDeviceCallback
  1003. *
  1004. * This function is called once for every device in the ACTIVE_DEVICE
  1005. * enumeration.
  1006. *
  1007. * Arguments:
  1008. *
  1009. * pDevice - A pointer to the ACTIVE_DEVICE node.
  1010. * pContext - This is a pointer to an enumeration context.
  1011. * The context contains a pointer to the Lock Manager,
  1012. * the shortest wait time, and a bool indicating whether
  1013. * AutoUnlock needs to be re-scheduled.
  1014. *
  1015. * Return Value:
  1016. *
  1017. * History:
  1018. *
  1019. * 15/1/1999 Original Version
  1020. *
  1021. \**************************************************************************/
  1022. VOID WINAPI EnumDeviceCallback(ACTIVE_DEVICE *pDevice, VOID *pContext)
  1023. {
  1024. DBG_FN(EnumDeviceCallback);
  1025. EnumContext *pCtx = (EnumContext*) pContext;
  1026. if (pCtx) {
  1027. //
  1028. // Update the lock status on this device
  1029. //
  1030. pCtx->This->UpdateLockInfoStatus(pDevice,
  1031. &pCtx->lShortestWaitTime,
  1032. &pCtx->bMustSchedule);
  1033. }
  1034. }
  1035. /**************************************************************************\
  1036. * UnlockTimedCallback
  1037. *
  1038. * This function gets called when a lock is still active and may need to
  1039. * be unlocked if the amount of idle time expires.
  1040. *
  1041. * Arguments:
  1042. *
  1043. * pArg - A pointer to the Lock Manager.
  1044. *
  1045. * Return Value:
  1046. *
  1047. * History:
  1048. *
  1049. * 15/1/1999 Original Version
  1050. *
  1051. \**************************************************************************/
  1052. VOID WINAPI UnlockTimedCallback(VOID *pArg)
  1053. {
  1054. DBG_FN(UnlockTimedCallback);
  1055. StiLockMgr *pLockMgr = (StiLockMgr*) pArg;
  1056. if (pLockMgr) {
  1057. __try {
  1058. pLockMgr->AutoUnlock();
  1059. }
  1060. __except (EXCEPTION_EXECUTE_HANDLER) {
  1061. #ifdef DEBUG
  1062. OutputDebugStringA("Exception in UnlockTimedCallback");
  1063. #endif
  1064. }
  1065. }
  1066. }