#include "hnotif.h" #include "hwdev.h" #include "misc.h" #include "mischlpr.h" #include "dbg.h" #include "tfids.h" #include #include #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0])) HRESULT CHandleNotif::Init(LPCWSTR pszElemName) { return _SetName(pszElemName); } HRESULT CHandleNotif::InitNotif(CHandleNotifTarget* phnt) { ASSERT(!_phnt); _phnt = phnt; return _Register(); } HDEVNOTIFY CHandleNotif::GetDeviceNotifyHandle() { return _hdevnotify; } CHandleNotifTarget* CHandleNotif::GetHandleNotifTarget() { return _phnt; } // // Application gets DBT_DEVICEQUERYREMOVE message with the handle of the device // that's being removed. It should just close the handle to the device. // // If everything goes OK it gets DBT_DEVICEREMOVEPENDING to notify that remove // is complete. Here it unregisters the notification that it did on the handle. // // If query-remove fails because somebody else in the system vetoed it, it gets // DBT_QUERYREMOVEFAILED. Here it should first unregister the notification and // reopen the device (if it's still interested) and register again for device // change notification (DBT_DEVTYP_HANDLE) on the new handle. // HRESULT CHandleNotif::HNHandleEvent(DEV_BROADCAST_HANDLE* UNREF_PARAM(pdbh), DWORD dwEventType, BOOL* pfSurpriseRemoval) { HRESULT hres; *pfSurpriseRemoval = FALSE; switch (dwEventType) { case DBT_DEVICEQUERYREMOVE: TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_DEVICEQUERYREMOVE for '%s'"), _pszElemName); hres = S_OK; break; case DBT_DEVICEREMOVEPENDING: TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_DEVICEREMOVEPENDING for '%s'"), _pszElemName); _fSurpriseRemoval = FALSE; hres = _Unregister(); break; case DBT_DEVICEQUERYREMOVEFAILED: TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_DEVICEQUERYREMOVEFAILED for '%s'"), _pszElemName); _fSurpriseRemoval = TRUE; hres = _Unregister(); if (SUCCEEDED(hres)) { hres = _Register(); } break; case DBT_DEVICEREMOVECOMPLETE: TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_DEVICEREMOVECOMPLETE for '%s'"), _pszElemName); if (_fSurpriseRemoval) { *pfSurpriseRemoval = TRUE; hres = _Unregister(); } hres = S_FALSE; break; default: hres = S_FALSE; break; } return hres; } //static HRESULT CHandleNotif::_HandleDeviceArrivalRemoval( DEV_BROADCAST_HANDLE* UNREF_PARAM(pdbh), DWORD UNREF_PARAM(dwEventType), CNamedElem* UNREF_PARAM(pelem)) { #ifdef ENABLE_SURPRISEREMOVAL HRESULT hres = S_OK; BOOL fSurpriseRemoval = FALSE; CHandleNotif* phn = (CHandleNotif*)pelem; CHandleNotifTarget* phnt = phn->GetHandleNotifTarget(); if (phnt) { if (fSurpriseRemoval && phnt->HNTIsSurpriseRemovalAware()) { // Use me! DWORD cchReq; WCHAR szDeviceIntfID[MAX_DEVICEID]; WCHAR szFriendlyName[30]; hres = pelem->GetName(szDeviceIntfID, ARRAYSIZE(szDeviceIntfID), &cchReq); if (SUCCEEDED(hres)) { CHWDeviceInst* phwdevinst; CNamedElem* pelemToRelease; hres = _GetHWDeviceInstFromDeviceOrVolumeIntfID( szDeviceIntfID, &phwdevinst, &pelemToRelease); if (SUCCEEDED(hres) && (S_FALSE != hres)) { hres = phwdevinst->GetFriendlyName(szFriendlyName, ARRAYSIZE(szFriendlyName)); if (SUCCEEDED(hres) && (S_FALSE != hres)) { TRACE(TF_SHHWDTCTDTCT, TEXT("! ! ! Surprise removal for: '%s' ! ! !"), szFriendlyName); } else { TRACE(TF_SHHWDTCTDTCT, TEXT("! ! ! Surprise removal for (no FriendlyName): '%s' ! ! !"), szDeviceIntfID); } pelemToRelease->RCRelease(); } } } } #endif return S_OK; } //static HRESULT CHandleNotif::_HandleDeviceLockUnlock(DEV_BROADCAST_HANDLE* pdbh, DWORD, CNamedElem* pelem) { HRESULT hres = S_OK; CHandleNotif* phn = (CHandleNotif*)pelem; if (GUID_IO_VOLUME_LOCK == pdbh->dbch_eventguid) { #ifdef DEBUG TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_CUSTOMEVENT + GUID_IO_VOLUME_LOCK for '%s'"), pelem->DbgGetName()); #endif // nothing to do ++(phn->_cLockAttempts); } else { if (GUID_IO_VOLUME_LOCK_FAILED == pdbh->dbch_eventguid) { #ifdef DEBUG TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_CUSTOMEVENT + GUID_IO_VOLUME_LOCK_FAILED for '%s'"), pelem->DbgGetName()); #endif --(phn->_cLockAttempts); if (0 == (phn->_cLockAttempts)) { hres = phn->_Unregister(); if (SUCCEEDED(hres)) { hres = phn->_Register(); } } } else { if (GUID_IO_VOLUME_UNLOCK == pdbh->dbch_eventguid) { #ifdef DEBUG TRACE(TF_SHHWDTCTDTCT, TEXT("DBT_CUSTOMEVENT + GUID_IO_VOLUME_UNLOCK for '%s'"), pelem->DbgGetName()); #endif // Play it safe... (phn->_cLockAttempts) = 0; hres = phn->_Unregister(); if (SUCCEEDED(hres)) { hres = phn->_Register(); } } } } return hres; } //static HRESULT CHandleNotif::HandleBroadcastHandleEvent(DEV_BROADCAST_HANDLE* pdbh, DWORD dwEventType) { CNamedElemList* pnel; HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_HANDLENOTIF, &pnel); if (S_OK == hres) { // Find the elem in the list CNamedElemEnum* penum; hres = pnel->GetEnum(&penum); if (SUCCEEDED(hres)) { CNamedElem* pelem; BOOL fFoundIt = FALSE; while (!fFoundIt && SUCCEEDED(hres = penum->Next(&pelem)) && (S_FALSE != hres)) { CHandleNotif* phn = (CHandleNotif*)pelem; if (phn->GetDeviceNotifyHandle() == pdbh->dbch_hdevnotify) { // Found it! BOOL fSurpriseRemoval; CHandleNotifTarget* phnt = phn->GetHandleNotifTarget(); hres = phn->HNHandleEvent(pdbh, dwEventType, &fSurpriseRemoval); if (SUCCEEDED(hres)) { if ((GUID_IO_MEDIA_ARRIVAL == pdbh->dbch_eventguid) || (GUID_IO_MEDIA_REMOVAL == pdbh->dbch_eventguid)) { hres = _HandleDeviceArrivalRemoval(pdbh, dwEventType, pelem); } else { if ((GUID_IO_VOLUME_LOCK == pdbh->dbch_eventguid) || (GUID_IO_VOLUME_LOCK_FAILED == pdbh->dbch_eventguid) || (GUID_IO_VOLUME_UNLOCK == pdbh->dbch_eventguid)) { hres = _HandleDeviceLockUnlock(pdbh, dwEventType, pelem); } } if (SUCCEEDED(hres)) { hres = phnt->HNTHandleEvent(pdbh, dwEventType); // phnt has the same life span as pelem, no need to // RCAddRef/RCRelease } } fFoundIt = TRUE; } pelem->RCRelease(); } penum->RCRelease(); } pnel->RCRelease(); } return hres; } /////////////////////////////////////////////////////////////////////////////// // //static HRESULT CHandleNotif::Create(CNamedElem** ppelem) { HRESULT hres = S_OK; *ppelem = new CHandleNotif(); if (!(*ppelem)) { hres = E_OUTOFMEMORY; } return hres; } /////////////////////////////////////////////////////////////////////////////// // HRESULT CHandleNotif::_Register() { HRESULT hres = S_FALSE; DEV_BROADCAST_HANDLE dbhNotifFilter = {0}; dbhNotifFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE); dbhNotifFilter.dbch_devicetype = DBT_DEVTYP_HANDLE; dbhNotifFilter.dbch_handle = _GetDeviceHandle(_pszElemName, FILE_READ_ATTRIBUTES); if (INVALID_HANDLE_VALUE != dbhNotifFilter.dbch_handle) { hres = CHWEventDetectorHelper::RegisterDeviceNotification( &dbhNotifFilter, &_hdevnotify, FALSE); _CloseDeviceHandle(dbhNotifFilter.dbch_handle); } TRACE(TF_SHHWDTCTDTCT, TEXT("--- Registered for '%s'"), _pszElemName); return hres; } HRESULT CHandleNotif::_Unregister() { if (_hdevnotify) { UnregisterDeviceNotification(_hdevnotify); _hdevnotify = NULL; TRACE(TF_SHHWDTCTDTCT, TEXT("--- UNRegistered for '%s'"), _pszElemName); } return S_OK; } /////////////////////////////////////////////////////////////////////////////// // CHandleNotif::CHandleNotif() : _hdevnotify(NULL), _phnt(NULL), _fSurpriseRemoval(TRUE), _cLockAttempts(0) {} CHandleNotif::~CHandleNotif() { _Unregister(); }