2

I'm trying to write a C/C++ program to detect a new SATA SSD (solid-state drive) connection in Windows 7.

This SATA SSD also comes with a SATA-USB cable. I've connected the SATA end to the SATA SDD and the USB end into my computer. Doing this I've been able to detect the SATA SDD connection and removal by using the windows message system to detect WM_DEVICECHANGE message and the associatedDBT_DEVICEARRIVAL event. To do this I also used RegisterDeviceNotification to register the device (i.e. the SATA SSD) so the top-level window receives notifications for device types DBT_DEVTYP_DEVICEINTERFACE with the classguid for the SATA SSD.

However, when I try to connect the SATA SDD to a SATA port on my computer's motherboard, my program doesn't work.

In C/C++ how can I detect SATA SSD plug in and unplug in Windows?

user3731622
  • 4,844
  • 8
  • 45
  • 84
  • 1
    Are you sure your SATA controller supports hotplug? Not all do. – liori Sep 11 '15 at 00:34
  • No, I'm not sure. In Device Manager->IDE ATA/ATAPI controllers I see Intel(R) 8 Series/C220 Series SATA AHCI Controller - 8C02. I will look to see if this controller supports hotplug. – user3731622 Sep 11 '15 at 00:36
  • 1
    If the SATA controller *and* driver both supports hot-plug then this should be enough. The driver side should be taken care of by switching the controller to AHCI mode. However many controllers don't support hot-plug at all, or only for their dedicated eSATA ports. AFAIK the only way to get a drive on such non-hot-plug controller/port to show up in Windows is to instruct Windows to "re-scan disks". You can manually do this in Disk Management -- I don't know how to do it programmatically though. – Paul Groke Sep 11 '15 at 00:38
  • @liori I think my [intel controller](http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/8-series-chipset-pch-datasheet.pdf) does support hotplug. However, I'm not sure if it's enabled. I think I might need to set the controller (or SATA port?) to AHCI. Currently, I don't know how to tell if the controller is using AHCI. In Device Manager I can scan for hardware changes. Then windows will search for the driver, and the SATA SDD will show in Device Manager->Disk drives. However, this still doesn't trigger DBT_DEVICEARRIVAL. – user3731622 Sep 11 '15 at 00:50

1 Answers1

2

In general connecting an SSD drive to a SATA port on a powered-up computer is a bad idea. The SATA controller must have hotplug functionality to do this. But you can scan deviceclass and find all devices from this class and it will able to you process all interesting devices. I post code sample that can do this:

bool FindConnectedRemovableUsbstorDevices(std::list<std::wstring>& UsbList)
{
std::wstring ClassGuidString(L"{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}");
GUID ClassGuid;
BYTE buf[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATA_W pspdidd = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA_W>(buf);
SP_DEVICE_INTERFACE_DATA spdid;
SP_DEVINFO_DATA spdd;
DWORD size;
SP_DEVINFO_DATA dev_data;
DWORD properties;


if(NOERROR != CLSIDFromString(ClassGuidString.c_str(), &ClassGuid))
    return false;

HDEVINFO dev_info = INVALID_HANDLE_VALUE;
dev_info = SetupDiGetClassDevs(&ClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

if (dev_info == INVALID_HANDLE_VALUE)
    return false;

DWORD index = 0;
BOOL ret = FALSE;

spdid.cbSize = sizeof(spdid);

while (true)
{
    ret = SetupDiEnumDeviceInterfaces(dev_info, NULL, &ClassGuid, index, &spdid);
    if (!ret)
        break;

    size = 0;
    SetupDiGetDeviceInterfaceDetail(dev_info, &spdid, NULL, 0, &size, NULL);
    //Get required size

    if (size == 0 || size >= sizeof(buf))
        continue;
    //prepare structs
    ZeroMemory(reinterpret_cast<PVOID>(pspdidd), 1024);
    pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!

    ZeroMemory(reinterpret_cast<PVOID>(&spdd), sizeof(spdd));
    spdd.cbSize = sizeof(spdd);

    BOOL res = SetupDiGetDeviceInterfaceDetail(dev_info, &spdid, pspdidd, size, &size, &spdd);
    //Get info
    if (!res)
        continue;

    HANDLE drive = CreateFileW(pspdidd->DevicePath, FILE_READ_ATTRIBUTES,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, 0, NULL);//open device
    if (drive == INVALID_HANDLE_VALUE)
        continue;

    printf("\n%S\r\n", pspdidd->DevicePath);

    DWORD bytes_returned = 0;
    BOOL b = DeviceIoControl(drive, IOCTL_STORAGE_CHECK_VERIFY2, NULL, 0, NULL, 0, &bytes_returned, NULL);
    if (!b) //check is card reader?
    {
        printf("IOCTL_STORAGE_CHECK_VERIFY2 error = %d\r\n", GetLastError());
        goto stop_process_device;
    }

    bytes_returned = 0;
    STORAGE_DEVICE_NUMBER sdn;
    //Get Drive number
    b = DeviceIoControl(drive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &bytes_returned, NULL);
    if (!b)
        goto stop_process_device;
    RtlZeroMemory(&dev_data, sizeof(SP_DEVINFO_DATA));
    dev_data.cbSize = sizeof(dev_data);
    if (SetupDiEnumDeviceInfo(dev_info, sdn.DeviceNumber, &dev_data))
    {
        //check property
        b = SetupDiGetDeviceRegistryProperty(dev_info, &dev_data, SPDRP_REMOVAL_POLICY, NULL,
            reinterpret_cast<PBYTE>(&properties), sizeof(properties), NULL);
        if (b && properties != CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL)
        {
            UsbList.push_back(pspdidd->DevicePath);
            printf("REMOVAL\r\n");
        }
    }
stop_process_device:
    CloseHandle(drive);
    index++;
}
SetupDiDestroyDeviceInfoList(dev_info);
return true;
}
Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
drem1lin
  • 331
  • 1
  • 3
  • 14