USB Device Shut Down\Dispositivo USB Apagar

General Help regarding HMG, Compilation, Linking, Samples

Moderator: Rathinagiri

User avatar
Rathinagiri
Posts: 5481
Joined: Tue Jul 29, 2008 6:30 pm
DBs Used: MariaDB, SQLite, SQLCipher and MySQL
Location: Sivakasi, India
Contact:

Re: USB Device Shut Down\Dispositivo USB Apagar

Post by Rathinagiri »

Fantastic Pete!
East or West HMG is the Best.
South or North HMG is worth.
...the possibilities are endless.
User avatar
gfilatov
Posts: 1100
Joined: Fri Aug 01, 2008 5:42 am
Location: Ukraine
Contact:

Re: USB Device Shut Down\Dispositivo USB Apagar

Post by gfilatov »

PeteWG wrote:Hi,

try the code below to see if it serves your purpose:

...

regards,
Pete
Hi Pete,

Thanks for sharing! It works fine at Win 7 here 8-)

Please take a look for an updated C-code without the warnings below:

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 ENDDUMP
Thanks again!
Kind Regards,
Grigory Filatov

"Everything should be made as simple as possible, but no simpler." Albert Einstein
User avatar
serge_girard
Posts: 3343
Joined: Sun Nov 25, 2012 2:44 pm
DBs Used: 1 MySQL - MariaDB
2 DBF
Location: Belgium
Contact:

Re: USB Device Shut Down\Dispositivo USB Apagar

Post by serge_girard »

Thanks Grigory !

Serge
There's nothing you can do that can't be done...
User avatar
quartz565
Posts: 670
Joined: Mon Oct 01, 2012 12:37 pm
Location: Thessaloniki, Greece
Contact:

Re: USB Device Shut Down\Dispositivo USB Apagar

Post by quartz565 »

Hi pete,
It is also possible to enable later the same drive (or a drive)
How to become disconnect a map network drive
How to become enable it
Thank you again :!:
Best Regards,
Nikos.

os: Windows Server 2019 - 64
PeteWG
Posts: 176
Joined: Sun Mar 21, 2010 5:45 pm

Re: USB Device Shut Down\Dispositivo USB Apagar

Post by PeteWG »

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
User avatar
vagblad
Posts: 174
Joined: Tue Jun 18, 2013 12:18 pm
DBs Used: MySQL,DBF
Location: Thessaloniki, Greece

Re: USB Device Shut Down\Dispositivo USB Apagar

Post by vagblad »

I am sorry for the delayed post, i am home with a bad cold. :(

@Pete
Thanks a lot Pete! It also works flawlessly at windows 10. It doesn't work on Windows Server 2012, but maybe it is something permission-related.
I will test it some more and then i will post back.

@Grigory
Thanks a lot Grigory!

Everyone's help is much appreciated once more.Thanks a lot to all of you.
Vagelis Prodromidis
Email: vagblad@gmail.com, Skype: vagblad
User avatar
danielmaximiliano
Posts: 2646
Joined: Fri Apr 09, 2010 4:53 pm
Location: Argentina
Contact:

Re: USB Device Shut Down\Dispositivo USB Apagar

Post by danielmaximiliano »

Gracias Grigory ...
*´¨)
¸.·´¸.·*´¨) ¸.·*¨)
(¸.·´. (¸.·` *
.·`. Harbour/HMG : It's magic !
(¸.·``··*

Saludos / Regards
DaNiElMaXiMiLiAnO

Whatsapp. := +54901169026142
Telegram Name := DaNiElMaXiMiLiAnO
User avatar
srvet_claudio
Posts: 2223
Joined: Thu Feb 25, 2010 8:43 pm
Location: Uruguay
Contact:

Re: USB Device Shut Down\Dispositivo USB Apagar

Post by srvet_claudio »

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
Very good!
Best regards.
Dr. Claudio Soto
(from Uruguay)
http://srvet.blogspot.com
User avatar
quartz565
Posts: 670
Joined: Mon Oct 01, 2012 12:37 pm
Location: Thessaloniki, Greece
Contact:

Re: USB Device Shut Down\Dispositivo USB Apagar

Post by quartz565 »

Hi Pete thank you,
As the Vagelis already has written, It doesn't work on Windows Server 2012 at any hard drive (usb or sata).
The only thing it does, if you select a DVD drive letter the program ejects the drive without disabling it. :(

do you think there is any solution, any ideas?
Best Regards,
Nikos.

os: Windows Server 2019 - 64
Post Reply