#include <windows.h>
   #include <winioctl.h>
   #include <tchar.h>
   #include <stdio.h>   // Prototypes   BOOL EjectVolume(TCHAR cDriveLetter);   HANDLE OpenVolume(TCHAR cDriveLetter);
   BOOL LockVolume(HANDLE hVolume);
   BOOL DismountVolume(HANDLE hVolume);
   BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPrevent);
   BOOL AutoEjectVolume(HANDLE hVolume);
   BOOL CloseVolume(HANDLE hVolume);   LPTSTR szVolumeFormat = TEXT("\\\\.\\%c:");
   LPTSTR szRootFormat = TEXT("%c:\\");
   LPTSTR szErrorFormat = TEXT("Error %d: %s\n");   void ReportError(LPTSTR szMsg)
   {
       _tprintf(szErrorFormat, GetLastError(), szMsg);
   }   HANDLE OpenVolume(TCHAR cDriveLetter)
   {
       HANDLE hVolume;
       UINT uDriveType;
       TCHAR szVolumeName[8];
       TCHAR szRootName[5];
       DWORD dwAccessFlags;       wsprintf(szRootName, szRootFormat, cDriveLetter);       uDriveType = GetDriveType(szRootName);
       switch(uDriveType) {
       case DRIVE_REMOVABLE:
           dwAccessFlags = GENERIC_READ | GENERIC_WRITE;
           break;
       case DRIVE_CDROM:
           dwAccessFlags = GENERIC_READ;
           break;
       default:
           _tprintf(TEXT("Cannot eject.  Drive type is incorrect.\n"));
           return INVALID_HANDLE_VALUE;
       }       wsprintf(szVolumeName, szVolumeFormat, cDriveLetter);       hVolume = CreateFile(   szVolumeName,
                               dwAccessFlags,
                               FILE_SHARE_READ | FILE_SHARE_WRITE,
                               NULL,
                               OPEN_EXISTING,
                               0,
                               NULL );
       if (hVolume == INVALID_HANDLE_VALUE)
           ReportError(TEXT("CreateFile"));       return hVolume;
   }   BOOL CloseVolume(HANDLE hVolume)
   {
       return CloseHandle(hVolume);
   }   #define LOCK_TIMEOUT        10000       // 10 Seconds
   #define LOCK_RETRIES        20   BOOL LockVolume(HANDLE hVolume)
   {
       DWORD dwBytesReturned;
       DWORD dwSleepAmount;
       int nTryCount;       dwSleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;       // Do this in a loop until a timeout period has expired
       for (nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++) {
           if (DeviceIoControl(hVolume,
                               FSCTL_LOCK_VOLUME,
                               NULL, 0,
                               NULL, 0,
                               &dwBytesReturned,
                               NULL))
               return TRUE;           Sleep(dwSleepAmount);
       }       return FALSE;
   }   BOOL DismountVolume(HANDLE hVolume)
   {
       DWORD dwBytesReturned;       return DeviceIoControl( hVolume,
                               FSCTL_DISMOUNT_VOLUME,
                               NULL, 0,
                               NULL, 0,
                               &dwBytesReturned,
                               NULL);
   }   BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPreventRemoval)
   {
       DWORD dwBytesReturned;
       PREVENT_MEDIA_REMOVAL PMRBuffer;       PMRBuffer.PreventMediaRemoval = fPreventRemoval;       return DeviceIoControl( hVolume,
                               IOCTL_STORAGE_MEDIA_REMOVAL,
                               &PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
                               NULL, 0,
                               &dwBytesReturned,
                               NULL);
   }   AutoEjectVolume(HANDLE hVolume)
   {
       DWORD dwBytesReturned;       return DeviceIoControl( hVolume,
                               IOCTL_STORAGE_EJECT_MEDIA,
                               NULL, 0,
                               NULL, 0,
                               &dwBytesReturned,
                               NULL);
   }   BOOL EjectVolume(TCHAR cDriveLetter)
   {
       HANDLE hVolume;       BOOL fRemoveSafely = FALSE;
       BOOL fAutoEject = FALSE;       // Open the volume.
       hVolume = OpenVolume(cDriveLetter);
       if (hVolume == INVALID_HANDLE_VALUE)
           return FALSE;       // Lock and dismount the volume.
       if (LockVolume(hVolume) && DismountVolume(hVolume)) {
           fRemoveSafely = TRUE;           // Set prevent removal to false and eject the volume.
           if (PreventRemovalOfVolume(hVolume, FALSE) &&
               AutoEjectVolume(hVolume))
               fAutoEject = TRUE;
       }       // Close the volume so other processes can use the drive.
       if (!CloseVolume(hVolume))
           return FALSE;       if (fAutoEject)
           printf("Media in Drive %c has been ejected safely.\n",
                  cDriveLetter);
       else {
           if (fRemoveSafely)
               printf("Media in Drive %c can be safely removed.\n",
               cDriveLetter);
       }       return TRUE;
   }   void Usage()
   {
       printf("Usage: Eject <drive letter>\n\n");
       return ;
   }   void main(int argc, char * argv[])
   {
       if (argc != 2) {
           Usage();
           return ;
       }       if (!EjectVolume(argv[1][0]))
           printf("Failure ejecting drive %c.\n", argv[1][0]);       return ;
   }

解决方案 »

  1.   

    function OpenVolume(ADrive: char): THandle;
    var
      RootName, VolumeName: string;
      AccessFlags: DWORD;
    begin
      RootName := ADrive + ':' + #134; // ADrive + ':\' kills the syntax highlighting
      case GetDriveType(PChar(RootName)) of
        DRIVE_REMOVABLE:
          AccessFlags := GENERIC_READ or GENERIC_WRITE;
        DRIVE_CDROM:
          AccessFlags := GENERIC_READ;
      else
        Result := INVALID_HANDLE_VALUE;
        exit;
      end;
      VolumeName := Format('\\.\%s:', [ADrive]);
      Result := CreateFile(PChar(VolumeName), AccessFlags,
        FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
      if Result = INVALID_HANDLE_VALUE then
        RaiseLastWin32Error;
    end;function LockVolume(AVolumeHandle: THandle): boolean;
    const
      LOCK_TIMEOUT = 10 * 1000; // 10 Seconds
      LOCK_RETRIES = 20;
      LOCK_SLEEP = LOCK_TIMEOUT div LOCK_RETRIES;// #define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
      FSCTL_LOCK_VOLUME = (9 shl 16) or (0 shl 14) or (6 shl 2) or 0;
    var
      Retries: integer;
      BytesReturned: Cardinal;
    begin
      for Retries := 1 to LOCK_RETRIES do begin
        Result := DeviceIoControl(AVolumeHandle, FSCTL_LOCK_VOLUME, nil, 0,
          nil, 0, BytesReturned, nil);
        if Result then
          break;
        Sleep(LOCK_SLEEP);
      end;
    end;function DismountVolume(AVolumeHandle: THandle): boolean;
    const
    // #define FSCTL_DISMOUNT_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
      FSCTL_DISMOUNT_VOLUME = (9 shl 16) or (0 shl 14) or (8 shl 2) or 0;
    var
      BytesReturned: Cardinal;
    begin
      Result := DeviceIoControl(AVolumeHandle, FSCTL_DISMOUNT_VOLUME, nil, 0,
        nil, 0, BytesReturned, nil);
      if not Result then
        RaiseLastWin32Error;
    end;function PreventRemovalOfVolume(AVolumeHandle: THandle;
      APreventRemoval: boolean): boolean;
    const
    // #define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
      IOCTL_STORAGE_MEDIA_REMOVAL = ($2d shl 16) or (1 shl 14) or ($201 shl 2) or 0;
    type
      TPreventMediaRemoval = record
        PreventMediaRemoval: BOOL;
      end;
    var
      BytesReturned: Cardinal;
      PMRBuffer: TPreventMediaRemoval;
    begin
      PMRBuffer.PreventMediaRemoval := APreventRemoval;
      Result := DeviceIoControl(AVolumeHandle, IOCTL_STORAGE_MEDIA_REMOVAL,
        @PMRBuffer, SizeOf(TPreventMediaRemoval), nil, 0, BytesReturned, nil);
      if not Result then
        RaiseLastWin32Error;
    end;function AutoEjectVolume(AVolumeHandle: THandle): boolean;
    const
    // #define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
      IOCTL_STORAGE_EJECT_MEDIA = ($2d shl 16) or (1 shl 14) or ($202 shl 2) or 0;
    var
      BytesReturned: Cardinal;
    begin
      Result := DeviceIoControl(AVolumeHandle, IOCTL_STORAGE_EJECT_MEDIA, nil, 0,
        nil, 0, BytesReturned, nil);
      if not Result then
        RaiseLastWin32Error;
    end;function EjectVolume(ADrive: char): boolean;
    var
      VolumeHandle: THandle;
    begin
      Result := FALSE;
      // Open the volume
      VolumeHandle := OpenVolume(ADrive);
      if VolumeHandle = INVALID_HANDLE_VALUE then
        exit;
      try
        // Lock and dismount the volume
        if LockVolume(VolumeHandle) and DismountVolume(VolumeHandle) then begin
          // Set prevent removal to false and eject the volume
          if PreventRemovalOfVolume(VolumeHandle, FALSE) then
            AutoEjectVolume(VolumeHandle);
        end;
      finally
        // Close the volume so other processes can use the drive
        CloseHandle(VolumeHandle);
      end;
    end;