void CNdasLogicalDeviceManager::ShutdownOf( const CNdasLogicalDeviceManager::LDIDMap::value_type& pair) { CNdasLogicalDevice* pLogicalDevice = pair.second; pLogicalDevice->OnShutdown(); }
CNdasLogicalDevice* CNdasLogicalDeviceManager::Find(CONST NDAS_SCSI_LOCATION& location) { ximeta::CAutoLock autolock(this); LocationMap::const_iterator citr = m_NdasScsiLocationMap.find(location); if (m_NdasScsiLocationMap.end() == citr) { return NULL; } CNdasLogicalDevice* pLogicalDevice = citr->second; if (NULL != pLogicalDevice) pLogicalDevice->AddRef(); return pLogicalDevice; }
CNdasLogicalDevice* CNdasLogicalDeviceManager::Find(NDAS_LOGICALDEVICE_ID ldid) { ximeta::CAutoLock autolock(this); LDIDMap::const_iterator citr = m_LDIDMap.find(ldid); if (m_LDIDMap.end() == citr) { return NULL; } CNdasLogicalDevice* pLogicalDevice = citr->second; if (NULL != pLogicalDevice) pLogicalDevice->AddRef(); return pLogicalDevice; }
CNdasLogicalDevice* CNdasLogicalDeviceManager::Register(CNdasUnitDevice& unitDevice) { ximeta::CAutoLock autolock(this); CONST NDAS_LOGICALDEVICE_GROUP& ldGroup = unitDevice.GetLDGroup(); DWORD ldSequence = unitDevice.GetLDSequence(); CNdasLogicalDevice* pLogDevice = NULL; LDGroupMap::iterator itr = m_LDGroupMap.find(ldGroup); if (itr == m_LDGroupMap.end()) { // // New Logical Device Instance // NDAS_LOGICALDEVICE_ID id = cpAllocateID(); if (0 == id) { // SLOT FULL ::SetLastError(NDASSVC_ERROR_LOGICALDEVICE_SLOT_FULL); return NULL; } pLogDevice = new CNdasLogicalDevice(id, ldGroup); if (NULL == pLogDevice) { ::SetLastError(ERROR_OUTOFMEMORY); return NULL; } BOOL fSuccess = pLogDevice->Initialize(); if (!fSuccess) { delete pLogDevice; return NULL; } pLogDevice->AddRef(); // internal pointer reference m_LDGroupMap.insert(LDGroupMap::value_type(ldGroup, pLogDevice)); m_LDIDMap.insert(LDIDMap::value_type(id, pLogDevice)); CRefObjPtr<CNdasDevice> pDevice = unitDevice.GetParentDevice(); _ASSERTE(NULL != pDevice.p); if (pDevice->IsAutoRegistered()) { pLogDevice->SetMountOnReady(pDevice->GetGrantedAccess()); // auto registered devices always ignore RiskyMountFlag pLogDevice->SetRiskyMountFlag(FALSE); } } else { pLogDevice = itr->second; } BOOL fSuccess = pLogDevice->AddUnitDevice(unitDevice); _ASSERTE(fSuccess); if (!fSuccess) { return NULL; } if (NULL != pLogDevice) pLogDevice->AddRef(); // external pointer reference return pLogDevice; }
BOOL CNdasLogicalDeviceManager::Unregister(CNdasUnitDevice& unitDevice) { ximeta::CAutoLock autolock(this); CNdasLogicalDevice* pLogDevice = unitDevice.GetLogicalDevice(); if (NULL == pLogDevice) { return FALSE; } DWORD ldSequence = unitDevice.GetLDSequence(); pLogDevice->RemoveUnitDevice(unitDevice); if (pLogDevice->GetUnitDeviceInstanceCount() == 0) { NDAS_LOGICALDEVICE_ID id = pLogDevice->GetLogicalDeviceId(); LDGroupMap::size_type ldg_erased = m_LDGroupMap.erase(pLogDevice->GetLDGroup()); _ASSERTE(1 == ldg_erased); LDIDMap::size_type id_erased = m_LDIDMap.erase(id); _ASSERTE(1 == id_erased); pLogDevice->Release(); BOOL fSuccess = cpDeallocateID(id); _ASSERTE(fSuccess); } return TRUE; }
BOOL CNdasEventMonitor::OnLogicalDeviceDisconnected(DWORD nWaitIndex) { ximeta::CAutoLock autolock(this); CNdasLogicalDevice* pLogDevice = NULL; if (nWaitIndex < m_vLogDevices.size()) { pLogDevice = m_vLogDevices[nWaitIndex]; } else { _ASSERTE(FALSE); return TRUE; } if (NULL == pLogDevice) { _ASSERTE(FALSE); return TRUE; } CNdasScsiLocation location = pLogDevice->GetNdasScsiLocation(); DBGPRT_INFO(_FT("Disconnect Event from %s: %s\n"), location.ToString(), pLogDevice->ToString()); // // reset the event to prevent consecutive same event pulse // BOOL fSuccess = ::ResetEvent(pLogDevice->GetDisconnectEvent()); _ASSERTE(fSuccess); CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); NDAS_LOGICALDEVICE_ID logicalDeviceId = pLogDevice->GetLogicalDeviceId(); (VOID) pEventPublisher->LogicalDeviceDisconnected(logicalDeviceId); pLogDevice->OnDisconnected(); return TRUE; }
DWORD CNdasEventMonitor::OnTaskStart() { BOOL bTerminateThread(FALSE); // 15 sec = 10,000,000 nanosec // negative value means relative time LARGE_INTEGER liDueTime; liDueTime.QuadPart = - 10 * 1000 * 1000; BOOL fSuccess = ::SetWaitableTimer( m_hHeartbeatMonitorTimer, &liDueTime, HEARTBEAT_MONITOR_INTERVAL, NULL, NULL, FALSE); if (!fSuccess) { DBGPRT_ERR_EX(_FT("Setting waitable timer failed: ")); } do { // // Lock against m_vLogDevice set change // this->Lock(); DWORD dwLogDevices = m_vLogDevices.size(); DWORD dwHandles = 3 + 2 * dwLogDevices; HANDLE* hWaitingHandles = new HANDLE[dwHandles]; hWaitingHandles[0] = m_hTaskTerminateEvent; hWaitingHandles[1] = m_hLogDeviceSetChangeEvent; hWaitingHandles[2] = m_hHeartbeatMonitorTimer; CNdasLogicalDeviceVector::const_iterator itr = m_vLogDevices.begin(); for (DWORD i = 3; itr != m_vLogDevices.end(); ++itr, ++i) { CNdasLogicalDevice* pLogDevice = *itr; hWaitingHandles[i] = pLogDevice->GetDisconnectEvent(); hWaitingHandles[dwLogDevices + i] = pLogDevice->GetAlarmEvent(); } this->Unlock(); fSuccess = ::ResetEvent(m_hLogDeviceSetChangeEvent); _ASSERTE(fSuccess); BOOL bResetLogDeviceSet(FALSE); do { DWORD dwWaitResult = ::WaitForMultipleObjects( dwHandles, hWaitingHandles, FALSE, INFINITE); if (WAIT_OBJECT_0 == dwWaitResult) { // // Terminate Thread Event // bTerminateThread = TRUE; } else if (WAIT_OBJECT_0 + 1 == dwWaitResult) { // // LogicalDeviceSetChange Event // bResetLogDeviceSet = TRUE; } else if (WAIT_OBJECT_0 + 2 == dwWaitResult) { ximeta::CAutoLock autolock(this); // // Heartbeat Monitor Timer Event // CNdasDeviceSet::const_iterator devitr = m_hbMonDevices.begin(); m_bIterating = TRUE; for (; devitr != m_hbMonDevices.end();) { CNdasDevice* pDevice = *devitr; BOOL fDetach = pDevice->OnStatusCheck(); if (fDetach) { devitr = m_hbMonDevices.erase(devitr); pDevice->Release(); } else { ++devitr; } } m_bIterating = FALSE; // // Check the logical devices // std::for_each( m_vLogDevices.begin(), m_vLogDevices.end(), NdasLogicalDeviceStatusCheck); } else if (WAIT_OBJECT_0 + 3 <= dwWaitResult && dwWaitResult < WAIT_OBJECT_0 + 3 + dwLogDevices) { // // Disconnect Event // DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3); BOOL fHandled = OnLogicalDeviceDisconnected(n); if (!fHandled) { fSuccess = ::ResetEvent(hWaitingHandles[dwWaitResult - WAIT_OBJECT_0]); _ASSERTE(fSuccess); } } else if (WAIT_OBJECT_0 + 3 + dwLogDevices <= dwWaitResult && dwWaitResult < WAIT_OBJECT_0 + 3 + 2 * dwLogDevices) { // // Alarm Event // DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3 + dwLogDevices); BOOL fHandled = OnLogicalDeviceAlarmed(n); if (!fHandled) { fSuccess = ::ResetEvent(hWaitingHandles[dwWaitResult - WAIT_OBJECT_0]); _ASSERTE(fSuccess); } } else { // _ASSERTE(FALSE); // Some handles may be already invalid. // LogicalDeviceSetChange Event // bResetLogDeviceSet = TRUE; DBGPRT_ERR_EX(_FT("Wait failed: ")); } } while (!bResetLogDeviceSet && !bTerminateThread); delete [] hWaitingHandles; } while (!bTerminateThread); fSuccess = ::CancelWaitableTimer(m_hHeartbeatMonitorTimer); if (!fSuccess) { DBGPRT_ERR_EX(_FT("Canceling waitable timer failed: ")); } return 0; }
BOOL CNdasEventMonitor::OnLogicalDeviceAlarmed(DWORD nWaitIndex) { ximeta::CAutoLock autolock(this); CNdasLogicalDevice* pLogDevice = NULL; if (nWaitIndex < m_vLogDevices.size()) { pLogDevice = m_vLogDevices[nWaitIndex]; } else { _ASSERTE(FALSE); return FALSE; } if (NULL == pLogDevice) { _ASSERTE(FALSE); return FALSE; } CNdasScsiLocation ndasScsiLocation = pLogDevice->GetNdasScsiLocation(); DBGPRT_INFO(_FT("Alarm Event from %s: %s\n"), ndasScsiLocation.ToString(), pLogDevice->ToString()); if (ndasScsiLocation.IsInvalid()) { DBGPRT_ERR(_FT("Invalid SCSI Location\n")); _ASSERTE(FALSE); return FALSE; } // // reset the event to prevent consecutive same event pulse // // should return TRUE BOOL fSuccess = ::ResetEvent(pLogDevice->GetAlarmEvent()); _ASSERTE(fSuccess); ULONG ulAdapterStatus; fSuccess = ::LsBusCtlQueryStatus( ndasScsiLocation.SlotNo, &ulAdapterStatus); if (!fSuccess) { DBGPRT_ERR_EX(_FT("(%s) query status failed on alarm, ignored: "), ndasScsiLocation.ToString()); return TRUE; } DBGPRT_INFO(_FT("(%s) alarmed %08X.\n"), ndasScsiLocation.ToString(), ulAdapterStatus); // Determine whether an alarm will be issued. // Only viable alarm will be published if(pIsViableAlarmStatus(pLogDevice->GetAdapterStatus(), ulAdapterStatus)) { CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); (VOID) pEventPublisher->LogicalDeviceAlarmed( pLogDevice->GetLogicalDeviceId(), pGetSignificatAlarm(pLogDevice->GetAdapterStatus(), ulAdapterStatus)); } pLogDevice->SetAdapterStatus(ulAdapterStatus); return TRUE; }
BOOL CNdasIXBcast::BroadcastStatus() { BUSENUM_QUERY_INFORMATION BusEnumQuery; BUSENUM_INFORMATION BusEnumInformation; CNdasLogicalDeviceManager* pLdm = pGetNdasLogicalDeviceManager(); CNdasLogicalDeviceCollection coll; pLdm->Lock(); pLdm->GetItems(coll); pLdm->Unlock(); for (CNdasLogicalDeviceCollection::const_iterator itr = coll.begin(); itr != coll.end(); ++itr) { CNdasLogicalDevice* pLogDevice = *itr; if (NDAS_LOGICALDEVICE_STATUS_MOUNTED != pLogDevice->GetStatus()) { continue; } CONST NDAS_SCSI_LOCATION& location = pLogDevice->GetNdasScsiLocation(); BusEnumQuery.InfoClass = INFORMATION_PDO; BusEnumQuery.Size = sizeof(BUSENUM_QUERY_INFORMATION); BusEnumQuery.SlotNo = location.SlotNo; BOOL fSuccess = LsBusCtlQueryInformation( &BusEnumQuery, sizeof(BUSENUM_QUERY_INFORMATION), &BusEnumInformation, sizeof(BUSENUM_INFORMATION)); if (!fSuccess) { DPErrorEx(_FT("LanscsiQueryInformation failed at slot %d: "), location.SlotNo); continue; } // // Broadcast a primary write access status // if (ND_ACCESS_ISRW(BusEnumInformation.PdoInfo.GrantedAccess)) { const DWORD cbBuffer = sizeof(LSINFOX_HEADER) + sizeof(LSINFOX_PRIMARY_UPDATE); BYTE lpbBuffer[cbBuffer] = {0}; PLSINFOX_HEADER pixHeader = reinterpret_cast<PLSINFOX_HEADER>(lpbBuffer); PLSINFOX_DATA pixData = reinterpret_cast<PLSINFOX_DATA>(lpbBuffer + sizeof(LSINFOX_HEADER)); // // CAUTION: InfoExchange Protocol uses little-endian (Intel) // // // Header // UCHAR ixProtocolName[4] = INFOX_DATAGRAM_PROTOCOL; ::CopyMemory(pixHeader->Protocol, ixProtocolName, 4); pixHeader->LSInfoXMajorVersion = INFOX_DATAGRAM_MAJVER; pixHeader->LSInfoXMinorVersion = INFOX_DATAGRAM_MINVER; pixHeader->OsMajorType = OSTYPE_WINDOWS; DWORD dwOSMajorVersion, dwOSMinorVersion; pGetOSVersion(&dwOSMajorVersion, &dwOSMinorVersion); USHORT usLfsOsMinorType = pInfoXGetOSType(dwOSMajorVersion, dwOSMinorVersion); pixHeader->OsMinorType = usLfsOsMinorType; pixHeader->Type = LSINFOX_PRIMARY_UPDATE_MESSAGE; pixHeader->MessageSize = cbBuffer; // // Data // // primary node is dependent to each interface pixData->Update.PrimaryNode; pixData->Update.PrimaryPort = LPXRP_LFS_PRIMARY; pixData->Update.SWMajorVersion = NDASIX_VERSION_MAJOR; // TODO: Change these values pixData->Update.SWMinorVersion = NDASIX_VERSION_MINOR; pixData->Update.SWBuildNumber = NDASIX_VERSION_BUILD; pixData->Update.NDFSCompatVersion = m_NDFSVersion.wMajor; pixData->Update.NDFSVersion = m_NDFSVersion.wMinor; // // NetDisk Node is a property of each unit device // pixData->Update.NetDiskNode; // // We have fixed the port // (CNdasDevice does not store Port Number internally) // Do not try to retrieve from GetRemoteLpxAddress() // pixData->Update.NetDiskPort = NDAS_DEVICE_LPX_PORT; // // Unit Disk Number is a property of each unit device // pixData->Update.UnitDiskNo; // // pLogDevice->GetStatus() // for (DWORD n = 0; n < pLogDevice->GetUnitDeviceCount(); ++n) { // // Actually, we should traverse the real entry // from the device registrar. // However, here we do the shortcut for using NDAS device id // and fixed NetDiskPort, etc. // NDAS_UNITDEVICE_ID unitDeviceId = pLogDevice->GetUnitDeviceID(n); _ASSERTE(sizeof(pixData->Update.NetDiskNode) == sizeof(unitDeviceId.DeviceId)); ::CopyMemory( pixData->Update.NetDiskNode, unitDeviceId.DeviceId.Node, sizeof(pixData->Update.NetDiskNode)); pixData->Update.UnitDiskNo = unitDeviceId.UnitNo; // // Broadcast the data to every interface // for (DWORD i = 0; i < MAX_SOCKETLPX_INTERFACE; ++i) { if (INVALID_SOCKET != (SOCKET) m_senders[i]) { // // Fill the Primary Node (LPX Address Node) // LPX_ADDRESS localLpxAddress = m_senders[i].GetBoundAddr()->LpxAddress; _ASSERTE(sizeof(pixData->Update.PrimaryNode) == sizeof(localLpxAddress.Node)); ::CopyMemory( pixData->Update.PrimaryNode, localLpxAddress.Node, sizeof(pixData->Update.PrimaryNode)); // // Send the data // DWORD cbSent = 0; BOOL fSuccess = m_senders[i].SendToSync( &NDASIX_BCAST_ADDR, cbBuffer, lpbBuffer, 0, &cbSent); if (!fSuccess) { DPWarningEx(_FT("Sending a packet failed: ")); } } // end if } // for each local LPX address } // for each unit device } // if the logical device has a primary write access. } // for each logical device return TRUE; }
VOID CNdasIXServer::OnIXUsageRequest( CLpxDatagramSocket& sock, CONST SOCKADDR_LPX* pRemoteAddr, CONST LSINFOX_NDASDEV_USAGE_REQUEST* pData) { NDAS_UNITDEVICE_ID unitDeviceId = { { pData->NetDiskNode[0], pData->NetDiskNode[1], pData->NetDiskNode[2], pData->NetDiskNode[3], pData->NetDiskNode[4], pData->NetDiskNode[5] }, pData->UnitDiskNo }; DPNoise(_FT("LSINFOX_PRIMARY_USAGE_MESSAGE: %02X:%02X:%02X:%02X:%02X:%02X@%d\n"), pData->NetDiskNode[0], pData->NetDiskNode[1], pData->NetDiskNode[2], pData->NetDiskNode[3], pData->NetDiskNode[4], pData->NetDiskNode[5], pData->UnitDiskNo); CNdasLogicalDevice* pLogDevice = pGetNdasLogicalDevice(unitDeviceId); if (NULL == pLogDevice) { // Discard message return; } switch (pLogDevice->GetStatus()) { case NDAS_LOGICALDEVICE_STATUS_MOUNTED: case NDAS_LOGICALDEVICE_STATUS_MOUNT_PENDING: case NDAS_LOGICALDEVICE_STATUS_UNMOUNT_PENDING: break; default: // // Otherwise, discard message // return; } ACCESS_MASK mountedAcces = pLogDevice->GetMountedAccess(); CONST DWORD cbPacket = sizeof(LSINFOX_HEADER) + sizeof(LSINFOX_NDASDEV_USAGE_REPLY) + MAX_HOSTNAME_LEN * sizeof(WCHAR); BYTE pbPacket[cbPacket] = {0}; PLSINFOX_HEADER pHeader = reinterpret_cast<PLSINFOX_HEADER>(pbPacket); PLSINFOX_NDASDEV_USAGE_REPLY pUsageReply = reinterpret_cast<PLSINFOX_NDASDEV_USAGE_REPLY>( pbPacket + sizeof(LSINFOX_HEADER)); // // Header // CONST BYTE NdasIxProtocolName[] = INFOX_DATAGRAM_PROTOCOL; ::CopyMemory( pHeader->Protocol, NdasIxProtocolName, sizeof(NdasIxProtocolName)); pHeader->LSInfoXMajorVersion = INFOX_DATAGRAM_MAJVER; pHeader->LSInfoXMinorVersion = INFOX_DATAGRAM_MINVER; pHeader->OsMajorType = OSTYPE_WINDOWS; DWORD dwOSMajorVersion, dwOSMinorVersion; pGetOSVersion(&dwOSMajorVersion, &dwOSMinorVersion); USHORT usLfsOsMinorType = pInfoXGetOSType(dwOSMajorVersion, dwOSMinorVersion); pHeader->OsMinorType = usLfsOsMinorType; pHeader->Type = LSINFOX_PRIMARY_UPDATE_MESSAGE | LSINFOX_TYPE_REPLY; pHeader->MessageSize = cbPacket; // // Body // LPX_ADDRESS localLpxAddress = sock.GetBoundAddr()->LpxAddress; pUsageReply->HostLanAddr.AddressType = LSNODE_ADDRTYPE_ETHER; pUsageReply->HostLanAddr.AddressLen = LPXADDR_NODE_LENGTH; ::CopyMemory( pUsageReply->HostLanAddr.Address, localLpxAddress.Node, LPXADDR_NODE_LENGTH); WCHAR wszHostName[MAX_HOSTNAME_LEN] = {0}; USHORT hostNameType = LSNODENAME_DNSFULLYQ; DWORD cchHostName = MAX_HOSTNAME_LEN; BOOL fSuccess = ::GetComputerNameExW( ComputerNameDnsFullyQualified, wszHostName, &cchHostName); if (!fSuccess) { hostNameType = LSNODENAME_NETBOIS; cchHostName = MAX_HOSTNAME_LEN; fSuccess = ::GetComputerNameExW( ComputerNameNetBIOS, wszHostName, &cchHostName); } if (!fSuccess) { hostNameType = LSNODENAME_UNKNOWN; cchHostName = 0; } pUsageReply->HostNameType = hostNameType; pUsageReply->HostNameLength = cchHostName; ::CopyMemory( pUsageReply->HostName, wszHostName, cchHostName * sizeof(WCHAR)); // // LPX Address.Node is an adapter address. // const DWORD cbAdapterAddress = 6; BYTE pAdapterAddress[cbAdapterAddress] = {0}; ::CopyMemory(pAdapterAddress, localLpxAddress.Node, 6); DWORD cbIpAddress = 14; // TODO: why is this 14? BYTE pPrimaryIpAddress[14] = {0}; fSuccess = pGetAdapterPrimaryIpAddress( cbAdapterAddress, pAdapterAddress, &cbIpAddress, pPrimaryIpAddress); fSuccess = FALSE; if (!fSuccess) { DBGPRT_WARN_EX(_FT("Failed to get primary ip address of %s: "), CSockLpxAddr(sock.GetBoundAddr()).ToString()); pUsageReply->HostWanAddr.AddressLen = 0; pUsageReply->HostWanAddr.AddressType = LSNODE_ADDRTYPE_IP; ::ZeroMemory(pUsageReply->HostWanAddr.Address, LSNODE_ADDR_LENGTH); } else { pUsageReply->HostWanAddr.AddressLen = (USHORT) cbIpAddress; pUsageReply->HostWanAddr.AddressType = LSNODE_ADDRTYPE_IP; _ASSERTE(cbIpAddress <= LSNODE_ADDR_LENGTH); ::CopyMemory( pUsageReply->HostWanAddr.Address, pPrimaryIpAddress, cbIpAddress); } // // Software Versions, status, etc // if (mountedAcces & GENERIC_READ) { pUsageReply->AccessRight |= LSSESSION_ACCESS_READ; } if (mountedAcces & GENERIC_WRITE) { pUsageReply->AccessRight |= LSSESSION_ACCESS_WRITE; } pUsageReply->NetDiskPort = NDAS_DEVICE_LPX_PORT; pUsageReply->UnitDiskNo = unitDeviceId.UnitNo; pUsageReply->UsageID = 0; pUsageReply->SWMajorVersion = NDASIX_VERSION_MAJOR; pUsageReply->SWMinorVersion = NDASIX_VERSION_MINOR; pUsageReply->SWBuildNumber = NDASIX_VERSION_BUILD; pUsageReply->NDFSCompatVersion = m_NDFSVersion.wMajor; pUsageReply->NDFSVersion = m_NDFSVersion.wMinor; DWORD cbSent = 0; fSuccess = sock.SendToSync(pRemoteAddr, cbPacket, pbPacket, 0, &cbSent); if (!fSuccess) { DBGPRT_ERR_EX(_FT("Failed to send a reply (%d bytes): "), cbPacket); return; } return; }
DWORD CNdasService::OnServiceStop() { // // We should report the SCM that the service is stopping // Otherwise, the service will terminate the thread. // And we'll get ACCESS VIOLATION ERROR! // DBGPRT_INFO(_FT("Service is stopping...\n")); #if 0 // // Eject all logical device instances // if (NULL != GetTaskHandle()) { CNdasInstanceManager* pInstMan = CNdasInstanceManager::Instance(); if (NULL != pInstMan) { CNdasLogicalDeviceManager* pLdm = pInstMan->GetLogDevMan(); if (NULL != pLdm) { pLdm->Lock(); CNdasLogicalDeviceManager::ConstIterator itr = pLdm->begin(); for (; itr != pLdm->end(); ++itr) { CNdasLogicalDevice* pLogDevice = itr->second; if (NDAS_LOGICALDEVICE_STATUS_MOUNTED == pLogDevice->GetStatus()) { // // If we should call pLogDevice->Eject here, // we must wait here until eject is really complete. // BOOL fSuccess = pLogDevice->Eject(); ReportStatusToSCMgr(SERVICE_STOP_PENDING, 3000); ::Sleep(2000); } } pLdm->Unlock(); } } } #endif ReportStatusToSCMgr(SERVICE_STOP_PENDING, 3000); HANDLE hTask = GetTaskHandle(); this->Stop(FALSE); DWORD dwWaitTimeout = 3000L; // 3 sec ReportStatusToSCMgr(SERVICE_STOP_PENDING, 3000); DWORD dwWaitResult = ::WaitForSingleObject(hTask, dwWaitTimeout); if (WAIT_OBJECT_0 == dwWaitResult) { ReportStatusToSCMgr(SERVICE_STOPPED, 1000, NO_ERROR); return NO_ERROR; } ReportStatusToSCMgr(SERVICE_STOP_PENDING); dwWaitResult = ::WaitForSingleObject(hTask, dwWaitTimeout); if (WAIT_OBJECT_0 == dwWaitResult) { ReportStatusToSCMgr(SERVICE_STOPPED, 1000, NO_ERROR); return NO_ERROR; } ReportStatusToSCMgr(SERVICE_STOP_PENDING); dwWaitResult = ::WaitForSingleObject(hTask, dwWaitTimeout); if (WAIT_OBJECT_0 == dwWaitResult) { ReportStatusToSCMgr(SERVICE_STOPPED, 1000, NO_ERROR); return NO_ERROR; } ReportStatusToSCMgr(SERVICE_STOP_PENDING); dwWaitResult = ::WaitForSingleObject(hTask, dwWaitTimeout); if (dwWaitResult == WAIT_TIMEOUT) { } ReportStatusToSCMgr(SERVICE_STOPPED, 100, 1); return 1; }