Ejemplo n.º 1
0
/**
 * 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);
}