Re: USB Device Shut Down\Dispositivo USB Apagar
Posted: Wed Nov 04, 2015 2:14 am
Fantastic Pete!
Exclusive forum for HMG, a Free / Open Source xBase WIN32/64 Bits / GUI Development System
http://www.hmgforum.com/
Hi Pete,PeteWG wrote:Hi,
try the code below to see if it serves your purpose:
...
regards,
Pete
Code: Select all
#pragma BEGINDUMP
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
#include <stdio.h>
#include "hbapi.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:\\");
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:
return INVALID_HANDLE_VALUE;
}
wsprintf(szVolumeName, szVolumeFormat, cDriveLetter);
hVolume = CreateFile( szVolumeName,
dwAccessFlags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
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;
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 );
}
BOOL 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;
hVolume = OpenVolume(cDriveLetter);
if( hVolume == INVALID_HANDLE_VALUE )
return FALSE;
if( LockVolume(hVolume) && DismountVolume(hVolume) )
{
fRemoveSafely = TRUE;
if ( PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume) )
fAutoEject = TRUE;
}
if( ! CloseVolume(hVolume) )
return FALSE;
return ( fRemoveSafely && fAutoEject );
}
HB_FUNC( EJECTREMOVABLE )
{
char * szDrive = (char *) hb_parc( 1 );
hb_retl( EjectVolume( *szDrive ) );
}
#pragma ENDDUMPCode: Select all
// test program
request hb_gt_win_default
PROC MAIN( cDriveLetter )
hb_Default( @cDriveLetter, "G:" )
IF EjectRemovable( cDriveLetter )
? "The drive " + cDriveLetter + " can be safely removed."
ELSE
? "Failed to safely remove/eject drive " + cDriveLetter
ENDIF
WAIT
RETURN
// end test program
#pragma BEGINDUMP
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
#include <stdio.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:\\");
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:
return INVALID_HANDLE_VALUE;
}
wsprintf(szVolumeName, szVolumeFormat, cDriveLetter);
hVolume = CreateFile( szVolumeName,
dwAccessFlags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
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;
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 );
}
BOOL 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;
hVolume = OpenVolume(cDriveLetter);
if( hVolume == INVALID_HANDLE_VALUE )
return FALSE;
if( LockVolume(hVolume) && DismountVolume(hVolume) )
{
fRemoveSafely = TRUE;
if( PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume) )
fAutoEject = TRUE;
}
if( ! CloseVolume(hVolume) )
return FALSE;
return ( fRemoveSafely && fAutoEject );
}
#include "hbapi.h"
HB_FUNC( EJECTREMOVABLE )
{
char * szDrive = (char *) hb_parc( 1 );
BOOL retval = EjectVolume( *szDrive );
if( retval )
SHChangeNotify( SHCNE_DRIVEREMOVED, SHCNF_PATH , szDrive, NULL );
hb_retl( retval );
}
#pragma ENDDUMP
Very good!PeteWG wrote:Hi,
(thanks for any "thanks" <g>)
@grigory
Well, the code i posted was of a "quick and dirty" kind.
I think, I had spotted the warnings but I (lazy!) cared not to pacify them;
it's nice that you took the time to do it.
Furthermore, the 1st version of the function was not only "warning-fraught", but also incomplete. (however, it did the job..)
Below is the 2nd version, enriched with one more operation: to notify Explorer that the disk has been removed, to stop displaying it (in case of USB), in the pane.
Code: Select all
// test program request hb_gt_win_default PROC MAIN( cDriveLetter ) hb_Default( @cDriveLetter, "G:" ) IF EjectRemovable( cDriveLetter ) ? "The drive " + cDriveLetter + " can be safely removed." ELSE ? "Failed to safely remove/eject drive " + cDriveLetter ENDIF WAIT RETURN // end test program #pragma BEGINDUMP #include <windows.h> #include <winioctl.h> #include <tchar.h> #include <stdio.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:\\"); 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: return INVALID_HANDLE_VALUE; } wsprintf(szVolumeName, szVolumeFormat, cDriveLetter); hVolume = CreateFile( szVolumeName, dwAccessFlags, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); 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; 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 ); } BOOL 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; hVolume = OpenVolume(cDriveLetter); if( hVolume == INVALID_HANDLE_VALUE ) return FALSE; if( LockVolume(hVolume) && DismountVolume(hVolume) ) { fRemoveSafely = TRUE; if( PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume) ) fAutoEject = TRUE; } if( ! CloseVolume(hVolume) ) return FALSE; return ( fRemoveSafely && fAutoEject ); } #include "hbapi.h" HB_FUNC( EJECTREMOVABLE ) { char * szDrive = (char *) hb_parc( 1 ); BOOL retval = EjectVolume( *szDrive ); if( retval ) SHChangeNotify( SHCNE_DRIVEREMOVED, SHCNF_PATH , szDrive, NULL ); hb_retl( retval ); } #pragma ENDDUMP
@Nikos
>It is also possible to enable later the same drive (or a drive)
if I understood correctly, you mean the same drive-letter. my answer is: I dont know if this is possible, but i think that Windows "remember" the previous used drive-letter for a removable drive and try to give the same letter unless it is already occupied.
>How to become disconnect a map network drive
hmm, I guess that if the disk is mapped to a letter, the function should be able to eject it. otherwise maybe the UNC name of the drive must be used. you have to test it!
> How to become enable it
if you mean how to re-enable it without take it out and re-insert, this need further investigation. I will try to find a way, if time permits.. (or maybe some other guy here could help it.)
regards,
Pete