C# How to eject the mobile hard disk

Afon.zhang 396 Reputation points
2021-01-04T09:41:45.39+00:00
  Mobile hard disk is USB interface。


  The following function can only eject the U disk, not the mobile hard disk。


    public static List<string> GetMoveDisk()
    {
        List<string> lstDisk = new List<string>();
        ManagementClass mgtCls = new ManagementClass("Win32_DiskDrive");
        var disks = mgtCls.GetInstances();
        foreach (ManagementObject mo in disks)
        {
            if (mo.Properties["MediaType"].Value == null ||
              mo.Properties["MediaType"].Value.ToString() != "External hard disk media")
            {
                continue;
            }

            foreach (ManagementObject diskPartition in mo.GetRelated("Win32_DiskPartition"))
            {
                foreach (var disk in diskPartition.GetRelated("Win32_LogicalDisk"))
                {
                    lstDisk.Add(disk.Properties["Name"].Value.ToString());
                }
            }
        }
        string filename = @"\\.\" + lstDisk[0];
        IntPtr handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);

        uint byteReturned;
        bool result = Win32.DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
        bool isexit = Win32.CloseHandle(handle);
        return lstDisk;
    }
Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,585 questions
{count} votes

Accepted answer
  1. Rita Han - MSFT 2,161 Reputation points
    2021-01-06T02:18:18.003+00:00

    Hello @Afon.zhang ,
    You can try the following sample to see if it helps.

      // EjectMobileHardDisk.cpp : This file contains the 'main' function. Program execution begins and ends there.  
        //  
          
        #include <stdio.h>  
        #include <windows.h>  
        #include <Setupapi.h>  
        #include <winioctl.h>  
        #include <winioctl.h>  
        #include <cfgmgr32.h>  
          
        #pragma comment(lib, "SetupAPI.lib")  
          
        #define SLEEP_TIME 500  
          
        //-------------------------------------------------  
        DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber, UINT DriveType, char* szDosDeviceName);  
        //-------------------------------------------------  
          
        //-------------------------------------------------  
        int main()  
        {  
         char DriveLetter = 'F';  
         DriveLetter &= ~0x20; // uppercase  
          
         if (DriveLetter < 'A' || DriveLetter > 'Z') {  
         return 1;  
         }  
          
         char szRootPath[] = "F:\\";   // "X:\"  -> for GetDriveType  
         szRootPath[0] = DriveLetter;  
          
         char szDevicePath[] = "F:";   // "X:"   -> for QueryDosDevice  
         szDevicePath[0] = DriveLetter;  
          
         char szVolumeAccessPath[] = "\\\\.\\F:";   // "\\.\X:"  -> to open the volume  
         szVolumeAccessPath[4] = DriveLetter;  
          
         long DeviceNumber = -1;  
          
         // open the storage volume  
         HANDLE hVolume = CreateFile(szVolumeAccessPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);  
         if (hVolume == INVALID_HANDLE_VALUE) {  
         return 1;  
         }  
          
         // get the volume's device number  
         STORAGE_DEVICE_NUMBER sdn;  
         DWORD dwBytesReturned = 0;  
         long res = DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);  
         if (res) {  
         DeviceNumber = sdn.DeviceNumber;  
         }  
         CloseHandle(hVolume);  
          
         if (DeviceNumber == -1) {  
         return 1;  
         }  
          
         // get the drive type which is required to match the device numbers correctely  
         UINT DriveType = GetDriveType(szRootPath);  
          
         // get the dos device name (like \device\floppy0) to decide if it's a floppy or not - who knows a better way?  
         char szDosDeviceName[MAX_PATH];  
         res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);  
         if (!res) {  
         return 1;  
         }  
          
         // get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number  
         DEVINST DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber, DriveType, szDosDeviceName);  
          
         if (DevInst == 0) {  
         return 1;  
         }  
          
         PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;  
         WCHAR VetoNameW[MAX_PATH];  
         VetoNameW[0] = 0;  
         bool bSuccess = false;  
          
         // get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives!  
         DEVINST DevInstParent = 0;  
         res = CM_Get_Parent(&DevInstParent, DevInst, 0);  
          
         for (long tries = 1; tries <= 3; tries++) { // sometimes we need some tries...  
          
         VetoNameW[0] = 0;  
          
         // CM_Query_And_Remove_SubTree doesn't work for restricted users  
         //res = CM_Query_And_Remove_SubTreeW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, CM_REMOVE_NO_RESTART); // CM_Query_And_Remove_SubTreeA is not implemented under W2K!  
         //res = CM_Query_And_Remove_SubTreeW(DevInstParent, NULL, NULL, 0, CM_REMOVE_NO_RESTART);  // with messagebox (W2K, Vista) or balloon (XP)  
          
         res = CM_Request_Device_EjectW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, 0);  
         //res = CM_Request_Device_EjectW(DevInstParent, NULL, NULL, 0, 0); // with messagebox (W2K, Vista) or balloon (XP)  
          
         bSuccess = (res == CR_SUCCESS && VetoType == PNP_VetoTypeUnknown);  
         if (bSuccess) {  
         break;  
         }  
          
         Sleep(SLEEP_TIME); // required to give the next tries a chance!  
         }  
          
         if (bSuccess) {  
         printf("Success\n\n");  
         return 0;  
         }  
          
         printf("failed\n");  
          
         printf("Result=0x%2X\n", res);  
          
         if (VetoNameW[0]) {  
         printf("VetoName=%ws)\n\n", VetoNameW);  
         }  
         return 1;  
        }  
        //-----------------------------------------------------------  
          
          
          
        //----------------------------------------------------------------------  
        // returns the device instance handle of a storage volume or 0 on error  
        //----------------------------------------------------------------------  
        DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber, UINT DriveType, char* szDosDeviceName)  
        {  
         bool IsFloppy = (strstr(szDosDeviceName, "\\Floppy") != NULL); // who knows a better way?  
          
         GUID* guid;  
          
         switch (DriveType) {  
         case DRIVE_REMOVABLE:  
         if (IsFloppy) {  
         guid = (GUID*)& GUID_DEVINTERFACE_FLOPPY;  
         }  
         else {  
         guid = (GUID*)& GUID_DEVINTERFACE_DISK;  
         }  
         break;  
         case DRIVE_FIXED:  
         guid = (GUID*)& GUID_DEVINTERFACE_DISK;  
         break;  
         case DRIVE_CDROM:  
         guid = (GUID*)& GUID_DEVINTERFACE_CDROM;  
         break;  
         default:  
         return 0;  
         }  
          
         // Get device interface info set handle for all devices attached to system  
         HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);  
          
         if (hDevInfo == INVALID_HANDLE_VALUE) {  
         return 0;  
         }  
          
         // Retrieve a context structure for a device interface of a device information set  
         DWORD dwIndex = 0;  
         long res;  
          
         BYTE Buf[1024];  
         PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;  
         SP_DEVICE_INTERFACE_DATA         spdid;  
         SP_DEVINFO_DATA                  spdd;  
         DWORD                            dwSize;  
          
         spdid.cbSize = sizeof(spdid);  
          
         while (true) {  
         res = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, dwIndex, &spdid);  
         if (!res) {  
         break;  
         }  
          
         dwSize = 0;  
         SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL); // check the buffer size  
          
         if (dwSize != 0 && dwSize <= sizeof(Buf)) {  
          
         pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!  
          
         ZeroMemory(&spdd, sizeof(spdd));  
         spdd.cbSize = sizeof(spdd);  
          
         long res = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd, dwSize, &dwSize, &spdd);  
         if (res) {  
          
         // in case you are interested in the USB serial number:  
         // the device id string contains the serial number if the device has one,  
         // otherwise a generated id that contains the '&' char...  
         /*  
         DEVINST DevInstParent = 0;  
         CM_Get_Parent(&DevInstParent, spdd.DevInst, 0);  
         char szDeviceIdString[MAX_PATH];  
         CM_Get_Device_ID(DevInstParent, szDeviceIdString, MAX_PATH, 0);  
         printf("DeviceId=%s\n", szDeviceIdString);  
         */  
          
         // open the disk or cdrom or floppy  
         HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);  
         if (hDrive != INVALID_HANDLE_VALUE) {  
         // get its device number  
         STORAGE_DEVICE_NUMBER sdn;  
         DWORD dwBytesReturned = 0;  
         res = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);  
         if (res) {  
         if (DeviceNumber == (long)sdn.DeviceNumber) {  // match the given device number with the one of the current device  
         CloseHandle(hDrive);  
         SetupDiDestroyDeviceInfoList(hDevInfo);  
         return spdd.DevInst;  
         }  
         }  
         CloseHandle(hDrive);  
         }  
         }  
         }  
         dwIndex++;  
         }  
          
         SetupDiDestroyDeviceInfoList(hDevInfo);  
          
         return 0;  
        }  
    

    If the answer is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.