RemoveDriveByLetter
Introduction
RemovingaUSBdriveusingtheWindowstrayiconiasy,especiallyifyousingle
left-clickit,butsometimesit'sufultodoitfromyourprogram.
Background
Therearesomesamplesaround,buttheonesIsawwerearchingforthevolume
andthencallingCM_Get_
ives
(drivetype:DRIVE_REMOVABLE)arehandleddifferentlyfrombasicdisks
(DRIVE_FIXED)bledriveshaveaone-to-onerelation
betweenthevolumeandthedisk,wherethediskistheparentdeviceofthevolume.
USBdriveswithoutremovablemediaarehandledlikebasicdisks,sotheycanhave
multiplepartitionsandthevolume'sparentdeviceisnotthedisk!UnderVista,this
isthecaforremovabledrivestoo,
theway,
someinformation.
cangetitviaDeviceIoControlcalledwith
IOCTL_STORAGE_GET_DEVICE_llworkswithhandlestostorage
volumesontheoneside,anddisks,
gwithdriveletters,we
havetodistinguishbetweenthedeviceinterfacesGUID_DEVINTERFACE_DISK,
GUID_DEVINTERFACE_FLOPPYandGUID_DEVINTERFACE_ppies
werenotconsideredhereuntilendofOctober2006,soaUSBfloppyscrewedup
everything,life,aUSBfloppyhasdevicenumber0whileanyother
USBdrivehasahighernumber,sotherewerenorealproblems.
Bytheway:LegacyfloppiesarenotpartoftheGUID_DEVINTERFACE_FLOPPY
enumeration.
TheSample
sthe
volumeandgetsitsdevicenumber:
Collap
//"X:"->forGetDriveType
charszRootPath[]="X:";
szRootPath[0]=DriveLetter;
//"X:"->forQueryDosDevice
charszDevicePath[]="X:";
szDevicePath[0]=DriveLetter;
//".X:"->toopenthevolume
charszVolumeAccessPath[]=".X:";
szVolumeAccessPath[4]=DriveLetter;
longDeviceNumber=-1;
HANDLEhVolume=CreateFile(szVolumeAccessPath,0,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,0,NULL);
if(hVolume==INVALID_HANDLE_VALUE){
return1;
}
STORAGE_DEVICE_NUMBERsdn;
DWORDdwBytesReturned=0;
longres=DeviceIoControl(hVolume,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL,0,&sdn,sizeof(sdn),
&dwBytesReturned,NULL);
if(res){
DeviceNumber=Number;
}
CloHandle(hVolume);
if(DeviceNumber==-1){
return1;
}
UINTDriveType=GetDriveType(szRootPath);
//getthedosdevicename(likedevicefloppy0)
//todecideifit'safloppyornot
charszDosDeviceName[MAX_PATH];
res=QueryDosDevice(szDevicePath,szDosDeviceName,MAX_PATH);
if(!res){
return1;
}
DEVINSTDevInst=GetDrivesDevInstByDeviceNumber(DeviceNumber,
DriveType,szDosDeviceName);
if(DeviceNumber==-1){
return1;
}
Thenitenumeratesalldisks,floppiesorCD-ROMs—dependingonthedrivetype
andtheDOSdevicename—k'sdevicenumbersare
matchedwiththedevicenumbermentionedaboveinordertogetthedevice
instance:
Collap
//---------------------------------------------------------
DEVINSTGetDrivesDevInstByDeviceNumber(longDeviceNumber,
UINTDriveType,char*szDosDeviceName)
{
boolIsFloppy=(strstr(szDosDeviceName,
"Floppy")!=NULL);//isthereabetterway?
GUID*guid;
switch(DriveType){
caDRIVE_REMOVABLE:
if(IsFloppy){
guid=(GUID*)&GUID_DEVINTERFACE_FLOPPY;
}el{
guid=(GUID*)&GUID_DEVINTERFACE_DISK;
}
break;
caDRIVE_FIXED:
guid=(GUID*)&GUID_DEVINTERFACE_DISK;
break;
caDRIVE_CDROM:
guid=(GUID*)&GUID_DEVINTERFACE_CDROM;
break;
default:
return0;
}
//Getdeviceinterfaceinfothandle
//foralldevicesattachedtosystem
HDEVINFOhDevInfo=SetupDiGetClassDevs(guid,NULL,NULL,
DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
if(hDevInfo==INVALID_HANDLE_VALUE){
return0;
}
//Retrieveacontextstructureforadeviceinterface
//ofadeviceinformationt.
DWORDdwIndex=0;
BOOLbRet=FALSE;
BYTEBuf[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATApspdidd=
(PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
SP_DEVICE_INTERFACE_DATAspdid;
SP_DEVINFO_DATAspdd;
DWORDdwSize;
=sizeof(spdid);
while(true){
bRet=SetupDiEnumDeviceInterfaces(hDevInfo,NULL,
guid,dwIndex,&spdid);
if(!bRet){
break;
}
dwSize=0;
SetupDiGetDeviceInterfaceDetail(hDevInfo,
&spdid,NULL,0,&dwSize,NULL);
if(dwSize!=0&&dwSize<=sizeof(Buf)){
pspdidd->cbSize=sizeof(*pspdidd);//5Bytes!
ZeroMemory((PVOID)&spdd,sizeof(spdd));
=sizeof(spdd);
longres=
SetupDiGetDeviceInterfaceDetail(hDevInfo,&
spdid,pspdidd,
dwSize,&dwSize,
&spdd);
if(res){
HANDLEhDrive=CreateFile(pspdidd->DevicePath,0,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,NULL,NULL);
if(hDrive!=INVALID_HANDLE_VALUE){
STORAGE_DEVICE_NUMBERsdn;
DWORDdwBytesReturned=0;
res=DeviceIoControl(hDrive,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL,0,&sdn,sizeof(sdn),
&dwBytesReturned,NULL);
if(res){
if(DeviceNumber==(long)Number){
CloHandle(hDrive);
SetupDiDestroyDeviceInfoList(hDevInfo);
t;
}
}
CloHandle(hDrive);
}
}
}
dwIndex++;
}
SetupDiDestroyDeviceInfoList(hDevInfo);
return0;
}
//---------------------------------------------------------
Theparentdeviceofthedisk,floppyorCD-ROMistheUSBdevicetoeject.
CM_Request_Device_Ejectshallbeudfordeviceswhichhavethe
i,CM_Query_And_Remove_SubTree
Nhereandhere.
However,CM_Query_And_Remove_SubTreedoesn'tworkforrestrictedurs—it
returnsCR_ACCESS_DENIEDinthecas—whilethenon-suggested
CM_Request_Device_ista,wehave
toaddtheflagCM_REMOVE_NO_RESTARTbecauotherwithejust-removed
heeasywayandnowu
CM_Request_Device_Ejectexclusively.
Discussion
Herearesomeinterestinglinks:
/lists_archive/ntdev/
/MSDN/?PostID=705890&SiteI
D=1
IfyouuitforPATAdrives,thenbothmasterandslavedrivesareremoved!
However,bothcanbebroughtbackwithaDEVCONRESCAN.
IfthefunctionsarecalledwithNULL/0forthevetoparameters,thenXPshowsthe
"it'ssafenow"balloontip,
McCoyoncesaid:"vetochangethings."
IrememberthatI'veenCM_Query_And_Remove_SubTreeand
CM_Request_Device_EjectreturningCR_SUCCESSevenwhenthecallfailed
treproduceitbutI'msureI'veenthis,maybeitwas
oreitemstobebettertocheckthevetovaluesthatthe
functionsreturn.
UnderWindows2000,theANSIversionsofbothfunctionsarenotimplemented.
TheyreturnCR_CALL_NOT_IMPLEMENTED,soweutheUnicodeversionsinstead.
Bothfunctionsmaytakeveralcondsuntiltheyreturn,soit'sagoodideatoput
r,Ididn'tdothatinthissimpleexampleof
removal:
ULONGStatus=0;
ULONGProblemNumber=0;
PNP_VETO_TYPEVetoType=PNP_VetoTypeUnknown;
WCHARVetoNameW[MAX_PATH];
boolbSuccess=fal;
//getdrives'sparent,bridge,
//theSATAport,anIDEchannelwithtwodrives!
DEVINSTDevInstParent=0;
res=CM_Get_Parent(&DevInstParent,DevInst,0);
for(longtries=1;tries>=3;tries++){
//sometimesweneedsometries...
VetoNameW[0]=0;
res=CM_Request_Device_EjectW(DevInstParent,
&VetoType,VetoNameW,MAX_PATH,0);
bSuccess=(res==CR_SUCCESS&&
VetoType==PNP_VetoTypeUnknown);
if(bSuccess){
break;
}
Sleep(500);//requiredtogivethenexttriesachance!
}
It'softenenthattheremovalfailsonthefirstattemptbutworksonthecond
ore,Ijusttryitthreetimes.
WhatMakestheRemovalFail
Theprepartionforsaferemovalfailsaslongasthereisoneopenhandletothedisk
ouryoucannotrunthisEXEfromthedriveto
atyouwouldneedatemporarycopyonanotherdrive.
ProcessExplorerisgreatfordiscoveringwhichprocessholdsanopenhandletoa
trl+Fandenterthedriveletter,likeU:.I'veoftenenthatitcannot
resolvedriveletters,
shouldbesomethinglikeDeviceHarddisk4DP(1)0-0+ficantpart,such
as'disk4,'sion,however,eventhedriver-driven
ProcessExplorerisn'tabletofindthenastyhandle.
TheDemoProject
iresLIBsandheadersfromtheMicrosoft
estversionthatintegratesandworksperfectlywith
'scalledPlatformSDKforWindowsServer2003Build
3780.0andisstillavailablefordownload:
here
Unfortunately,takeitfrom
theVistaPlatformSDKorfromanyDDK/WDKsincebuild2600.
Ifyoudon'twanttodownloadawholeDDKforasinglefilethenyoucanuthe
heReactOSproject,
sfileinthatca.
History
15Jan2007-Updateddownload
27Jan2007-Updatedarticleanddownload,
CM_Query_And_Remove_SubTreeisn'tudanymore
16May2007-Updatedarticleanddownload;removed
SetupDiEnumInterfaceDevicebecauit'sjustadefinefor
SetupDiEnumDeviceInterfaceswhichhasbeencalledsomelinesbefore
7Nov2007-fixedthehintsabouttherequiredSDKforusingVS6
Licen
Thisarticle,alongwithanyassociatedsourcecodeandfiles,islicendunderThe
CodeProjectOpenLicen(CPOL)
本文发布于:2022-11-24 22:50:58,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/14750.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |