请问如何编程实现“安全删除”U盘?

解决方案 »

  1.   

    不好做,这个八成得用驱动,
    WDK当中的CM_Request_Device_Eject这个函数
    不过据说Setupapi.dll里面也有,可以考虑动态导出
      

  2.   

    参考:
    http://www.codeproject.com/KB/system/RemoveDriveByLetter.aspxhttp://www.microsoft.com/china/whdc/archive/usbfaq.mspx
      

  3.   

    开始运行%windir%\system32\rundll32.exe shell32.dll,Control_RunDLL hotplug.dll
      

  4.   

    http://support.microsoft.com/kb/165721/zh-cn接分
      

  5.   

    翻了下老帖子,月亮写的,根据LS发的MSDN翻译的
    源地址:
    http://topic.csdn.net/u/20090628/16/96e73f9e-5e74-4bed-bb75-2f18a0e9cb02.html
    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;
      

  6.   

    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 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;procedure TForm1.Button2Click(Sender: TObject);
    begin
     if AutoEjectVolume(OpenVolume('G')) then
     showMessage('OK');
    end;用上面的代码,点按钮后显示“OK”,但是看U盘('G:\')怎么仍然可用啊。如果是这样:
     if DismountVolume(OpenVolume('G')) then showMessage('OK2');“OK2”弹出了,然后“G:\”盘也确实不能访问了,但是“G:\”盘的符号在驱动器列表中仍然存在,并不同于用户“安全删除”的效果?
      

  7.   

    我直接用上面MS的C代码:
    #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 ;
       }运行(G为U盘盘符)
    project1.exe G
    运行结果:Media in Drive G has been ejected safely.
    但我到我的电脑中看见,这个“G”盘依然存在,是什么问题啊?
      

  8.   

    我试了若是光驱,则光驱弹出.
    如果打开U盘,显示里面的内容,则运行后U盘窗口关闭,但是U盘仍可用,噢,那看来是这样的,运行上面的程序后,U盘的确是卸载了,但是随后电脑又自动装了……