BOOL WINAPI NdasDmGetDiskNumbersOfVolume( HANDLE hVolume, LPDWORD pDiskNumbers, DWORD dwDiskNumbers, LPDWORD lpdwDiskNumbersUsed) { BOOL fSuccess(FALSE); DWORD cbReturned(0); // // Prepare Volume Disk Extent Buffer // DWORD cbVolumeDiskExtents = sizeof(VOLUME_DISK_EXTENTS) + MAX_VOL_DISK_EXTS * sizeof(VOLUME_DISK_EXTENTS); PVOLUME_DISK_EXTENTS pVolumeDiskExtents = (PVOLUME_DISK_EXTENTS) ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbVolumeDiskExtents); if (NULL == pVolumeDiskExtents) { DPErrorEx(_FT("Memory allication (%d bytes) failed: "), cbVolumeDiskExtents); return FALSE; } // // Get Volume Disk Extents // DPTrace(_FT("DeviceIoControl(IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS)\n")); fSuccess = ::DeviceIoControl( hVolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, pVolumeDiskExtents, cbVolumeDiskExtents, &cbReturned, NULL); if (!fSuccess) { DPErrorEx(_FT("DeviceIoControl(IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS) failed: ")); ::HeapFree(::GetProcessHeap(), 0, pVolumeDiskExtents); return FALSE; } // // usually it returns one disk device // *lpdwDiskNumbersUsed = 0; for (DWORD i = 0; i < pVolumeDiskExtents->NumberOfDiskExtents; ++i) { DPInfo(_FT("Extents[%d]:: Disk Number: %d, Starting Offset: %d, Extent Length: %d.\n"), i, pVolumeDiskExtents->Extents[i].DiskNumber, pVolumeDiskExtents->Extents[i].StartingOffset, pVolumeDiskExtents->Extents[i].ExtentLength); if (i < dwDiskNumbers) { pDiskNumbers[i] = pVolumeDiskExtents->Extents[i].DiskNumber; ++(*lpdwDiskNumbersUsed); } } ::HeapFree(::GetProcessHeap(), 0, pVolumeDiskExtents); return TRUE; }
int drvinst(int argc, LPTSTR *argv) { typedef enum { SVC_INSTALL, SVC_REMOVE, SVC_REMOVE_PNP } COMMAND_TYPE; struct { COMMAND_TYPE type; LPCTSTR cmd; int argc; BOOL op; } opts[] = { { SVC_INSTALL, L"install", 3, TRUE}, { SVC_REMOVE, L"remove", 1, FALSE}, { SVC_REMOVE_PNP, L"removepnp", 1, FALSE} }; COMMAND_TYPE CmdType; const DWORD nopts = RTL_NUMBER_OF(opts); DWORD i = 0; for (; i < nopts; ++i) { if (lstrcmpi(opts[i].cmd, argv[0]) == 0) { if ((argc - 1) == opts[i].argc || (opts[i].op && (argc - 1) >= opts[i].argc)) { CmdType = opts[i].type; } else { _ftprintf(stderr, _T("Invalid command arguments.\n")); return 254; } break; } } if (i == nopts) { _ftprintf(stderr, _T("Invalid command.\n")); return 254; } if (SVC_INSTALL == CmdType) { LPTSTR szSourceFilePath = argv[1]; LPTSTR szServiceName = argv[2]; LPTSTR szDisplayName = argv[3]; LPTSTR szLoadOrderGroup = NULL; if (argc > 4) { szLoadOrderGroup = argv[4]; } DPInfo(_FT("Source: %s, ServiceName: %s, DisplayName: %s, LoadOrder: %s"), szSourceFilePath, szServiceName, szDisplayName, szLoadOrderGroup); BOOL bUpdated; BOOL fSuccess = NdasDiInstallOrUpdateDriverService( szSourceFilePath, szServiceName, szDisplayName, _T(""), SERVICE_KERNEL_DRIVER, SERVICE_SYSTEM_START, SERVICE_ERROR_NORMAL, szLoadOrderGroup, NULL, NULL, &bUpdated); if (!fSuccess) { printErrorText(); return 254; } else { if (bUpdated) { _ftprintf(stdout, _T("Driver Service %s updated successfully.\n"), szServiceName); } else { _ftprintf(stdout, _T("Driver Service %s installed successfully.\n"), szServiceName); } return 0; } } else if (SVC_REMOVE == CmdType) { LPTSTR szServiceName = argv[1]; BOOL fSuccess = NdasDiDeleteService(szServiceName); if (!fSuccess) { printErrorText(); return 254; } else { _ftprintf(stdout, _T("Driver Service %s deleted successfully.\n"), szServiceName); } } else if (SVC_REMOVE_PNP == CmdType) { LPTSTR szServiceName = argv[1]; DWORD cRemoved; BOOL fRebootRequired; BOOL fSuccess = NdasDiRemoveLegacyDevice( NULL, szServiceName, FALSE, &cRemoved, &fRebootRequired, NULL, NULL); if (!fSuccess) { printErrorText(); return 254; } _ftprintf(stdout, _T("Driver Enum Key (%d) removed successfully.%s\n"), cRemoved, fRebootRequired ? _T(" (Reboot required)") : _T("")); } else { _ftprintf(stderr, _T("Unknown command.\n")); return 254; } return 0; }
BOOL WINAPI NdasDmGetNdasLogDevSlotNoOfScsiPort( DWORD dwScsiPortNumber, LPDWORD lpdwSlotNo) { BOOL fSuccess(FALSE); // // Make up SCSI Port Name // TCHAR szScsiPortName[_MAX_PATH + 1]; HRESULT hr = ::StringCchPrintf( szScsiPortName, _MAX_PATH + 1, TEXT("\\\\.\\Scsi%d:"), dwScsiPortNumber); DPInfo(_FT("SCSI Port Name: %s\n"), szScsiPortName); // // Open SCSI Port Device // HANDLE hScsiPort = ::CreateFile( szScsiPortName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hScsiPort) { DPErrorEx(_FT("CreateFile(%s) failed: "), szScsiPortName); return FALSE; } // // Make up IOCTL In-parameter // LANSCSIMINIPORT_IOCTL_GET_SLOT_NO to get Logical Device Slot No // const DWORD cbHeader = sizeof(SRB_IO_CONTROL); const DWORD cbData = sizeof(ULONG); const DWORD cbInBuffer = cbHeader + cbData; DWORD cbReturned(0); BYTE lpInBuffer[cbInBuffer]; ::ZeroMemory(lpInBuffer, cbInBuffer); PSRB_IO_CONTROL pSrbIoControl = (PSRB_IO_CONTROL) lpInBuffer; pSrbIoControl->HeaderLength = cbHeader; ::CopyMemory(pSrbIoControl->Signature, LANSCSIMINIPORT_IOCTL_SIGNATURE, 8); pSrbIoControl->Timeout = 10; pSrbIoControl->ControlCode = LANSCSIMINIPORT_IOCTL_GET_SLOT_NO; pSrbIoControl->Length = cbData; // // Get Logical Device Slot No // fSuccess = ::DeviceIoControl( hScsiPort, IOCTL_SCSI_MINIPORT, lpInBuffer, cbInBuffer, lpInBuffer, // we use the same buffer for output cbInBuffer, &cbReturned, NULL); if (!fSuccess) { DPErrorEx(_FT("DeviceIoControl(IOCTL_SCSI_MINIPORT,") _T("LANSCSIMINIPORT_IOCTL_GET_SLOT_NO) failed: ")); ::CloseHandle(hScsiPort); return FALSE; } if (0 != pSrbIoControl->ReturnCode) { DPError(_FT("DeviceIoControl(IOCTL_SCSI_MINIPORT,") _T("LANSCSIMINIPORT_IOCTL_GET_SLOT_NO) returned error %d.\n"), pSrbIoControl->ReturnCode); ::CloseHandle(hScsiPort); return FALSE; } // // Calculate the slot number offset and retrieve the value // ULONG* lpdwSlotNoOut = (ULONG*)(lpInBuffer + cbHeader); *lpdwSlotNo = *lpdwSlotNoOut; DPInfo(_FT("NDAS Logical Device Slot: %d\n"), *lpdwSlotNo); ::CloseHandle(hScsiPort); return TRUE; }
BOOL CNdasDeviceComm::GetUnitDeviceInformation(PNDAS_UNITDEVICE_INFORMATION pUnitDevInfo) { _ASSERTE(m_bInitialized && "CNdasDeviceComm is not initialized"); _ASSERTE(pUnitDevInfo != NULL); INT iResult = GetDiskInfo(&m_lspath, m_dwUnitNo); if (0 != iResult) { // TODO: LANDISK_ERROR_BADKEY? DPError(_FT("GetDiskInfo failed with error %d\n"), iResult); return FALSE; } PTARGET_DATA pTargetData = &m_lspath.PerTarget[m_dwUnitNo]; pUnitDevInfo->bLBA = pTargetData->bLBA; pUnitDevInfo->bLBA48 = pTargetData->bLBA48; pUnitDevInfo->bPIO = pTargetData->bPIO; pUnitDevInfo->bDMA = pTargetData->bDma; pUnitDevInfo->bUDMA = pTargetData->bUDma; pUnitDevInfo->MediaType = pTargetData->MediaType; pUnitDevInfo->dwROHosts = pTargetData->NRROHost; pUnitDevInfo->dwRWHosts = pTargetData->NRRWHost; pUnitDevInfo->SectorCount = pTargetData->SectorCount; #ifdef UNICODE // // What if FwRev, Model, SerialNo is not null terminated? // -> solved by terminating null between fields _ASSERTE(sizeof(pUnitDevInfo->szModel) / sizeof(pUnitDevInfo->szModel[0]) == sizeof(pTargetData->Model)); _ASSERTE(sizeof(pUnitDevInfo->szSerialNo) / sizeof(pUnitDevInfo->szSerialNo[0]) == sizeof(pTargetData->SerialNo)); _ASSERTE(sizeof(pUnitDevInfo->szFwRev) / sizeof(pUnitDevInfo->szFwRev[0]) == sizeof(pTargetData->FwRev)); ::MultiByteToWideChar( CP_ACP, 0, pTargetData->Model, sizeof(pTargetData->Model), pUnitDevInfo->szModel, sizeof(pUnitDevInfo->szModel) / sizeof(pUnitDevInfo->szModel[0])); ::MultiByteToWideChar( CP_ACP, 0, pTargetData->SerialNo, sizeof(pTargetData->SerialNo), pUnitDevInfo->szSerialNo, sizeof(pUnitDevInfo->szSerialNo) / sizeof(pUnitDevInfo->szSerialNo[0])); ::MultiByteToWideChar( CP_ACP, 0, pTargetData->FwRev, sizeof(pTargetData->FwRev), pUnitDevInfo->szFwRev, sizeof(pUnitDevInfo->szFwRev) / sizeof(pUnitDevInfo->szFwRev[0])); #else _ASSERTE(sizeof(pUnitDevInfo->szModel) == sizeof(pTargetData->Model)); _ASSERTE(sizeof(pUnitDevInfo->szFwRev) == sizeof(pTargetData->FwRev)); _ASSERTE(sizeof(pUnitDevInfo->szSerialNo) == sizeof(pTargetData->SerialNo)); ::CopyMemory(pUnitDevInfo->szModel, pTargetData->Model, sizeof(pTargetData->Model)); ::CopyMemory(pUnitDevInfo->szFwRev, pTargetData->FwRev, sizeof(pTargetData->FwRev)); ::CopyMemory(pUnitDevInfo->szSerialNo, pTargetData->SerialNo, sizeof(pTargetData->SerialNo)); #endif DPInfo(_FT("Model : %s\n"), pUnitDevInfo->szModel); DPInfo(_FT("Serial No : %s\n"), pUnitDevInfo->szSerialNo); DPInfo(_FT("Firmware Rev : %s\n"), pUnitDevInfo->szFwRev); 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) { DPErrorEx(_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; PCNdasLogicalDeviceVector::const_iterator itr = m_vLogDevices.begin(); for (DWORD i = 3; itr != m_vLogDevices.end(); ++itr, ++i) { PCNdasLogicalDevice pLogDevice = *itr; hWaitingHandles[i] = pLogDevice->GetDisconnectEvent(); hWaitingHandles[dwLogDevices + i] = pLogDevice->GetAlarmEvent(); } this->Unlock(); BOOL 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) { // // Heartbeat Monitor Timer Event // ximeta::CAutoLock autolock(this); PCNdasDeviceSet::const_iterator itr = m_hbMonDevices.begin(); m_bIterating = TRUE; for (; itr != m_hbMonDevices.end();) { PCNdasDevice pDevice = *itr; BOOL bDetach = pDevice->OnStatusCheck(); if (bDetach) { DPInfo(_FT("Detaching device %s from the monitor\n"), CNdasDeviceId(pDevice->GetDeviceId()).ToString()); itr = m_hbMonDevices.erase(itr); } else { ++itr; } } m_bIterating = FALSE; } else if (WAIT_OBJECT_0 + 3 <= dwWaitResult && dwWaitResult < WAIT_OBJECT_0 + 3 + dwLogDevices) { // // Disconnect Event // DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3); PCNdasLogicalDevice pLogDevice = m_vLogDevices[n]; DPInfo(_FT("Disconnect Event from slot %d: %s\n"), pLogDevice->GetSlot(), pLogDevice->ToString()); // // Publish event here // // TODO: Publish event here // CNdasInstanceManager* pInstMan = CNdasInstanceManager::Instance(); _ASSERTE(NULL != pInstMan); CNdasEventPublisher* pEventPublisher = pInstMan->GetEventPublisher(); _ASSERTE(NULL != pEventPublisher); NDAS_LOGICALDEVICE_ID logicalDeviceId = {0}; logicalDeviceId.SlotNo = pLogDevice->GetSlot(); logicalDeviceId.TargetId = 0; logicalDeviceId.LUN = 0; (void) pEventPublisher->LogicalDeviceDisconnected(logicalDeviceId); BOOL fSuccess = ::ResetEvent(pLogDevice->GetDisconnectEvent()); _ASSERTE(fSuccess); // // Eject device // DPInfo(_FT("Ejecting disconnected logical device\n")); fSuccess = pLogDevice->Eject(); if (!fSuccess) { DPErrorEx(_FT("Eject failed: ")); DPError(_FT("Trying to unplug...\n")); fSuccess = pLogDevice->Unplug(); if (!fSuccess) { DPErrorEx(_FT("Unplugging failed: ")); } } } 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); PCNdasLogicalDevice pLogDevice = m_vLogDevices[n]; ULONG ulStatus; DPInfo(_FT("Alarm Event from slot %d: %s\n"), pLogDevice->GetSlot(), pLogDevice->ToString()); LsBusCtlQueryAlarmStatus(pLogDevice->GetSlot(), &ulStatus); CNdasInstanceManager* pInstMan = CNdasInstanceManager::Instance(); _ASSERTE(NULL != pInstMan); CNdasEventPublisher* pEventPublisher = pInstMan->GetEventPublisher(); _ASSERTE(NULL != pEventPublisher); switch (ulStatus) { case ALARM_STATUS_NORMAL: { DPInfo(_FT("Alarm Normal\n")); NDAS_LOGICALDEVICE_ID logicalDeviceId = {0}; logicalDeviceId.SlotNo = pLogDevice->GetSlot(); logicalDeviceId.TargetId = 0; logicalDeviceId.LUN = 0; (void) pEventPublisher-> LogicalDeviceReconnected(logicalDeviceId); } break; case ALARM_STATUS_START_RECONNECT: { DPInfo(_FT("Alarm Start Reconnect\n")); NDAS_LOGICALDEVICE_ID logicalDeviceId = {0}; logicalDeviceId.SlotNo = pLogDevice->GetSlot(); logicalDeviceId.TargetId = 0; logicalDeviceId.LUN = 0; (void) pEventPublisher-> LogicalDeviceReconnecting(logicalDeviceId); } break; case ALARM_STATUS_FAIL_RECONNECT: // obsolete DPInfo(_FT("Alarm Failed Reconnecting\n")); break; default: DPWarning(_FT("Unknown alarm status: %d\n"), ulStatus); } // // TODO: Publish event here // BOOL fSuccess = ::ResetEvent(pLogDevice->GetAlarmEvent()); _ASSERTE(fSuccess); } else { _ASSERTE(FALSE); DPErrorEx(_FT("Wait failed: ")); } } while (!bResetLogDeviceSet && !bTerminateThread); delete [] hWaitingHandles; } while (!bTerminateThread); fSuccess = ::CancelWaitableTimer(m_hHeartbeatMonitorTimer); if (!fSuccess) { DPErrorEx(_FT("Canceling waitable timer failed: ")); } return 0; }
PCNdasDevice CNdasDeviceRegistrar::Register(const NDAS_DEVICE_ID& DeviceId, DWORD dwSlotNo) { // // this will lock this class from here // and releases the lock when the function returns; // ximeta::CAutoLock autolock(this); DPInfo(_FT("Registering device %s at slot %d\n"), LPCTSTR(CNdasDeviceId(DeviceId)), dwSlotNo); // check slot number if (dwSlotNo < 1 || dwSlotNo > m_dwMaxSlotNo) { ::SetLastError(NDASHLPSVC_ERROR_INVALID_SLOT_NUMBER); return NULL; } // check and see if the slot is occupied if (m_pbSlotOccupied[dwSlotNo]) { ::SetLastError(NDASHLPSVC_ERROR_SLOT_ALREADY_OCCUPIED); return NULL; } // find an duplicate address if (NULL != Find(DeviceId)) { ::SetLastError(NDASHLPSVC_ERROR_DUPLICATE_DEVICE_ENTRY); return NULL; } // register PCNdasDevice pDevice = new CNdasDevice(dwSlotNo, DeviceId); if (NULL == pDevice) { // memory allocation failed // No need to set error here! return NULL; } pDevice->AddRef(); BOOL fSuccess = pDevice->Initialize(); if (!fSuccess) { // DebugPrintError((ERROR_T("Device initialization failed!"))); pDevice->Release(); return NULL; } m_pbSlotOccupied[dwSlotNo] = TRUE; bool insertResult; insertResult = m_deviceSlotMap.insert(DeviceSlotMap::value_type(dwSlotNo, pDevice)).second; _ASSERTE(insertResult == true); insertResult = m_deviceIdMap.insert(DeviceIdMap::value_type(DeviceId, pDevice)).second; _ASSERTE(insertResult == true); _ASSERTE(m_deviceSlotMap.size() == m_deviceIdMap.size()); TCHAR szContainer[30]; HRESULT hr = ::StringCchPrintf(szContainer, 30, TEXT("Devices\\%04d"), dwSlotNo); _ASSERT(SUCCEEDED(hr)); fSuccess = _NdasSystemCfg.SetSecureValueEx( szContainer, _T("DeviceId"), &DeviceId, sizeof(DeviceId)); if (!fSuccess) { DPWarningEx( _FT("Writing registration entry to the registry failed at %s.\n"), szContainer); } // // During bootstrapping, we do not publish this event // Bootstrapper will do this later. // if (!m_fBootstrapping) { CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); (VOID) pEventPublisher->DeviceEntryChanged(); } return pDevice; }
BOOL CNamedPipeTransport::Send( LPCVOID lpBuffer, DWORD cbToSend, LPDWORD lpcbSent, LPOVERLAPPED lpOverlapped, DWORD dwFlags) { // AUTOFUNCTRACE(); _ASSERTE(!IsBadReadPtr(lpBuffer, cbToSend)); _ASSERTE(!IsBadWritePtr(lpcbSent, sizeof(DWORD))); _ASSERTE( (NULL == lpOverlapped) || (!IsBadReadPtr(lpOverlapped, sizeof(OVERLAPPED)) && NULL != lpOverlapped->hEvent && INVALID_HANDLE_VALUE != lpOverlapped->hEvent)); UNREFERENCED_PARAMETER(dwFlags); // handling sending zero-byte packet if (cbToSend == 0) { *lpcbSent = 0; if (lpOverlapped) { BOOL fSuccess = ::SetEvent(lpOverlapped->hEvent); _ASSERT(fSuccess); } DPInfo(_FT("Sending 0 byte ignored\n")); return TRUE; } DPInfo(_FT("Sending %d bytes.\n"), cbToSend); BOOL fSuccess(FALSE); DWORD cbCurSent(0), cbCurToSend(cbToSend); const BYTE* lpCurBuffer = reinterpret_cast<const BYTE*>(lpBuffer); *lpcbSent = 0; while (cbCurToSend > 0) { fSuccess = ::WriteFile(m_hPipe, lpBuffer, cbCurToSend, &cbCurSent, lpOverlapped); if (!fSuccess && NULL != lpOverlapped && ::GetLastError() != ERROR_IO_PENDING) { break; } if (lpOverlapped) { // wait until timeout (to prevent indefinite waiting...) DWORD dwWaitResult = ::WaitForSingleObject(lpOverlapped->hEvent, TRANSMIT_TIMEOUT); if (dwWaitResult != WAIT_OBJECT_0) { switch (dwWaitResult) { case WAIT_TIMEOUT: ::SetLastError(WAIT_TIMEOUT); case WAIT_ABANDONED: ::SetLastError(WAIT_ABANDONED); default: break; } return FALSE; } fSuccess = ::GetOverlappedResult(m_hPipe, lpOverlapped, &cbCurSent, TRUE); if (!fSuccess && ::GetLastError() != ERROR_IO_PENDING) { break; } } cbCurToSend -= cbCurSent; *lpcbSent += cbCurSent; lpCurBuffer += cbCurSent; } DPInfo(_FT("Sent %d bytes.\n"), *lpcbSent); return fSuccess; }
BOOL CNamedPipeTransport::Receive( LPVOID lpBuffer, DWORD cbToReceive, LPDWORD lpcbReceived, LPOVERLAPPED lpOverlapped, LPDWORD lpdwFlags) { // AUTOFUNCTRACE(); _ASSERTE(!IsBadWritePtr(lpBuffer, cbToReceive)); _ASSERTE(!IsBadWritePtr(lpcbReceived, sizeof(DWORD))); _ASSERTE(NULL == lpOverlapped || !IsBadWritePtr(lpOverlapped, sizeof(OVERLAPPED)) && NULL != lpOverlapped->hEvent && INVALID_HANDLE_VALUE != lpOverlapped->hEvent); UNREFERENCED_PARAMETER(lpdwFlags); // handling sending zero-byte packet if (cbToReceive == 0) { *lpcbReceived = 0; if (lpOverlapped) { BOOL fSuccess = ::SetEvent(lpOverlapped->hEvent); _ASSERT(fSuccess); } return TRUE; } // we have to receive by the request size DPInfo(_FT("Reading %d bytes.\n"), cbToReceive); BOOL fSuccess(FALSE); DWORD cbCurReceived(0), cbCurToReceive(cbToReceive); LPBYTE lpCurBuffer = reinterpret_cast<LPBYTE>(lpBuffer); *lpcbReceived = 0; while (cbCurToReceive > 0) { fSuccess = ::ReadFile(m_hPipe, lpBuffer, cbCurToReceive, &cbCurReceived, lpOverlapped); if (!fSuccess && NULL != lpOverlapped && ::GetLastError() != ERROR_IO_PENDING) { break; } if (lpOverlapped) { // wait until timeout (to prevent indefinite waiting...) DWORD dwWaitResult = ::WaitForSingleObject(lpOverlapped->hEvent, TRANSMIT_TIMEOUT); if (dwWaitResult != WAIT_OBJECT_0) { switch (dwWaitResult) { case WAIT_TIMEOUT: ::SetLastError(WAIT_TIMEOUT); case WAIT_ABANDONED: ::SetLastError(WAIT_ABANDONED); default: break; } return FALSE; } fSuccess = ::GetOverlappedResult(m_hPipe, lpOverlapped, &cbCurReceived, TRUE); if (!fSuccess && ::GetLastError() != ERROR_IO_PENDING) { break; } } cbCurToReceive -= cbCurReceived; *lpcbReceived += cbCurReceived; lpCurBuffer += cbCurReceived; } DPInfo(_FT("Read %d bytes.\n"), *lpcbReceived); return fSuccess; }