Tech Support > Microsoft Windows > Drivers > Safely Remove USB Device
Safely Remove USB Device
Posted by Ivana Rebczek on February 21st, 2005


Hi all.

I'm trying to do what's done with the little icon "Safely remove hardware".
I found something about a hotplug.dll and various other things, but there
was nothing on how to really achieve what I want.

It would be great if someone could help me with that. I'm able to display
the "remove dialog", but it should be without the dialog!

Ivana


Posted by Calvin Guan on February 21st, 2005


Are you saying you don't want the "safely remove" icon? You can monitor the
IRP_MJ_PNP/IRP_MN_QUERY_CAPABILITIES and set the SurpriseRemoveOK on the
IRP's way back.

--
Calvin Guan Software Engineer/Radeon NT Drivers
ATI Technologies Inc. Markham ON, Canada www.ati.com

"Ivana Rebczek" <dontspam_ivanarebczek@yahoo.de> wrote in message
news:eBI5YrBGFHA.444@TK2MSFTNGP15.phx.gbl...


Posted by Ivana Rebczek on February 21st, 2005


Not quite.
There is a device which should be removable by my application. So the app
should perform the same thing the "safely remove hardware"-button/icon does.

Ivana

"Calvin Guan" <cguan@pleasenospam.ati.com> schrieb im Newsbeitrag
news:OtCGKjCGFHA.2876@TK2MSFTNGP12.phx.gbl...


Posted by Robert Marquardt on February 21st, 2005


Ivana Rebczek wrote:

For that you need to call CM_Request_Device_Eject. The first Parameter
is the DevInst. DevInst you get from enumerating devices with SetupDi
functions. SetupDiGetDeviceInterfaceDetail returns DevInst and the
device path for CreateFile.

Beware, some devices react to CM_Request_Device_Eject even if they
should not. I was able to eject my mice which is really infuriating.

Posted by Pavel A. on February 22nd, 2005


"Robert Marquardt" <robert_marquardt@gmx.de> wrote in message news:#h3jsUEGFHA.1456@TK2MSFTNGP09.phx.gbl...
Good that you didn't try eject CPU cooling fans

--PA




Posted by Robert Marquardt on February 22nd, 2005


Pavel A. wrote:

That is the job of fan speed tools ;-)

The problem i have is that i expected the mice to never react to safe
removal. After all the mice are opened by the system with aa exclusive
CreateFile call.

Posted by Ivana Rebczek on February 22nd, 2005


Hm. I can't get this to work.
I found this C example here:
http://www.codeguru.com/forum/showth...174#post891174

But it seems to me that this is not the right way.
Or at least I don't want to test it, because there might be unwanted
problems after that.

I only want to eject my USB stick via code, didn't know it would be that
hard.

So if you or someone else could propose a little example code it would be
great!

Ivana

"Pavel A." <pavel_a@NOwritemeNO.com> schrieb im Newsbeitrag
news:euxNPUHGFHA.444@TK2MSFTNGP15.phx.gbl...


Posted by Robert Marquardt on February 23rd, 2005


Ivana Rebczek wrote:

That example is bad.

Here is some code from another message here.
The DevInst from the second CM_Get_parent is the one you need to feed to
CM_Request_Device_Eject.


Subject:
RE: How to match between physical usb device and its drive letter?
From:
"Kiran" <Kiran@discussions.microsoft.com>
Date:
Wed, 20 Oct 2004 22:01:02 -0700
Newsgroups:
microsoft.public.development.device.drivers

Hi,

There is no simple/direct way of obtaining the drive letter.

The following code can be used to get the drive letter
But you have to modify them here and there to meet you need.

Kiran


struct tagDrives
{
WCHAR letter;
WCHAR volume[BUFFER_SIZE];
} g_drives[26];

//
WCHAR GetUSBDrive()
{
LPTSTR lpDevID;
WCHAR cDrive;
DWORD dwSize = BUFFER_SIZE;

// Get all removable disks on user laptop.
if(!GetAllRemovableDisks())
{
WRITELOG("Error - GetAllRemovableDisks failed\n");
return 0;
}

// Alocate memory to device ID
lpDevID = (LPTSTR)AllocMem(BUFFER_SIZE);

// Get device ID corresponding to USBFM from registry.
if(!GetRegValue(lpDevID, DEVICE_ID, dwSize))
{
WRITELOG("Error - Registry - USBFMDevID failed\n");
FreeMem(lpDevID);
return 0;
}

// Get drive corresponding to the registry entry.
cDrive = GetSpecificDrive(lpDevID);

FreeMem(lpDevID);

// return the drive letter.
return cDrive;
}

/************************************************** ****************************
* GetAllRemovableDisks - This function retrieves volume information for all
removable disks
*
* In: None
*
* Out: TRUE - Success
* FALSE - Failure
*
************************************************** *****************************/

BOOL GetAllRemovableDisks()
{
WCHAR caDrive[4];
WCHAR volume[BUFFER_SIZE];
int nLoopIndex;
DWORD dwDriveMask;

caDrive[0] = 'A';
caDrive[1] = ':';
caDrive[2] = '\\';
caDrive[3] = 0;

g_count = 0;

// Get all drives in the system.
dwDriveMask = GetLogicalDrives();

if(dwDriveMask == 0)
{
WRITELOG("Error - GetLogicalDrives failed\n");
return FALSE;
}

// Loop for all drives (MAX_DRIVES = 26)

for(nLoopIndex = 0; nLoopIndex< MAX_DRIVES; nLoopIndex++)
{
// if a drive is present,
if(dwDriveMask & 1)
{
caDrive[0] = 'A' + nLoopIndex;

// If a drive is removable
if(GetDriveType(caDrive) == DRIVE_REMOVABLE)
{
//Get its volume info and store it in the global variable.
if(GetVolumeNameForVolumeMountPoint(caDrive, volume, BUFFER_SIZE))
{
g_drives[g_count].letter = caDrive[0];
wcscpy(g_drives[g_count].volume, volume);
g_count ++;
}

}
}
dwDriveMask >>= 1;
}

// success if atleast one removable drive is found.
if(g_count == 0)
{
return FALSE;
}
else
{
return TRUE;
}
}

/************************************************** ****************************
* GetSpecificDrive - This function returns the drive corresponding to the
given device ID
*
* In : lpDevID - Device ID
*
* Return: Drive letter corresponding to the given device ID.
*
************************************************** *****************************/

WCHAR GetSpecificDrive(
LPTSTR lpDevID)
{
HDEVINFO hDevInfo;
GUID guid;
BYTE buffer[BUFFER_SIZE];
DWORD dwRequiredSize ;
WCHAR buf[BUFFER_SIZE];
DEVINST devInstParent;
DWORD dwIndex;
WCHAR volume[BUFFER_SIZE];
int nLength,nLoopIndex;

SP_DEVICE_INTERFACE_DATA devInterfaceData;
SP_DEVINFO_DATA devInfoData;
PSP_DEVICE_INTERFACE_DETAIL_DATA pDevDetail;

if(!lpDevID)
{
return 0;
}

// GUID_DEVINTERFACE_VOLUME is interface Guid for Volume class devices.
guid = GUID_DEVINTERFACE_VOLUME;


// Get device Information handle for Volume interface
hDevInfo = SetupDiGetClassDevs(&guid, NULL, NULL,
DIGCF_DEVICEINTERFACE |
DIGCF_PRESENT);

if(hDevInfo == INVALID_HANDLE_VALUE)
{
WRITELOG("Error - SetupDiGetClassDevs failed\n");
return 0;
}

// Loop until device interfaces are found.
for(dwIndex = 0; ;dwIndex ++)
{
ZeroMemory(&devInterfaceData, sizeof(devInterfaceData));
devInterfaceData.cbSize = sizeof(devInterfaceData);

// Get device Interface data.

if(!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &guid,
dwIndex,&devInterfaceData))
{
break;
}

ZeroMemory(&devInfoData, sizeof(devInfoData));
devInfoData.cbSize = sizeof(devInfoData);

pDevDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)buffer;
pDevDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

// Get device interface detail data to get
// Device Instance from SP_DEVINFO_DATA and
// Device Path from SP_DEVICE_INTERFACE_DETAIL_DATA

SetupDiGetDeviceInterfaceDetail(hDevInfo,
&devInterfaceData,
pDevDetail, // SP_DEVICE_INTERFACE_DETAIL_DATA
BUFFER_SIZE,
&dwRequiredSize,
&devInfoData); // SP_DEVINFO_DATA

// Get the device instance of parent. This points to USBSTOR.
CM_Get_Parent(&devInstParent,devInfoData.DevInst, 0);

// Get the device instance of grand parent. This points to USB root.
CM_Get_Parent(&devInstParent,devInstParent, 0);

// Get the device ID of the USB root.
CM_Get_Device_ID(devInstParent, buf, BUFFER_SIZE,0);

// If USB root device matches with the input device ID, it is the target
device.

if( buf != NULL && wcscmp(lpDevID,buf) == 0)
{
// Append \ to the DevicePath of SP_DEVICE_INTERFACE_DETAIL_DATA

nLength = wcslen(pDevDetail->DevicePath);
pDevDetail->DevicePath[nLength] = '\\';
pDevDetail->DevicePath[nLength+1] = 0;

// Get Volume mount point for the device path.
if(GetVolumeNameForVolumeMountPoint(pDevDetail->DevicePath, volume,
BUFFER_SIZE))
{
for(nLoopIndex=0; nLoopIndex< g_count; nLoopIndex++)
{
// Compare volume mount point with the one stored earlier.
// If both match, return the corresponding drive letter.

if(wcscmp(g_drives[nLoopIndex].volume, volume)==0)
{
SetupDiDestroyDeviceInfoList(hDevInfo);
return g_drives[nLoopIndex].letter;
}
}
}
}
}

SetupDiDestroyDeviceInfoList(hDevInfo);
WRITELOG("Error - No drives found in GetSpecificDrives\n");
return 0;
}

Posted by Stefan de Buhr on March 1st, 2005


Moin,

I once wrote the following small code to do the job. You might need to
change the USB ID.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~


#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <setupapi.h>
#include <devguid.h>


/*
* -- Definitions:
*/
const char* TelkoID = "USB\\VID_090A&PID_1540";

/*
* The buffer receives the hardware ID.
*/
#define ID_BUFFER_SIZE 512
BYTE gBuffer[ID_BUFFER_SIZE];

/*
* -- Local protoypes:
*/
BOOL RemoveDevice(const char*);


/*
*
*/
int main(void)
{
BOOL status;

status = RemoveDevice(TelkoID);

if (status == FALSE)
{
printf("Failed to remove Telko\n");
}

return 0;
}

/*
* -- RemoveDevice
*
* This function removes the device specified by the supplied ID.
* Returns TRUE if the device was removed, otherwise FALSE.
*
* First we collect all currently present USB devices in a device info set.
* Then we enumerate those devices and get their hardware IDs. Then we check
* if "our" device is present. If so then we remove the device.
*/
BOOL RemoveDevice(const char* DeviceID)
{
BOOL deviceRemoved = FALSE;
HDEVINFO devInfoSet = INVALID_HANDLE_VALUE;
BOOL status = FALSE;

/*
* Retrieve a device info set with currently present USB devices:
*/
devInfoSet =
SetupDiGetClassDevs(&GUID_DEVCLASS_USB,NULL,INVALI D_HANDLE_VALUE,DIGCF_PRESENT);

if (devInfoSet != INVALID_HANDLE_VALUE)
{
SP_DEVINFO_DATA devInfoData;
DWORD requiredSize;
DWORD index = 0;

/*
* Enumerate the USB devices:
*/
do
{
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
status = SetupDiEnumDeviceInfo(devInfoSet,index,&devInfoDat a);
if (status == 0) break;

status =
SetupDiGetDeviceRegistryProperty(devInfoSet,&devIn foData,SPDRP_HARDWAREID,NULL,gBuffer,ID_BUFFER_SIZ E,&requiredSize);
if (status == 0) break;

/*
* Windows 98 returns the hardware ID in upper case.
* Windows XP returns it in mixed case.
* So we convert the ID to upper case to have a defined
* behaviour so that we can compare with the upper case
* hardware ID:
*/
_strupr(gBuffer);

if (strncmp(DeviceID,gBuffer,strlen(DeviceID)) == 0)
{
/* We found our device, so remove it: */
status = SetupDiRemoveDevice(devInfoSet,&devInfoData);
if (status == 0)
{
deviceRemoved = TRUE;
}

/* We are done removing the device. */
break;
}

index += 1;

} while (status != 0);

/* Clean up the device info set: */
SetupDiDestroyDeviceInfoList(devInfoSet);
}

return deviceRemoved;
}