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.

365 lines
9.6 KiB

  1. #include "hnotif.h"
  2. #include "hwdev.h"
  3. #include "misc.h"
  4. #include "mischlpr.h"
  5. #include "dbg.h"
  6. #include "tfids.h"
  7. #include <ioevent.h>
  8. #include <dbt.h>
  9. #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0]))
  10. HRESULT CHandleNotif::Init(LPCWSTR pszElemName)
  11. {
  12. return _SetName(pszElemName);
  13. }
  14. HRESULT CHandleNotif::InitNotif(CHandleNotifTarget* phnt)
  15. {
  16. ASSERT(!_phnt);
  17. _phnt = phnt;
  18. return _Register();
  19. }
  20. HDEVNOTIFY CHandleNotif::GetDeviceNotifyHandle()
  21. {
  22. return _hdevnotify;
  23. }
  24. CHandleNotifTarget* CHandleNotif::GetHandleNotifTarget()
  25. {
  26. return _phnt;
  27. }
  28. //
  29. // Application gets DBT_DEVICEQUERYREMOVE message with the handle of the device
  30. // that's being removed. It should just close the handle to the device.
  31. //
  32. // If everything goes OK it gets DBT_DEVICEREMOVEPENDING to notify that remove
  33. // is complete. Here it unregisters the notification that it did on the handle.
  34. //
  35. // If query-remove fails because somebody else in the system vetoed it, it gets
  36. // DBT_QUERYREMOVEFAILED. Here it should first unregister the notification and
  37. // reopen the device (if it's still interested) and register again for device
  38. // change notification (DBT_DEVTYP_HANDLE) on the new handle.
  39. //
  40. HRESULT CHandleNotif::HNHandleEvent(DEV_BROADCAST_HANDLE* UNREF_PARAM(pdbh),
  41. DWORD dwEventType, BOOL* pfSurpriseRemoval)
  42. {
  43. HRESULT hres;
  44. *pfSurpriseRemoval = FALSE;
  45. switch (dwEventType)
  46. {
  47. case DBT_DEVICEQUERYREMOVE:
  48. TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_DEVICEQUERYREMOVE for '%s'"), _pszElemName);
  49. hres = S_OK;
  50. break;
  51. case DBT_DEVICEREMOVEPENDING:
  52. TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_DEVICEREMOVEPENDING for '%s'"), _pszElemName);
  53. _fSurpriseRemoval = FALSE;
  54. hres = _Unregister();
  55. break;
  56. case DBT_DEVICEQUERYREMOVEFAILED:
  57. TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_DEVICEQUERYREMOVEFAILED for '%s'"), _pszElemName);
  58. _fSurpriseRemoval = TRUE;
  59. hres = _Unregister();
  60. if (SUCCEEDED(hres))
  61. {
  62. hres = _Register();
  63. }
  64. break;
  65. case DBT_DEVICEREMOVECOMPLETE:
  66. TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_DEVICEREMOVECOMPLETE for '%s'"), _pszElemName);
  67. if (_fSurpriseRemoval)
  68. {
  69. *pfSurpriseRemoval = TRUE;
  70. hres = _Unregister();
  71. }
  72. hres = S_FALSE;
  73. break;
  74. default:
  75. hres = S_FALSE;
  76. break;
  77. }
  78. return hres;
  79. }
  80. //static
  81. HRESULT CHandleNotif::_HandleDeviceArrivalRemoval(
  82. DEV_BROADCAST_HANDLE* UNREF_PARAM(pdbh), DWORD UNREF_PARAM(dwEventType),
  83. CNamedElem* UNREF_PARAM(pelem))
  84. {
  85. #ifdef ENABLE_SURPRISEREMOVAL
  86. HRESULT hres = S_OK;
  87. BOOL fSurpriseRemoval = FALSE;
  88. CHandleNotif* phn = (CHandleNotif*)pelem;
  89. CHandleNotifTarget* phnt = phn->GetHandleNotifTarget();
  90. if (phnt)
  91. {
  92. if (fSurpriseRemoval && phnt->HNTIsSurpriseRemovalAware())
  93. {
  94. // Use me!
  95. DWORD cchReq;
  96. WCHAR szDeviceIntfID[MAX_DEVICEID];
  97. WCHAR szFriendlyName[30];
  98. hres = pelem->GetName(szDeviceIntfID,
  99. ARRAYSIZE(szDeviceIntfID), &cchReq);
  100. if (SUCCEEDED(hres))
  101. {
  102. CHWDeviceInst* phwdevinst;
  103. CNamedElem* pelemToRelease;
  104. hres = _GetHWDeviceInstFromDeviceOrVolumeIntfID(
  105. szDeviceIntfID, &phwdevinst, &pelemToRelease);
  106. if (SUCCEEDED(hres) && (S_FALSE != hres))
  107. {
  108. hres = phwdevinst->GetFriendlyName(szFriendlyName,
  109. ARRAYSIZE(szFriendlyName));
  110. if (SUCCEEDED(hres) && (S_FALSE != hres))
  111. {
  112. TRACE(TF_SHHWDTCTDTCT, TEXT("! ! ! Surprise removal for: '%s' ! ! !"),
  113. szFriendlyName);
  114. }
  115. else
  116. {
  117. TRACE(TF_SHHWDTCTDTCT, TEXT("! ! ! Surprise removal for (no FriendlyName): '%s' ! ! !"),
  118. szDeviceIntfID);
  119. }
  120. pelemToRelease->RCRelease();
  121. }
  122. }
  123. }
  124. }
  125. #endif
  126. return S_OK;
  127. }
  128. //static
  129. HRESULT CHandleNotif::_HandleDeviceLockUnlock(DEV_BROADCAST_HANDLE* pdbh,
  130. DWORD, CNamedElem* pelem)
  131. {
  132. HRESULT hres = S_OK;
  133. CHandleNotif* phn = (CHandleNotif*)pelem;
  134. if (GUID_IO_VOLUME_LOCK == pdbh->dbch_eventguid)
  135. {
  136. #ifdef DEBUG
  137. TRACE(TF_SHHWDTCTDTCT,
  138. TEXT("DBT_CUSTOMEVENT + GUID_IO_VOLUME_LOCK for '%s'"),
  139. pelem->DbgGetName());
  140. #endif
  141. // nothing to do
  142. ++(phn->_cLockAttempts);
  143. }
  144. else
  145. {
  146. if (GUID_IO_VOLUME_LOCK_FAILED == pdbh->dbch_eventguid)
  147. {
  148. #ifdef DEBUG
  149. TRACE(TF_SHHWDTCTDTCT,
  150. TEXT("DBT_CUSTOMEVENT + GUID_IO_VOLUME_LOCK_FAILED for '%s'"),
  151. pelem->DbgGetName());
  152. #endif
  153. --(phn->_cLockAttempts);
  154. if (0 == (phn->_cLockAttempts))
  155. {
  156. hres = phn->_Unregister();
  157. if (SUCCEEDED(hres))
  158. {
  159. hres = phn->_Register();
  160. }
  161. }
  162. }
  163. else
  164. {
  165. if (GUID_IO_VOLUME_UNLOCK == pdbh->dbch_eventguid)
  166. {
  167. #ifdef DEBUG
  168. TRACE(TF_SHHWDTCTDTCT,
  169. TEXT("DBT_CUSTOMEVENT + GUID_IO_VOLUME_UNLOCK for '%s'"),
  170. pelem->DbgGetName());
  171. #endif
  172. // Play it safe...
  173. (phn->_cLockAttempts) = 0;
  174. hres = phn->_Unregister();
  175. if (SUCCEEDED(hres))
  176. {
  177. hres = phn->_Register();
  178. }
  179. }
  180. }
  181. }
  182. return hres;
  183. }
  184. //static
  185. HRESULT CHandleNotif::HandleBroadcastHandleEvent(DEV_BROADCAST_HANDLE* pdbh,
  186. DWORD dwEventType)
  187. {
  188. CNamedElemList* pnel;
  189. HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_HANDLENOTIF,
  190. &pnel);
  191. if (S_OK == hres)
  192. {
  193. // Find the elem in the list
  194. CNamedElemEnum* penum;
  195. hres = pnel->GetEnum(&penum);
  196. if (SUCCEEDED(hres))
  197. {
  198. CNamedElem* pelem;
  199. BOOL fFoundIt = FALSE;
  200. while (!fFoundIt && SUCCEEDED(hres = penum->Next(&pelem)) &&
  201. (S_FALSE != hres))
  202. {
  203. CHandleNotif* phn = (CHandleNotif*)pelem;
  204. if (phn->GetDeviceNotifyHandle() == pdbh->dbch_hdevnotify)
  205. {
  206. // Found it!
  207. BOOL fSurpriseRemoval;
  208. CHandleNotifTarget* phnt = phn->GetHandleNotifTarget();
  209. hres = phn->HNHandleEvent(pdbh, dwEventType, &fSurpriseRemoval);
  210. if (SUCCEEDED(hres))
  211. {
  212. if ((GUID_IO_MEDIA_ARRIVAL == pdbh->dbch_eventguid) ||
  213. (GUID_IO_MEDIA_REMOVAL == pdbh->dbch_eventguid))
  214. {
  215. hres = _HandleDeviceArrivalRemoval(pdbh, dwEventType,
  216. pelem);
  217. }
  218. else
  219. {
  220. if ((GUID_IO_VOLUME_LOCK == pdbh->dbch_eventguid) ||
  221. (GUID_IO_VOLUME_LOCK_FAILED == pdbh->dbch_eventguid) ||
  222. (GUID_IO_VOLUME_UNLOCK == pdbh->dbch_eventguid))
  223. {
  224. hres = _HandleDeviceLockUnlock(pdbh, dwEventType,
  225. pelem);
  226. }
  227. }
  228. if (SUCCEEDED(hres))
  229. {
  230. hres = phnt->HNTHandleEvent(pdbh, dwEventType);
  231. // phnt has the same life span as pelem, no need to
  232. // RCAddRef/RCRelease
  233. }
  234. }
  235. fFoundIt = TRUE;
  236. }
  237. pelem->RCRelease();
  238. }
  239. penum->RCRelease();
  240. }
  241. pnel->RCRelease();
  242. }
  243. return hres;
  244. }
  245. ///////////////////////////////////////////////////////////////////////////////
  246. //
  247. //static
  248. HRESULT CHandleNotif::Create(CNamedElem** ppelem)
  249. {
  250. HRESULT hres = S_OK;
  251. *ppelem = new CHandleNotif();
  252. if (!(*ppelem))
  253. {
  254. hres = E_OUTOFMEMORY;
  255. }
  256. return hres;
  257. }
  258. ///////////////////////////////////////////////////////////////////////////////
  259. //
  260. HRESULT CHandleNotif::_Register()
  261. {
  262. HRESULT hres = S_FALSE;
  263. DEV_BROADCAST_HANDLE dbhNotifFilter = {0};
  264. dbhNotifFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
  265. dbhNotifFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
  266. dbhNotifFilter.dbch_handle = _GetDeviceHandle(_pszElemName,
  267. FILE_READ_ATTRIBUTES);
  268. if (INVALID_HANDLE_VALUE != dbhNotifFilter.dbch_handle)
  269. {
  270. hres = CHWEventDetectorHelper::RegisterDeviceNotification(
  271. &dbhNotifFilter, &_hdevnotify, FALSE);
  272. _CloseDeviceHandle(dbhNotifFilter.dbch_handle);
  273. }
  274. TRACE(TF_SHHWDTCTDTCT, TEXT("--- Registered for '%s'"), _pszElemName);
  275. return hres;
  276. }
  277. HRESULT CHandleNotif::_Unregister()
  278. {
  279. if (_hdevnotify)
  280. {
  281. UnregisterDeviceNotification(_hdevnotify);
  282. _hdevnotify = NULL;
  283. TRACE(TF_SHHWDTCTDTCT, TEXT("--- UNRegistered for '%s'"), _pszElemName);
  284. }
  285. return S_OK;
  286. }
  287. ///////////////////////////////////////////////////////////////////////////////
  288. //
  289. CHandleNotif::CHandleNotif() : _hdevnotify(NULL), _phnt(NULL),
  290. _fSurpriseRemoval(TRUE), _cLockAttempts(0)
  291. {}
  292. CHandleNotif::~CHandleNotif()
  293. {
  294. _Unregister();
  295. }