STDMETHODIMP CNdasLogicalUnitManager::get_NdasLogicalUnits( DWORD Flags, CInterfaceArray<INdasLogicalUnit>& dest) { CAutoLock autolock(this); dest.Copy(m_NdasLogicalUnits); autolock.Release(); if (NDAS_ENUM_EXCLUDE_HIDDEN & Flags) { // // Filter out hidden logical devices // A hidden logical device is a logical device, // of which the device of the primary unit device // is hidden. // size_t count = dest.GetCount(); for (size_t index = 0; index < count; ++index) { INdasLogicalUnit* p = dest.GetAt(index); if (NdasLogicalUnitIsHidden()(p)) { dest.RemoveAt(index); --index; --count; } } } return S_OK; }
DWORD CNdasEventMonitor::ThreadStart(HANDLE hStopEvent) { CCoInitialize coinit(COINIT_MULTITHREADED); // 15 sec = 10,000,000 nanosec // negative value means relative time LARGE_INTEGER liDueTime; liDueTime.QuadPart = - 10 * 1000 * 1000; BOOL success = ::SetWaitableTimer( m_HeartbeatMonitorTimer, &liDueTime, HEARTBEAT_MONITOR_INTERVAL, NULL, NULL, FALSE); if (!success) { XTLTRACE2(NDASSVC_EVENTMON, TRACE_LEVEL_ERROR, "Setting waitable timer failed, error=0x%X\n", GetLastError()); } XTLVERIFY( ::ResetEvent(m_NdasLogicalUnitSetChanged) ); std::vector<HANDLE> waitHandles; waitHandles.reserve(20); // Lock-free copy of the devices and logDevices CInterfaceArray<INdasDevice> ndasDevices; CInterfaceArray<INdasLogicalUnit> ndasLogicalUnits; while (true) { // // Copy m_NdasDevices and m_NdasLogicalUnits to devices and logDevices // for lock free accesses // // DEVICE READER LOCK REGION { XTL::CReaderLockHolder holder(m_NdasDeviceDataLock); ndasDevices.Copy(m_NdasDevices); } { XTL::CReaderLockHolder holder(m_NdasLogicalUnitDataLock); ndasLogicalUnits.Copy(m_NdasLogicalUnits); } // DEVICE READER LOCK REGION // // Recreate wait handles // size_t ndasLogicalUnitCount = ndasLogicalUnits.GetCount(); waitHandles.resize(3 + ndasLogicalUnitCount * 2); waitHandles[0] = hStopEvent; waitHandles[1] = m_NdasLogicalUnitSetChanged; waitHandles[2] = m_HeartbeatMonitorTimer; // Disconnect events i=[3 ...3+nLogDevices) // Alarm Events events i=[3+nLogDevices ... 3+2*nLogDevices) for (size_t index = 0; index < ndasLogicalUnitCount; ++index) { INdasLogicalUnit* pNdasLogicalUnit = ndasLogicalUnits.GetAt(index); waitHandles[3 + index] = NdasLogicalUnitDisconnectEvent()(pNdasLogicalUnit); waitHandles[3 + index + ndasLogicalUnitCount] = NdasLogicalUnitAlarmEvent()(pNdasLogicalUnit); } DWORD nWaitHandles = waitHandles.size(); DWORD waitResult = ::WaitForMultipleObjects( nWaitHandles, &waitHandles[0], FALSE, INFINITE); if (WAIT_OBJECT_0 == waitResult) { // Terminate Thread Event XTLVERIFY( ::CancelWaitableTimer(m_HeartbeatMonitorTimer) ); return 0; } else if (WAIT_OBJECT_0 + 1 == waitResult) { // Logical device set change event XTLVERIFY( ::ResetEvent(m_NdasLogicalUnitSetChanged) ); continue; } else if (WAIT_OBJECT_0 + 2 == waitResult) { // Heartbeat Monitor Timer Event AtlForEach(ndasDevices, InvokeTimerEventSink<INdasDevice>()); AtlForEach(ndasLogicalUnits, InvokeTimerEventSink<INdasLogicalUnit>()); } else if ( waitResult >= WAIT_OBJECT_0 + 3 && waitResult < WAIT_OBJECT_0 + 3 + ndasLogicalUnitCount) { XTLVERIFY( ::ResetEvent(waitHandles[waitResult - WAIT_OBJECT_0]) ); // Disconnect Event DWORD n = waitResult - (WAIT_OBJECT_0 + 3); OnLogicalDeviceDisconnected(ndasLogicalUnits[n]); } else if ( waitResult >= WAIT_OBJECT_0 + 3 + ndasLogicalUnitCount && waitResult < WAIT_OBJECT_0 + 3 + 2 * ndasLogicalUnitCount) { XTLVERIFY( ::ResetEvent(waitHandles[waitResult - WAIT_OBJECT_0]) ); // Alarm Event DWORD n = waitResult - (WAIT_OBJECT_0 + 3 + ndasLogicalUnitCount); OnLogicalDeviceAlarmed(ndasLogicalUnits[n]); } else { XTLASSERT(FALSE); } } }
// // Return TRUE to grant the request to suspend. // To deny the request, return BROADCAST_QUERY_DENY. // LRESULT CNdasServicePowerEventHandler::OnQuerySuspend(DWORD dwFlags) { HRESULT hr; XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_INFORMATION, "OnQuerySuspend.\n"); // A DWORD value dwFlags specifies action flags. // If bit 0 is 1, the application can prompt the user for directions // on how to prepare for the suspension; otherwise, the application // must prepare without user interaction. All other bit values are reserved. DWORD dwValue = NdasServiceConfig::Get(nscSuspendOptions); if (NDASSVC_SUSPEND_ALLOW == dwValue) { return TRUE; } CComPtr<INdasLogicalUnitManager> pManager; COMVERIFY(hr = pGetNdasLogicalUnitManager(&pManager)); CInterfaceArray<INdasLogicalUnit> ndasLogicalUnits; pManager->get_NdasLogicalUnits(NDAS_ENUM_DEFAULT, ndasLogicalUnits); bool mounted = false; size_t count = ndasLogicalUnits.GetCount(); for (size_t index = 0; index < count; ++index) { INdasLogicalUnit* pNdasLogicalUnit = ndasLogicalUnits.GetAt(index); if (LogicalDeviceIsMounted()(pNdasLogicalUnit)) { mounted = true; break; } } // // Service won't interact with the user // If you want to make this function interactive // You should set the NDASSVC_SUSPEND_ALLOW // and the UI application should process NDASSVC_SUSPEND by itself // if (mounted) { if (0x01 == (dwFlags & 0x01)) { // // Possible to interact with the user // (void) m_service.GetEventPublisher().SuspendRejected(); return BROADCAST_QUERY_DENY; } else { // // No User interface is available // (void) m_service.GetEventPublisher().SuspendRejected(); return BROADCAST_QUERY_DENY; } } return TRUE; }