use Win32; use strict; use Win32::OLE qw( in ); use Win32::Daemon; use Win32::API::Prototype; # Declare api ApiLink( 'kernel32.dll', 'BOOL DeleteVolumeMountPoint( LPCTSTR lpszVolumeMountPoint )' ) || die; ApiLink( 'kernel32.dll', 'BOOL SetVolumeMountPoint( LPCTSTR lpszVolumeMountPoint, LPCTSTR lpszVolumeName ) ' ) || die; ApiLink( 'kernel32.dll', 'BOOL GetVolumeNameForVolumeMountPoint( LPCTSTR lpszVolumeMountPoint, LPTSTR lpszVolumeName, DWORD cchBufferLength )' ) || die; my ($State); my $SERVICE_SLEEP_TIME = 20; # 20 milliseconds my $PrevState = SERVICE_START_PENDING; # Start one loop to manage the services while( SERVICE_STOPPED != ( $State = Win32::Daemon::State() ) ) { if( SERVICE_START_PENDING == $State ) { # Initialization code Win32::Daemon::State( SERVICE_RUNNING ); $PrevState = SERVICE_RUNNING; } elsif( SERVICE_STOP_PENDING == $State ) { Win32::Daemon::State( SERVICE_STOPPED ); } elsif( SERVICE_PAUSE_PENDING == $State ) { # "Pausing..."; Win32::Daemon::State( SERVICE_PAUSED ); $PrevState = SERVICE_PAUSED; next; } elsif( SERVICE_CONTINUE_PENDING == $State ) { # "Resuming..."; Win32::Daemon::State( SERVICE_RUNNING ); $PrevState = SERVICE_RUNNING; next; } elsif( SERVICE_STOP_PENDING == $State ) { # "Stopping..."; Win32::Daemon::State( SERVICE_STOPPED ); $PrevState = SERVICE_STOPPED; next; } elsif( SERVICE_RUNNING == $State ) { my $VolumeMountPoint = GetLogicalDisk(); # if the drive is not U:, change if ( $VolumeMountPoint ne "U:" ) { my $VolumeName = NewString( 256 ); if (! GetVolumeNameForVolumeMountPoint ("$VolumeMountPoint\\", $VolumeName, 256) ) { print Win32::GetLastError(); } else { $VolumeName =~ /(\x00)/; $VolumeName = $`; # Remove null } if (! DeleteVolumeMountPoint("$VolumeMountPoint\\") ) { print Win32::GetLastError(); } if (! SetVolumeMountPoint ("U:\\", $VolumeName )) { print Win32::GetLastError(); } } } else { # Got an unhandled control message. Set the state to # whatever the previous state was. Win32::Daemon::State( $PrevState ); } # Check for any outstanding commands. Pass in a non zero value # and it resets the Last Message to SERVICE_CONTROL_NONE. if( SERVICE_CONTROL_NONE != ( my $Message = Win32::Daemon::QueryLastMessage( 1 ) ) ) { if( SERVICE_CONTROL_INTERROGATE == $Message ) { # Got here if the Service Control Manager is requesting # the current state of the service. This can happen for # a variety of reasons. Report the last state we set. Win32::Daemon::State( $PrevState ); } elsif( SERVICE_CONTROL_SHUTDOWN == $Message ) { # Yikes! The system is shutting down. We had better clean up # and stop. # Tell the SCM that we are preparing to shutdown and that we expect # it to take 25 seconds (so don't terminate us for at least 25 seconds)... Win32::Daemon::State( SERVICE_STOP_PENDING, 25000 ); } } # Snooze for awhile so we don't suck up cpu time... Win32::Sleep( $SERVICE_SLEEP_TIME ); } # We are done so close down... Win32::Daemon::StopService(); sub GetLogicalDisk { # Here, you could do a query to verify if the USB driver in on Windows, # look at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/win32_logicaldisk.asp # site to verify wich value you could use, like serialnumber or volume name my $WMIServices = Win32::OLE->GetObject ( "winmgmts:{impersonationLevel=impersonate, (security)}//./root/cimv2" ) || die; my $DriveCollection = $WMIServices->ExecQuery ( 'select * from Win32_LogicalDisk where VolumeSerialNumber = "2CBE1114"' ) || die "Query Failed"; foreach my $Drive ( in( $DriveCollection ) ) { return $Drive->{'Name'}; } }