请问如何编程实现“安全删除”U盘?
解决方案 »
- 新手学习delphi,TStringList简单问题求助,成功马上结贴。
- service 窗体的控件为什么是只读的?
- Delphi企业数据库开发项目,寻找合作伙伴!
- 谁有QQ号请加我:79790029 (仅限Delphi程序员)
- 急,急,急,急。请帮忙:TNMUDP控件发送数据流的问题。
- table1.filter这个属性如果过滤是两个字段组成的条件怎么写?
- 怎样设置才能令form只有“最小化”和“关闭”?
- activeform应用shellexecute的问题.
- 三层结构下,如何保存二进制大型数据
- 关于DBGRID的小问题,请指教!
- 获取ADO数据集内存的指针?
- 如何自动选中select的第2项并提交?
WDK当中的CM_Request_Device_Eject这个函数
不过据说Setupapi.dll里面也有,可以考虑动态导出
http://www.codeproject.com/KB/system/RemoveDriveByLetter.aspxhttp://www.microsoft.com/china/whdc/archive/usbfaq.mspx
源地址:
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;
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:\”盘的符号在驱动器列表中仍然存在,并不同于用户“安全删除”的效果?
#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”盘依然存在,是什么问题啊?
如果打开U盘,显示里面的内容,则运行后U盘窗口关闭,但是U盘仍可用,噢,那看来是这样的,运行上面的程序后,U盘的确是卸载了,但是随后电脑又自动装了……