![]() |
|
USB memory stick detection |
|
| About |
This PRG source code implements the "DriveDetector" class. Objects of this class are capable of identifying the drives currently available, and detecting when a USB memory stick is inserted or removed by the user. The PRG code demonstrates four programming techniques available with The YUKON Project:
A "DriveDetector" object posts the following events to Xbase++'s event queue
|
| Screen shot |
|
| USBStick.prg |
// FILE: USBStick.prg
// Copyright (c) Hannes Ziegler, 2008
// This file is published as Open Source for The YUKON Project (www.knowleXbase.com)
//
// This program shows how to detect insertion or removal of a USB memory stick in PRG code
//
// Requirements:
// - Alaska Xbase++ version 1.9 or later
// - The YUKON Project build 85 or later
#include "AppEvent.ch"
#include "YUkonEVM.ch"
#define xbeP_DriveAdded xbeP_User + 1024
#define xbeP_DriveRemoved xbeP_User + 1025
PROCEDURE Main
LOCAL nEvent, mp1, mp2, oXbp, aDevInfo
LOCAL oDriveDetect := DriveDetector():new():create()
? "Add or remove a USB memory stick (press ESC to quit)"
?
nEvent := 0
DO WHILE nEvent <> xbeP_Close
nEvent := AppEventEx( @mp1, @mp2, @oXbp )
IF oXbp <> NIL
oXbp:HandleEvent( nEvent, mp1, mp2 )
ENDIF
DO CASE
CASE nEvent == xbeK_SPACE
CLS
CASE nEvent == xbeK_ESC
EXIT
CASE nEvent == xbeP_DriveAdded
? "Drive added :", mp1 + ":"
? oDriveDetect:getDrives()
?
CASE nEvent == xbeP_DriveRemoved
? "Drive removed:", mp1 + ":"
? oDriveDetect:getDrives()
?
ENDCASE
ENDDO
oDriveDetect:destroy()
RETURN self
/* ***************************************************************************
* Class monitoring available drives
* ************************************************************************* */
CLASS DriveDetector FROM XbpStaticEx
PROTECTED:
CLASS VAR msgs
VAR nDrives
VAR oDevStruct
VAR nHandle
EXPORTED:
CLASS METHOD initClass
METHOD init, create, destroy
METHOD getDrives, WM_DeviceChange
ENDCLASS
/* ***************************************************************************
* Load a hash table holding values of DBT_* notification messages
* ************************************************************************* */
CLASS METHOD DriveDetector:initClass()
IF ::msgs == NIL
::msgs := WinDefines( "DBT_*" )
ENDIF
RETURN self
/* ***************************************************************************
* Initialize the object
* ************************************************************************* */
METHOD DriveDetector:init( oParent )
::XbpStaticEx:init( oParent )
// get bitmask of drives currently available
::nDrives := KERNEL32.GetLogicalDrives()
// load the structure required for the RegisterDeviceNotification API
::oDevStruct := StructLoad( "DEV_BROADCAST_DEVICEINTERFACE" )
RETURN Self
/* ***************************************************************************
* Request system resources
* ************************************************************************* */
METHOD DriveDetector:create( oParent )
LOCAL nFlags, nMessage
// Create XbpStaticEx outside the visible area of the parent
// The DriveDetector window is unvisible
::XbpStaticEx:create( oParent, oParent, {-10,-10}, {1,1} )
// This is the sum of two #define constants of the Windows platform SDK
nFlags := WinDefines( "DEVICE_NOTIFY_WINDOW_HANDLE" , ;
"DEVICE_NOTIFY_ALL_INTERFACE_CLASSES" )
// Obtain a registration handle for device notifications
::nHandle := USER32.RegisterDeviceNotification( ::getHWND() , ;
::oDevStruct , ;
nFlags )
// This yields the numeric value of the WM_DEVICECHANGE #define constant
nMessage := WinDefines( "WM_DEVICECHANGE" )
// Register a callback code block for the WM_DEVICECHANGE message
::setCallback( nMessage, ;
{|obj,msg,wParam,lParam| obj:WM_DeviceChange( wParam, lParam ) } )
RETURN self
/* ***************************************************************************
* Cleanup memory
* ************************************************************************* */
METHOD DriveDetector:destroy()
LOCAL nMsg := Windefines( "WM_DEVICECHANGE" )
// release the callback code block
::setCallback( nMsg, NIL )
// release the notification handle
USER32.UnregisterDeviceNotification( ::nHandle )
::nHandle := 0
// release the structure
kill::oDevStruct
// release the window
::XbpStaticEx:destroy()
RETURN self
/* ***************************************************************************
* Return drives currently available in an array
* ************************************************************************* */
METHOD DriveDetector:getDrives()
LOCAL nInBytes := 4096
LOCAL nOutBytes:= 0
LOCAL cBuffer := ZeroStr( nInBytes )
nOutBytes := KERNEL32.GetLogicalDriveStrings( nInBytes, @cBuffer )
RETURN SplitStr( Left(cBuffer,nOutBytes), Chr(0) )
/* ***************************************************************************
* Process the WM_DEVICECHANGE message
* ************************************************************************* */
METHOD DriveDetector:WM_DeviceChange( wParam, lParam )
LOCAL lDriveAdded, nOldDrives, nNewDrives, cDrive, i
IF wParam == ::msgs:DBT_DEVICEARRIVAL
lDriveAdded := .T.
ELSEIF wParam == ::msgs:DBT_DEVICEREMOVECOMPLETE
lDriveAdded := .F.
ENDIF
IF lDriveAdded == NIL
RETURN self
ENDIF
nOldDrives := ::nDrives
nNewDrives := KERNEL32.GetLogicalDrives()
IF nOldDrives == nNewDrives
RETURN self
ENDIF
::oDevStruct:loadFrom( lParam )
// Find the drive letter that has changed
FOR i:=1 TO 32
IF nOldDrives[i] <> nNewDrives[i]
cDrive := Chr(64+i)
EXIT
ENDIF
NEXT
::nDrives := nNewDrives
IF lDriveAdded
PostAppEvent( xbeP_DriveAdded , cDrive, ::oDevStruct:dbcc_name, ::setParent() )
ELSE
PostAppEvent( xbeP_DriveRemoved, cDrive, ::oDevStruct:dbcc_name, ::setParent() )
ENDIF
RETURN 1
/* ***************************************************************************
* Structure required for the RegisterDeviceNotification API
* ************************************************************************* */
STRUCTURE DEV_BROADCAST_DEVICEINTERFACE SIZEOF 540
MEMBER dbcc_size AT 0 IS DWORD
MEMBER dbcc_devicetype AT 4 IS DWORD
MEMBER dbcc_reserved AT 8 IS DWORD
MEMBER dbcc_classguid AT 12 IS UUID
MEMBER dbcc_name AT 28 IS CHAR SIZEOF 512 // Make this large enough to receive the device name string
DEFAULT MEMBER ;
dbcc_size := 540 , ;
dbcc_devicetype := WinDefines( "DBT_DEVTYP_DEVICEINTERFACE" )
STRUCTEND
|
| Copyright © Dr. Hannes Ziegler 2008 | |