哪位帮看看,这段MSDN上的C代码为什么在我的机器上起不了作用?

ynduanlian 2010-11-08 03:31:27
代码源自:http://support.microsoft.com/kb/165721/zh-cn

我在BCB中建立了一个控制台程序:
#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 ;
}


我的USB盘为“G”盘,
编译后我执行:
Project1.exe G
结果显示:Media in Drive G has been ejected safely.
但我到我的电脑中看见,这个“G”盘依然存在,还能打开访问里面的内容,为什么会这样?
...全文
128 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
ynduanlian 2010-11-08
  • 打赏
  • 举报
回复
真是奇怪,我找了一台XP的机器,上面的程序也没有起到任何效果啊
zzbinfo 2010-11-08
  • 打赏
  • 举报
回复
测试的是后面发的代码,我的系统是xp-sp2,bcb6
ynduanlian 2010-11-08
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 zzbinfo 的回复:]
测试了你的代码,没有问题,确实是可以删除移动存储设备的.你再试试.这个跟系统的移除有区别.这个删除以后,盘符还在,但是,设备已经安全删除了,从磁盘的卷标可以看出来
[/Quote]

请问您测试的是我前面发的还是后面的代码?会不会和操作系统有关系?您是什么操作系统?
zzbinfo 2010-11-08
  • 打赏
  • 举报
回复
测试了你的代码,没有问题,确实是可以删除移动存储设备的.你再试试.这个跟系统的移除有区别.这个删除以后,盘符还在,但是,设备已经安全删除了,从磁盘的卷标可以看出来
ynduanlian 2010-11-08
  • 打赏
  • 举报
回复
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
#include <stdio.h>
#include <dbt.h>
#include <shlobj.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);
}

void BroadcastDeviceChange( WPARAM message, int nDosDriveNo, DWORD driveMap )
{
DEV_BROADCAST_VOLUME dbv;
char root[] = {0,':', '\\', 0 };
DWORD dwResult;
LONG event = 0;
int i;

if (message == DBT_DEVICEARRIVAL) event = SHCNE_DRIVEADD;
if (message == DBT_DEVICEREMOVECOMPLETE) event = SHCNE_DRIVEREMOVED;

if (driveMap == 0)
{
root[0] = nDosDriveNo + 'A';
SHChangeNotify(event, SHCNF_PATH, root, NULL);
}
else
{
for (i = 0; i < 26; i++)
{
if (driveMap & (1 << i))
{
root[0] = i + 'A';
SHChangeNotify(event, SHCNF_PATH, root, NULL);
}
}
}

dbv.dbcv_size = sizeof(dbv);
dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
dbv.dbcv_reserved = 0;
dbv.dbcv_unitmask = (driveMap != 0) ? driveMap : (1 << nDosDriveNo);
dbv.dbcv_flags = 0;

SendMessageTimeout (HWND_BROADCAST, WM_DEVICECHANGE, message, (LPARAM)(&dbv), 0, 500, &dwResult);
}


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);
}
BroadcastDeviceChange(DBT_DEVICEREMOVECOMPLETE, 'G', 0 );
printf("Ok....");


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 ;
}



//-----------
贴出全部代码,上面的代码也不行啊?是哪有错?
ynduanlian 2010-11-08
  • 打赏
  • 举报
回复
char root[] = {0, \':\', \'\\\\\', 0 };
这是什么意思啊?不起作用啊?
shuaialang 2010-11-08
  • 打赏
  • 举报
回复
http://forum.driverdevelop.com/read.php?tid=92819

没试过。LZ说可以


Dismount后应该发广播消息吧?
偶做虚拟盘的时候在MOUNT后调用
BroadcastDeviceChange( DBT_DEVICEARRIVAL, nDriverNo, 0 );

Dismount后调用:
BroadcastDeviceChange( DBT_DEVICEREMOVECOMPLETE, nDriverNo, 0 );


void BroadcastDeviceChange( WPARAM message, int nDosDriveNo, DWORD driveMap )
{
DEV_BROADCAST_VOLUME dbv;
char root[] = {0, \':\', \'\\\\\', 0 };
DWORD dwResult;
LONG event = 0;
int i;

if (message == DBT_DEVICEARRIVAL) event = SHCNE_DRIVEADD;
if (message == DBT_DEVICEREMOVECOMPLETE) event = SHCNE_DRIVEREMOVED;

if (driveMap == 0)
{
root[0] = nDosDriveNo + \'A\';
SHChangeNotify(event, SHCNF_PATH, root, NULL);
}
else
{
for (i = 0; i < 26; i++)
{
if (driveMap & (1 << i))
{
root[0] = i + \'A\';
SHChangeNotify(event, SHCNF_PATH, root, NULL);
}
}
}

dbv.dbcv_size = sizeof(dbv);
dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
dbv.dbcv_reserved = 0;
dbv.dbcv_unitmask = (driveMap != 0) ? driveMap : (1 << nDosDriveNo);
dbv.dbcv_flags = 0;

SendMessageTimeout (HWND_BROADCAST, WM_DEVICECHANGE, message, (LPARAM)(&dbv), 0, 500, &dwResult);
}

1,221

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧