我正在努力创建一个能够弹出任何USB大容量存储设备的应用程序。 经过多次尝试,我终于使用了codeproject中的一些代码 https://www.codeproject.com/Articles/375916/How-to-Prepare-a-USB-Drive-for-Safe-Removal 但是对于某些USB设备,我收到错误“此设备当前正在使用中。关闭可能正在使用该设备的所有程序或窗口,然后再试一次。”我真的不明白为什么它会发生在一些设备而不是其他设备......
显示错误窗口,基本上removeDrive()方法返回false,USB不弹出。
public static bool RemoveDrive( string driveCharWithColon )
{
// open the storage volume
IntPtr hVolume = CreateFile( @"\\.\" + driveCharWithColon, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero );
if ( hVolume.ToInt32( ) == -1 ) return false;
// get the volume's device number
long DeviceNumber = GetDeviceNumber( hVolume );
if ( DeviceNumber == -1 ) return false;
// get the drive type which is required to match the device numbers correctely
string rootPath = driveCharWithColon + "\\";
DriveType driveType = GetDriveType( rootPath );
// get the dos device name (like \device\floppy0) to decide if it's a floppy or not - who knows a better way?
StringBuilder pathInformation = new StringBuilder( 250 );
uint res = QueryDosDevice( driveCharWithColon, pathInformation, 250 );
if ( res == 0 ) return false;
// get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number
long DevInst = GetDrivesDevInstByDeviceNumber( DeviceNumber, driveType, pathInformation.ToString( ) );
if ( DevInst == 0 ) return false;
// get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives!
int DevInstParent = 0;
CM_Get_Parent( ref DevInstParent, ( int ) DevInst, 0 );
for ( int tries=1; tries <= 3; tries++ ) // sometimes we need some tries...
{
int r = CM_Request_Device_Eject_NoUi( DevInstParent, IntPtr.Zero, null, 0, 0 );
if ( r == 0 ) return true;
Thread.Sleep( 500 );
}
return false;
}
阅读更多答案我发现了这个 Eject Memory card from Card Reader C#
如果提到在调用方法CM_Request_Device_Eject_NoUi之前,我必须使用从CreateFile返回的hVolume调用“LockVolume,DismountVolume和PrepareRemovalOfVolume”。
不幸的是,这些功能仅由Microsoft在C ++中提供。 how-to-ejecting-removable-media-in-windows
我想尝试这个解决方案,但我真的不知道如何使用c#实现这些方法。
任何人都可以告诉我可能发生的事情吗? 我试着简单地关闭文件处理程序
CloseHandle(hVolume);
在调用CM_Request_Device_Eject_NoUi方法之前,但它创建了其他SEHException异常(外部组件抛出异常)。
答案 0 :(得分:0)
我设法在C#中实现了3种方法,但LockVolume和DismountVolume方法总是返回false值。
eval(x.value)
更新: 我使用代码
捕获了DeviceIoControl调用中产生的错误 const int LOCK_TIMEOUT = 10000; // 10 Seconds
const int LOCK_RETRIES = 20;
public static bool LockVolume(IntPtr hVolume)
{
int dwBytesReturned;
int 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,
IntPtr.Zero, 0,
IntPtr.Zero, 0,
out dwBytesReturned,
IntPtr.Zero))
return true;
Thread.Sleep(dwSleepAmount);
}
return false;
}
public static bool PreventRemovalOfVolume(IntPtr hVolume, bool fPreventRemoval)
{
int retVal;
IntPtr buffer = new IntPtr((fPreventRemoval) ? 1 : 0);
return DeviceIoControl(hVolume, IOCTL_STORAGE_MEDIA_REMOVAL, buffer, 1, IntPtr.Zero, 0, out retVal, IntPtr.Zero);
}
public static bool DismountVolume(IntPtr hVolume)
{
int dwBytesReturned;
return DeviceIoControl(hVolume,
FSCTL_DISMOUNT_VOLUME,
IntPtr.Zero, 0,
IntPtr.Zero, 0,
out dwBytesReturned,
IntPtr.Zero);
}
public static bool AutoEjectVolume(IntPtr hVolume)
{
int dwBytesReturned;
return DeviceIoControl(hVolume,
IOCTL_STORAGE_EJECT_MEDIA,
IntPtr.Zero, 0,
IntPtr.Zero, 0,
out dwBytesReturned,
IntPtr.Zero);
}
public static bool CloseVolume(IntPtr hVolume)
{
return CloseHandle(hVolume);
}
我收到错误6,意思是ERROR_INVALID_HANDLE。 :o
现在我更加困惑,因为该处理程序在RemoveDrive方法的其余部分中运行良好,包括CloseVolume(处理程序)调用。
int error = Marshal.GetLastWin32Error();