/** * Handle the case where the device unexpectedly fails. * @param device The device the failed. * @param ec The error code from GetLastError() * @return The device error code. */ int handleDeviceFailure(struct FreespaceDeviceStruct* device, int ec) { int rc = FREESPACE_ERROR_UNEXPECTED; int formatRc = 0; LPVOID lpMsgBuf; // Retrieve the system error message for the last-error code formatRc = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ec, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); if (formatRc == 0) { DEBUG_WPRINTF(L"handleDeviceFailure: %d\n", ec); } else { // Display the error message and exit the process DEBUG_WPRINTF(L"handleDeviceFailure: %d => %s\n", ec, lpMsgBuf); LocalFree(lpMsgBuf); } // Clean up this device. freespace_private_removeDevice(device); freespace_private_forceCloseDevice(device); freespace_private_requestDeviceRescan(); if (ec == ERROR_DEVICE_NOT_CONNECTED) { rc = FREESPACE_ERROR_NOT_FOUND; } return rc; }
int checkDiscovery() { if (freespace_private_discoveryStatusChanged()) { int rc; int totalChanges = 0; // Wait for system to stabilize before scanning. if (CMP_WaitNoPendingInstallEvents(0) == WAIT_TIMEOUT) { DEBUG_PRINTF("Pending install events. Wait for resolution.\n"); freespace_private_requestDeviceRescan(); return FREESPACE_ERROR_BUSY; } DEBUG_WPRINTF(L"Scanning devices\n"); // Mark and sweep the device list. freespace_private_filterDevices(NULL, 0, NULL, filterInitialize); // Mark everything that still exists and add new devices rc = freespace_private_scanAndAddDevices(); if (rc != FREESPACE_SUCCESS) { // Unexpected error. Schedule a rescan. DEBUG_WPRINTF(L"Error %d while scanning devices. Request a rescan.\n", rc); freespace_private_requestDeviceRescan(); return rc; } // Handle all changes. totalChanges += checkDiscoveryRemoveDevices(); totalChanges += checkDiscoveryPartiallyRemovedDevices(); totalChanges += checkDiscoveryAddedDevices(); /* * Continue to schedule a rescan until no changes are detected. * Although this should not be necessary, rescanning until a * stable state is reached should increase robustness. */ if (totalChanges != 0) { DEBUG_WPRINTF(L"Detected %d changes. Schedule rescan\n", totalChanges); freespace_private_requestDeviceRescan(); } } return freespace_private_discoveryGetThreadStatus(); }
BOOL freespace_private_discoveryStatusChanged() { if ( freespace_instance_->needToRescanDevicesFlag_ || WaitForSingleObject(freespace_instance_->discoveryEvent_, 0) == WAIT_OBJECT_0) { // Race condition note: the flags need to be reset before the scan takes // place. If device status changes again between when this thread is notified // and the flags get reset, we're ok, since the scan happens afterwards. If the // change occurs after the reset of the flags, the flags will be set again, and // we'll scan next trip around the event loop. freespace_instance_->needToRescanDevicesFlag_ = FALSE; // Force the timer to unsignaled by restarting and then cancelling. freespace_private_requestDeviceRescan(); CancelWaitableTimer(freespace_instance_->discoveryEvent_); return TRUE; } else { return FALSE; } }
LRESULT CALLBACK discoveryCallback(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { if (nMsg == WM_CLOSE) { DestroyWindow(hwnd); return DefWindowProc(hwnd, nMsg, wParam, lParam); } if (nMsg == WM_DESTROY) { DEBUG_WPRINTF(L"discoveryCallback on WM_DESTROY\n"); // Remove the device notification if (freespace_instance_->windowEvent_) { UnregisterDeviceNotification(freespace_instance_->windowEvent_); freespace_instance_->windowEvent_ = NULL; } CancelWaitableTimer(freespace_instance_->discoveryEvent_); CloseHandle(freespace_instance_->discoveryEvent_); freespace_instance_->discoveryEvent_ = NULL; PostQuitMessage(0); return DefWindowProc(hwnd, nMsg, wParam, lParam); } if (nMsg == WM_DEVICECHANGE) { // Should start with DEV_BROADCAST_HDR and validate. DEV_BROADCAST_DEVICEINTERFACE* hdr; hdr = (DEV_BROADCAST_DEVICEINTERFACE*) lParam; // Schedule a device list rescan. freespace_private_requestDeviceRescan(); // Only handle all devices arrived or all devices removed. if ((LOWORD(wParam) != DBT_DEVICEARRIVAL) && (LOWORD(wParam) != DBT_DEVICEREMOVECOMPLETE)) { DEBUG_WPRINTF(L"WM_DEVICECHANGE => %d\n", LOWORD(wParam)); return TRUE; } /* * NOTE: Device scan is only performed once changes have stabilized. * The scan routine must be able to handled a device being removed * and reinserted without scan calls between events. */ if (hdr->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) { return TRUE; } if (LOWORD(wParam) == DBT_DEVICEARRIVAL) { DEBUG_WPRINTF(L"DBT_DEVICEARRIVAL => %s\n", hdr->dbcc_name); } else if (LOWORD(wParam) == DBT_DEVICEREMOVECOMPLETE) { DEBUG_WPRINTF(L"DBT_DEVICEREMOVECOMPLETE => %s\n", hdr->dbcc_name); } else { DEBUG_WPRINTF(L"discoveryCallback on unexpected change (%d) => %s\n", LOWORD(wParam), hdr->dbcc_name); } return TRUE; } return DefWindowProc(hwnd, nMsg, wParam, lParam); }