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

#include "hnotif.h"
#include "hwdev.h"
#include "misc.h"
#include "mischlpr.h"
#include "dbg.h"
#include "tfids.h"
#include <ioevent.h>
#include <dbt.h>
#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();
}