#include "dtct.h" #include "fact.h" #include "vol.h" #include "hnotif.h" #include "miscdev.h" #include "dtctreg.h" #include "regnotif.h" #include "cmmn.h" #include "sfstr.h" #include "misc.h" #include "str.h" #include "dbg.h" #include "tfids.h" #include #include #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0])) /////////////////////////////////////////////////////////////////////////////// // HRESULT _HandleDeviceEvent(LPCWSTR pszDeviceIntfID, CHWDeviceInst* phwdevinst, LPCWSTR pszEventType, BOOL* pfHasHandler) { HRESULT hres = _DispatchToHandler(pszDeviceIntfID, phwdevinst, pszEventType, pfHasHandler); if (SUCCEEDED(hres)) { TRACE(TF_SHHWDTCTDTCT, TEXT("_DispatchToHandler SUCCEEDED")); } else { TRACE(TF_SHHWDTCTDTCT, TEXT("_DispatchToHandler FAILED: 0x%08X"), hres); hres = S_FALSE; } return hres; } // {A5DCBF10-6530-11D2-901F-00C04FB951ED} const CLSID guidInterfaceUSB = {0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}}; // {53F5630A-B6BF-11D0-94F2-00A0C91EFB8B} const CLSID guidInterfacePartition = {0x53F5630A, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}}; HRESULT _IsInterfaceInList(const GUID* pguidInterface, const CLSID* rgList[], DWORD cList, BOOL* pfPresent) { *pfPresent = FALSE; for (DWORD dw = 0; !(*pfPresent) && (dw < cList); ++dw) { if (*(rgList[dw]) == *pguidInterface) { *pfPresent = TRUE; } } return S_OK; } const CLSID* _rgpguidRejectedInterface[] = { &guidInterfacePartition, }; HRESULT _IsInterfaceRejected(GUID* pguidInterface, BOOL* pfRejected) { return _IsInterfaceInList(pguidInterface, _rgpguidRejectedInterface, ARRAYSIZE(_rgpguidRejectedInterface), pfRejected); } const CLSID* _rgpguidSpecialInterface[] = { &guidInterfaceUSB, }; HRESULT _IsInterfaceSpecial(GUID* pguidInterface, BOOL* pfSpecial) { return _IsInterfaceInList(pguidInterface, _rgpguidSpecialInterface, ARRAYSIZE(_rgpguidRejectedInterface), pfSpecial); } HRESULT _TryAutoplay(LPCWSTR pszDeviceIntfID, CHWDeviceInst* phwdevinst, DWORD dwEventType) { LPCWSTR pszEventType = NULL; HRESULT hres; if (DBT_DEVICEARRIVAL == dwEventType) { pszEventType = TEXT("DeviceArrival"); } else { if (DBT_DEVICEREMOVECOMPLETE == dwEventType) { pszEventType = TEXT("DeviceRemoval"); } else { ASSERT(FALSE); } } if (pszEventType) { // Useless in this case BOOL fHasHandler; hres = _HandleDeviceEvent(pszDeviceIntfID, phwdevinst, pszEventType, &fHasHandler); } else { hres = S_FALSE; } return hres; } const CLSID* _rgpguidRequiringAdviseInterface[] = { &guidInterfaceUSB, &guidVideoCameraClass, &guidImagingDeviceClass, }; HRESULT _IsInterfaceRequiringAdvise(GUID* pguidInterface, BOOL* pfRequiringAdvise) { return _IsInterfaceInList(pguidInterface, _rgpguidRequiringAdviseInterface, ARRAYSIZE(_rgpguidRequiringAdviseInterface), pfRequiringAdvise); } // If it's one of the few interfaces requiring advise, or if the device has a // DeviceHandler we send notifications HRESULT _AdviseDeviceArrivedOrRemovedHelper(GUID* pguidInterface, LPCWSTR pszDeviceIntfID, CHWDeviceInst* phwdevinst, DWORD dwEventType) { BOOL fAdvise; HRESULT hr = _IsInterfaceRequiringAdvise(pguidInterface, &fAdvise); // This should never get here ASSERT(guidVolumeClass != *pguidInterface); if (SUCCEEDED(hr)) { DWORD dwDeviceFlags = HWDDF_HASDEVICEHANDLER_UNDETERMINED; if (phwdevinst) { WCHAR szDeviceHandler[MAX_DEVICEHANDLER]; HRESULT hrTmp = _GetDeviceHandler(phwdevinst, szDeviceHandler, ARRAYSIZE(szDeviceHandler)); if (SUCCEEDED(hrTmp) && (S_FALSE != hrTmp)) { fAdvise = TRUE; dwDeviceFlags &= ~HWDDF_HASDEVICEHANDLER_UNDETERMINED; dwDeviceFlags |= HWDDF_HASDEVICEHANDLER; } } if (fAdvise) { BOOL fRemovableDevice; LPCWSTR pszDeviceEvent; if (DBT_DEVICEARRIVAL == dwEventType) { pszDeviceEvent = TEXT("DeviceArrival"); } else { ASSERT(DBT_DEVICEREMOVECOMPLETE == dwEventType); pszDeviceEvent = TEXT("DeviceRemoval"); } dwDeviceFlags |= HWDDF_REMOVABLEDEVICE_UNDETERMINED; if (phwdevinst) { hr = phwdevinst->IsRemovableDevice(&fRemovableDevice); if (SUCCEEDED(hr)) { if (fRemovableDevice) { dwDeviceFlags &= ~HWDDF_REMOVABLEDEVICE_UNDETERMINED; dwDeviceFlags |= HWDDF_REMOVABLEDEVICE; } } } if (SUCCEEDED(hr)) { hr = CHardwareDevicesImpl::_AdviseDeviceArrivedOrRemoved( pszDeviceIntfID, pguidInterface, dwDeviceFlags, pszDeviceEvent); } } else { hr = S_FALSE; } } return hr; } HRESULT _ProcessInterface(GUID* pguidInterface, LPCWSTR pszDeviceIntfID, DWORD dwEventType) { CNamedElemList* pnel; HRESULT hr = CHWEventDetectorHelper::GetList(HWEDLIST_MISCDEVINTF, &pnel); if (SUCCEEDED(hr)) { if (DBT_DEVICEARRIVAL == dwEventType) { CNamedElem* pelem; hr = pnel->GetOrAdd(pszDeviceIntfID, &pelem); if (SUCCEEDED(hr)) { BOOL fRemoveFromList = TRUE; CMiscDeviceInterface* pmdi = (CMiscDeviceInterface*)pelem; // If we're adding it, let's finish its initialization hr = pmdi->InitInterfaceGUID(pguidInterface); if (SUCCEEDED(hr)) { CHWDeviceInst* phwdevinst; hr = pmdi->GetHWDeviceInst(&phwdevinst); if (SUCCEEDED(hr) && (S_FALSE != hr)) { BOOL f; _AdviseDeviceArrivedOrRemovedHelper(pguidInterface, pszDeviceIntfID, phwdevinst, dwEventType); hr = phwdevinst->IsRemovableDevice(&f); if (SUCCEEDED(hr) & f) { hr = _IsInterfaceSpecial(pguidInterface, &f); if (SUCCEEDED(hr) & f) { hr = phwdevinst->ShouldAutoplayOnSpecialInterface( pguidInterface, &f); if (FAILED(hr) || (S_FALSE == hr)) { f = FALSE; } } else { f = TRUE; } if (f) { hr = _TryAutoplay(pszDeviceIntfID, phwdevinst, dwEventType); fRemoveFromList = FALSE; } } } } if (fRemoveFromList) { hr = pnel->Remove(pszDeviceIntfID); } pelem->RCRelease(); } } else { CNamedElem* pelem; hr = pnel->Get(pszDeviceIntfID, &pelem); if (SUCCEEDED(hr) && (S_FALSE != hr)) { CHWDeviceInst* phwdevinst; CMiscDeviceInterface* pmdi = (CMiscDeviceInterface*)pelem; hr = pmdi->GetHWDeviceInst(&phwdevinst); if (SUCCEEDED(hr) && (S_FALSE != hr)) { _AdviseDeviceArrivedOrRemovedHelper(pguidInterface, pszDeviceIntfID, phwdevinst, dwEventType); hr = _TryAutoplay(pszDeviceIntfID, phwdevinst, dwEventType); // If we're removing it, let's remove it from the list HRESULT hr2 = pnel->Remove(pszDeviceIntfID); hr = FAILED(hr2) ? hr2 : hr; } pelem->RCRelease(); } else { _AdviseDeviceArrivedOrRemovedHelper(pguidInterface, pszDeviceIntfID, NULL, dwEventType); } } pnel->RCRelease(); } return hr; } HRESULT CHWEventDetectorImpl::_HandleInterfaceEvent( DEV_BROADCAST_DEVICEINTERFACE* pdbdi, DWORD dwEventType) { HRESULT hres = S_FALSE; if (pdbdi->dbcc_name[0]) { BOOL fSpecialCased; hres = _IsInterfaceSpecialCased(&(pdbdi->dbcc_classguid), &fSpecialCased); if (SUCCEEDED(hres)) { if (fSpecialCased) { TRACE(TF_SHHWDTCTDTCT, TEXT("---> Special case")); hres = _ProcessInterfaceSpecialCased(&(pdbdi->dbcc_classguid), pdbdi->dbcc_name, dwEventType); } else { if ((DBT_DEVICEARRIVAL == dwEventType) || (DBT_DEVICEREMOVECOMPLETE == dwEventType)) { BOOL fRejected; hres = _IsInterfaceRejected(&(pdbdi->dbcc_classguid), &fRejected); if (SUCCEEDED(hres)) { if (!fRejected) { TRACE(TF_SHHWDTCTDTCT, TEXT("---> Regular processing")); hres = _ProcessInterface(&(pdbdi->dbcc_classguid), pdbdi->dbcc_name, dwEventType); } else { TRACE(TF_SHHWDTCTDTCT, TEXT("---> Rejected")); } } } else { TRACE(TF_SHHWDTCTDTCT, TEXT("---> Not deviceArrival/Removal")); } } } } else { // why do we get this? } return hres; } // This is for volumes only // static HRESULT CHWEventDetectorImpl::HandleVolumeMediaEvent(LPCWSTR pszDeviceIDVolume, CHWDeviceInst* phwdevinst, LPCWSTR pszEventType, BOOL* pfHasHandler) { return _HandleDeviceEvent(pszDeviceIDVolume, phwdevinst, pszEventType, pfHasHandler); } // This is for volumes only HRESULT CHWEventDetectorImpl::_HandleBroadcastHandleEvent( DEV_BROADCAST_HANDLE* pdbh, DWORD dwEventType) { HRESULT hres = S_OK; if (DBT_CUSTOMEVENT == dwEventType) { if ((GUID_IO_VOLUME_MOUNT == pdbh->dbch_eventguid) || (GUID_IO_VOLUME_DISMOUNT == pdbh->dbch_eventguid) || (GUID_IO_VOLUME_DISMOUNT_FAILED == pdbh->dbch_eventguid) || (GUID_IO_VOLUME_LOCK == pdbh->dbch_eventguid) || (GUID_IO_VOLUME_UNLOCK == pdbh->dbch_eventguid) || (GUID_IO_VOLUME_LOCK_FAILED == pdbh->dbch_eventguid) || (GUID_IO_MEDIA_ARRIVAL == pdbh->dbch_eventguid) || (GUID_IO_MEDIA_REMOVAL == pdbh->dbch_eventguid) || (GUID_IO_VOLUME_CHANGE == pdbh->dbch_eventguid) || (GUID_IO_VOLUME_NAME_CHANGE == pdbh->dbch_eventguid)) { hres = CHandleNotif::HandleBroadcastHandleEvent(pdbh, dwEventType); } else { #ifdef DEBUG WCHAR szGUID[MAX_GUIDSTRING]; if (SUCCEEDED(_StringFromGUID(&(pdbh->dbch_eventguid), szGUID, ARRAYSIZE(szGUID)))) { TRACE(TF_SHHWDTCTDTCT, TEXT("UNHANDLED! DBT_CUSTOMEVENT + %s for '0x%08X'"), szGUID, pdbh->dbch_handle); } #endif } } else { if ((DBT_DEVICEQUERYREMOVE == dwEventType) || (DBT_DEVICEREMOVEPENDING == dwEventType) || (DBT_DEVICEQUERYREMOVEFAILED == dwEventType) || (DBT_DEVICEREMOVECOMPLETE == dwEventType)) { hres = CHandleNotif::HandleBroadcastHandleEvent(pdbh, dwEventType); } } return hres; } /////////////////////////////////////////////////////////////////////////////// // HRESULT CHWEventDetectorImpl::_RegisterForNotif() { HRESULT hres = CHWEventDetectorHelper::CreateLists(); if (SUCCEEDED(hres)) { hres = CHWEventDetectorHelper::FillLists(); if (SUCCEEDED(hres)) { // Register for all Device Interface Events DEV_BROADCAST_DEVICEINTERFACE dbdNotifFilter = {0}; dbdNotifFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); dbdNotifFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; dbdNotifFilter.dbcc_classguid = guidInvalid; hres = CHWEventDetectorHelper::RegisterDeviceNotification( &dbdNotifFilter, &_hdevnotifyAllInterfaces, TRUE); } } return hres; } HRESULT CHWEventDetectorImpl::_UnregisterForNotif() { CHWEventDetectorHelper::EmptyLists(); UnregisterDeviceNotification(_hdevnotifyAllInterfaces); return S_OK; } /////////////////////////////////////////////////////////////////////////////// // HRESULT CHWEventDetectorImpl::_RegisterFactories() { // TRUE: we want it to stay around HRESULT hres = (CCOMBaseFactory::_RegisterFactories(TRUE) ? S_OK : E_FAIL); TRACE(TF_COMSERVER, TEXT("CHWEventDetectorImpl::_RegisterFactories returns: 0x%08X"), hres); return hres; } HRESULT CHWEventDetectorImpl::_UnregisterFactories() { // TRUE: we wanted it to stay around HRESULT hres = (CCOMBaseFactory::_UnregisterFactories(TRUE) ? S_OK : E_FAIL); TRACE(TF_COMSERVER, TEXT("CHWEventDetectorImpl::_UnregisterFactories returns: 0x%08X"), hres); return hres; } HRESULT CHWEventDetectorImpl::_SuspendFactories() { HRESULT hres = (CCOMBaseFactory::_SuspendFactories() ? S_OK : E_FAIL); TRACE(TF_COMSERVER, TEXT("CHWEventDetectorImpl::_SuspendFactories returns: 0x%08X"), hres); return hres; } HRESULT CHWEventDetectorImpl::_ResumeFactories() { HRESULT hres = (CCOMBaseFactory::_ResumeFactories() ? S_OK : E_FAIL); TRACE(TF_COMSERVER, TEXT("CHWEventDetectorImpl::_ResumeFactories returns: 0x%08X"), hres); return hres; } /////////////////////////////////////////////////////////////////////////////// // CHWEventDetectorImpl::CHWEventDetectorImpl() : _hEventRelinquishControl(NULL), _hdevnotifyAllInterfaces(NULL), _hEventInitCompleted(NULL) {} CHWEventDetectorImpl::~CHWEventDetectorImpl() {}