Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

EjectDrive

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • PBWin EjectDrive

    EjectDrive DDT VER. 1


    Based on Drive Ejection method from Bernhard Fomm 2 Feb 2017, 08:22 PM
    found here.

    Comments here.

    Note:
    All cards must have a name to be recognized.
    Only the CF Cards have to have CF_ in their name.
    All testing was performed on Win10.
    There may be some code issues with Win7.


    Modified to work with PBWIN10.4 and J. Roca includes.
    Updated to recognize JMICRON drives as removable drives and not fixed drives.
    Will eject those USB to SATA drives as though they were thumbdrives..

    Also based on work by myself on DriveChange.

    Object:
    To eject all selected removable drives. If successful then the method will
    be incorporated into DriveChange.

    Works on:
    SD cards
    CF Cards
    USB Thumb drives
    CD/DVD drives
    Portable USB drives with USB to SATA bridges JMICRON type.

    Success!

    Disclaimer:
    EjectDrive does not determine if the drive is currently being
    used by another application which would preclude ejection but
    it can tell you quite a bit about the process if you enable the
    comments by changing the ShowMessage value from 0 to 1.
    Most of the time for removable drives and CD/DVD drives a
    simplified 1 and done method is used which should cause
    them to eject.


    USB to SATA bridge drives are different from the pack in that
    their ejection method is a bit more elaborate in that the parent
    container must be ejected.


    EjectDrive does not try to eject FIXED, REMOTE, RAMDISK,
    UNKNOWN, or NO_ROOT_DIR drives.


    Also Floppy drives have not been tested.


    EjectDrive_DDT.zip
    Attached Files
    Last edited by Jim Fritts; 7 Oct 2019, 08:50 AM.

  • #2
    Hey Jim,

    This is very cool! Tremendous work! I'm going to try it out on all the drives I have available, and will let you know how it goes.

    If I may be so bold, I'm going to make a suggestion that is trivial compared to what you've created, but I think it could make it a little easier to use.

    Where the source says this:
    Code:
       Call EjectVolume("F")   '<=== change this drive letter. See "HERE"
    Change to this:
    Code:
       Call EjectVolume(sCmdLine)
    and precede with this:
    Code:
        Local sCmdLine    As String
        Local sTemp       As String
    
       sCmdLine = UCase$(Trim$(Command$, Any $Spc & "\:"))
       Do Until Len(sCmdLine) = 1 And InStr(Chr$(65 To 90), sCmdLine)
          sTemp = InputBox$("Please enter a drive letter: ", "Eject Drive", "F")
          If Len(Trim$(sTemp)) = 0 Then Exit Function
          sCmdLine = UCase$(Trim$(sTemp, Any $Spc & "\:"))
       Loop
    Now it can be invoked from a command prompt, or from a .BAT or shortcut, with or without a target param...

    Again, thanks for a very cool addition to the toolbox,
    -John

    Comment


    • #3
      Jim,

      I'm running on Win 7 Pro, and I tried EjectDrive on a CD and a microSD (in a carrier/adapter for full-size SD cards).

      The CD is recognized and ejected, no problem.

      The microSD card was not initially recognized, so I followed the notes about CF_ cards, and changed the Volume Label to "SD Card".
      Now it's recognized, and it takes about 20 seconds, and the program reports that the card is ejected. (Physically, it remains clicked into the slot...)

      HOWEVER, the card remains in the Windows Explorer list, and the sys tray tool "Safely Remove Hardware and Eject Media" continues to show "SD Card".

      I don't want to remove the card if Windows thinks it's still there, so my question is: has Windows simply not updated drive status, or is the card really not "ejected"? How would I be able to tell? (Running EjectDrive again still shows the card - so I'm not sure that it was truly "removed/ejected")

      Thanks,
      -John

      [ADDED] Ah HA!
      OK, so I had zTreeWin running when I was testing, and had logged the SD Card. Once I released the drive from zTreeWin, then EjectDrive was able to complete the remove/eject, AND the card did come off the My Computer list, as well as from the sys tray tool.

      That being said, it would appear that EjectDrive is reporting success too soon, not detecting that another program is preventing it from being truly released/removed/ejected...???


      Comment


      • #4
        John,
        We should switch to here for comments. Thanks
        Last edited by Jim Fritts; 7 Oct 2019, 07:56 AM.

        Comment


        • #5
          EjectDrive SDK VER. 1

          Click image for larger version  Name:	New Bitmap Image.jpg Views:	3 Size:	37.2 KB ID:	785628

          Sorry John,
          I did not add any handling for command line directives.

          EjectDrive_SDK_1.zip
          Attached Files

          Comment


          • #6
            For those that appreciate searchable info here is the ejection routines separate.

            Code:
            '_________________________________________________________________
            '
            ' FUNCTION LockVolume
            '_________________________________________________________________
            
            FUNCTION LockVolume(BYVAL hVolume AS DWORD) AS LONG
                LOCAL lpBytesReturned AS DWORD
                LOCAL lpOverlapped    AS OVERLAPPED
                LOCAL dwSleepAmount   AS DWORD
                LOCAL nTryCount       AS LONG
                LOCAL lReturn         AS DWORD
            
                'Once this function returns successfully, the application is guaranteed
                'that the volume is not used by anything else in the system.
            
                dwSleepAmount = %LOCK_TIMEOUT / %LOCK_RETRIES
            
                FOR nTryCount = 1 TO %LOCK_RETRIES
                    SetLastError(%ERROR_SUCCESS) 'Clear previous error, if any
                    lReturn = %TRUE
                    lReturn = DeviceIoControl( _
                              hVolume            _
                            , %FSCTL_LOCK_VOLUME _
                            , BYVAL %NULL        _
                            , 0                  _
                            , BYVAL %NULL        _
                            , 0                  _
                            , lpBytesReturned    _
                            , BYVAL %NULL)
            
                    'If the operation completes successfully, the return value is nonzero.
                    CALL ShowErrorText(lReturn, "LockVolume", 0)
            
                    IF lReturn > 0 THEN
                        FUNCTION = %TRUE
                        EXIT FUNCTION
                    END IF
                    SLEEP dwSleepAmount
                NEXT
            
                FUNCTION = %FALSE
            END FUNCTION
            '_________________________________________________________________
            '
            ' FUNCTION UnLockVolume
            '_________________________________________________________________
            
            FUNCTION UnLockVolume(BYVAL hVolume AS DWORD) AS LONG
                LOCAL lpBytesReturned AS DWORD
                LOCAL lpOverlapped    AS OVERLAPPED
                LOCAL dwSleepAmount   AS DWORD
                LOCAL nTryCount       AS LONG
                LOCAL lReturn         AS DWORD
            
                dwSleepAmount = %LOCK_TIMEOUT / %LOCK_RETRIES
            
                FOR nTryCount = 1 TO %LOCK_RETRIES
                    SetLastError(%ERROR_SUCCESS) 'Clear previous error, if any
                    lReturn = %TRUE
                    lReturn = DeviceIoControl( _
                            hVolume        _
                          , %FSCTL_UNLOCK_VOLUME _
                          , BYVAL %NULL          _
                          , 0                    _
                          , BYVAL %NULL          _
                          , 0                    _
                          , lpBytesReturned      _
                          , BYVAL %NULL)
            
                    'If the operation completes successfully, the return value is nonzero.
                    CALL ShowErrorText(lReturn, "UnLockVolume", 0)
            
                    IF lReturn > 0 THEN
                        CALL CLOSE_THIS_HANDLE(hVolume, "Volume handle closed.", 0)
                        FUNCTION = %TRUE
                        EXIT FUNCTION
                    END IF
                    SLEEP dwSleepAmount
                NEXT
            
                FUNCTION = %FALSE
            END FUNCTION
            '_________________________________________________________________
            '
            ' FUNCTION DismountVolume
            '_________________________________________________________________
            
            FUNCTION DismountVolume(BYVAL hVolume AS DWORD) AS LONG
                LOCAL lpBytesReturned AS DWORD
                LOCAL lReturn         AS DWORD
            
                'This causes the file system to remove all knowledge of the volume
                'and to discard any internal information that it keeps regarding the volume.
            
                SetLastError(%ERROR_SUCCESS) 'Clear previous error, if any
                lReturn = %TRUE
                lReturn = DeviceIoControl( _
                               hVolume                _
                             , %FSCTL_DISMOUNT_VOLUME _
                             , BYVAL %NULL            _
                             , 0                      _
                             , BYVAL %NULL            _
                             , 0                      _
                             , lpBytesReturned        _
                             , BYVAL %NULL)
            
                'If the operation completes successfully, the return value is nonzero.
                CALL ShowErrorText(lReturn, "DismountVolume", 0)
            
                IF lReturn > 0 THEN
                    FUNCTION = lReturn
                END IF
            
            END FUNCTION
            '_________________________________________________________________
            '
            ' FUNCTION PreventRemovalOfVolume
            '_________________________________________________________________
            
            FUNCTION PreventRemovalOfVolume(BYVAL hVolume AS DWORD, bPreventRemoval AS LONG) AS LONG
                LOCAL lpBytesReturned AS DWORD
                LOCAL lpOverlapped    AS OVERLAPPED
                LOCAL PMRBuffer       AS PREVENT_MEDIA_REMOVAL
                LOCAL lReturn         AS DWORD
            
                'This stops the device from preventing the removal of the media.
                PMRBuffer.PreventMediaRemoval = bPreventRemoval
            
                SetLastError(%ERROR_SUCCESS) 'Clear previous error, if any
                lReturn = %TRUE
                lReturn = DeviceIoControl( _
                            hVolume                       _
                          , %IOCTL_STORAGE_MEDIA_REMOVAL  _
                          , PMRBuffer                     _
                          , SIZEOF(PREVENT_MEDIA_REMOVAL) _
                          , BYVAL %NULL                   _
                          , 0                             _
                          , lpBytesReturned               _
                          , BYVAL %NULL)
            
                'If the operation completes successfully, the return value is nonzero.
                CALL ShowErrorText(lReturn, "PreventRemovalOfVolume", 0)
            
                IF lReturn > 0 THEN
                    FUNCTION = lReturn
                END IF
            
            END FUNCTION
            '_________________________________________________________________
            '
            ' FUNCTION AutoEjectVolume
            '_________________________________________________________________
            
            FUNCTION AutoEjectVolume(BYVAL hVolume AS DWORD) AS LONG
                LOCAL dwBytesReturned AS DWORD
                LOCAL lReturn         AS DWORD
            
                SetLastError(%ERROR_SUCCESS) 'Clear previous error, if any
                lReturn = %TRUE
                lReturn = DeviceIoControl( _
                            hVolume                    _
                          , %IOCTL_STORAGE_EJECT_MEDIA _
                          , BYVAL %NULL                _
                          , 0                          _
                          , BYVAL %NULL                _
                          , 0                          _
                          , dwBytesReturned            _
                          , BYVAL %NULL)
            
                'If the operation completes successfully, the return value is nonzero.
                CALL ShowErrorText(lReturn, "AutoEjectVolume", 0)
            
                IF lReturn > 0 THEN
                    FUNCTION = lReturn
                END IF
            
            END FUNCTION
            '_________________________________________________________________
            '
            ' SUB DisplayEjectionBanner
            '_________________________________________________________________
            
            SUB DisplayEjectionBanner( _
                          S01 AS ASCIIZ * %MAX_PATH    _
                        , S02 AS STRING    _
                        , S03 AS STRING    _
                        , S04 AS STRING    _
                        , S05 AS STRING    _
                        , S06 AS STRING    _
                        , S07 AS STRING    _
                        , ShowMessage AS LONG) 'ShowMessage Yes = 1 No = 0
            
              IF ShowMessage > 0 THEN
                  ? "DriveLetter = " & S01 & $CRLF & _
                    "DriveLabel = " & S02 & $CRLF & _
                    "DriveType = " & S03 & $CRLF & _
                    "DriveSize = " & S04 & $CRLF & _
                    "DriveSerial = " & S05 & $CRLF & _
                    "DriveKind = " & S06 & $CRLF & _
                    "FileSystem = " & S07 & $CRLF
              END IF
            END SUB
            '_________________________________________________________________
            '
            ' FUNCTION EjectVolume
            '_________________________________________________________________
            
            FUNCTION EjectVolume(cDriveLetter AS STRING) AS LONG
                LOCAL hVolume            AS DWORD
                LOCAL fRemoveSafely      AS LONG
                LOCAL fAutoEject         AS LONG
                LOCAL szRootName         AS ASCIIZ * %MAX_PATH
                LOCAL szVolumeName       AS ASCIIZ * %MAX_PATH
                LOCAL szDevicePath       AS ASCIIZ * %MAX_PATH
                LOCAL szDosDeviceName    AS ASCIIZ * %MAX_PATH
                LOCAL dwAccessFlags      AS DWORD
            
                LOCAL sMessage           AS STRING
                LOCAL sStoredLetter      AS STRING
                LOCAL sStoredLabel       AS STRING
                LOCAL sStoredType        AS STRING
                LOCAL sStoredSize        AS STRING
                LOCAL sStoredSerial      AS STRING
                LOCAL sStoredKind        AS STRING
                LOCAL sStoredFileSystem  AS STRING
            
                LOCAL sDeviceId          AS STRING
                LOCAL sFriendlyName      AS STRING
                LOCAL sManufacturer      AS STRING
                LOCAL sDescription       AS STRING
            
                LOCAL sDriveType         AS STRING
                LOCAL lReturn            AS DWORD
            
                LOCAL DeviceNumber       AS LONG
                LOCAL dwBytesReturned    AS DWORD
                LOCAL DriveType          AS LONG
            
                LOCAL StorageGUID        AS GUID
                LOCAL IsFloppy           AS INTEGER
                LOCAL hDevInfo           AS DWORD
                LOCAL dwIndex            AS DWORD
                LOCAL hDrive             AS DWORD
                LOCAL LastDevice         AS LONG
                LOCAL MyDeviceDetected   AS LONG
                LOCAL Last_Error         AS LONG
                LOCAL pszDevicePathName  AS ASCIIZ POINTER
                LOCAL szDevicePathName   AS ASCIIZ * %MAX_PATH
            
                LOCAL resCM              AS DWORD
                LOCAL VetoType           AS LONG
                LOCAL bSuccess           AS INTEGER
                LOCAL tries              AS INTEGER
            
                LOCAL VetoName           AS ASCIIZ * %MAX_PATH
                LOCAL DevInstParent      AS DWORD
                LOCAL DevInst            AS DWORD
            
            
                fRemoveSafely = %FALSE
                fAutoEject    = %FALSE
            
                '1) obtain a handle to the volume I'm interested in.
            
                giArrayIndex =  ASC(cDriveLetter)
            
                szRootName   = cDriveLetter + ":\"
                szDevicePath = cDriveLetter & ":"
                szVolumeName = "\\.\" + cDriveLetter + ":"
            
                sStoredLabel = TRIM$(RTRIM$(TheArray(giArrayIndex).VolumeLabel, CHR$(0)))
                sStoredType = TRIM$(RTRIM$(TheArray(giArrayIndex).DriveType, CHR$(0)))
                sStoredSerial = TRIM$(RTRIM$(TheArray(giArrayIndex).VolumeSerial, CHR$(0)))
                sStoredKind = TRIM$(RTRIM$(TheArray(giArrayIndex).DriveKind, CHR$(0)))
            
                sStoredSize = TRIM$(RTRIM$(TheArray(giArrayIndex).DriveSize, CHR$(0)))
                sStoredSize = TRIM$(FORMAT$(VAL(sStoredSize)/1024/1024/1024, "#.##"))
            
                sStoredFileSystem = TRIM$(RTRIM$(TheArray(giArrayIndex).FileSystem, CHR$(0)))
            
                SELECT CASE sStoredKind
                    CASE "0"
                        sStoredKind = "UNKNOWN"      'Not Partitioned
                    CASE "1"
                        sStoredKind = "NO ROOT DIR"  'No filesystem found
                    CASE "2"
                        sStoredKind = "REMOVABLE"
                    CASE "3"
                        sStoredKind = "FIXED"
                    CASE "4"
                        sStoredKind = "REMOTE"
                    CASE "5"
                        sStoredKind = "CD-ROM"
                    CASE "6"
                        sStoredKind = "RAMDISK"
                END SELECT
            
                'Mfg = JMICRON USB to SATA Bridge
                '    USB 3.1 Gen 2 to PCIe Gen3x2 Bridge Controller
                '    The JMS583 is a USB 3.1 Gen 2 to PCIe Gen3 x 2 bridge
                '    controller between USB host and PCIe storage device.
                '    The USB 3.1 Gen 2 interface offers data transfer speed
                '    up to 10Gbps, doubling the USB 3.1 Gen 1 data rate.
                '    Meanwhile, the downstream port of the JMS583 is
                '    compatible with storage device with PCIe interface,
                '    such as SSD. The PCIe port is compliant with PCIe
                '    Gen3 x 2 specifications
            
                sManufacturer = TRIM$(RTRIM$(TheArray(giArrayIndex).Mfg, CHR$(0)))
            
                IF sStoredLabel <> "" AND VAL(sStoredSize) > 0 THEN
                    sDriveType = "PORTABLE USB"
            
                    IF sManufacturer = "JMICRON" THEN
                        '? sManufacturer
                        sStoredKind = "REMOVABLE"
                        sStoredType = "USB TO SATA"
                        TheArray(giArrayIndex).DriveType = sStoredType
                    ELSE
                        IF sStoredKind = "FIXED" OR sStoredKind = "REMOTE" THEN
                            IF sStoredKind = "FIXED" THEN
                                sStoredType = "LOCAL DRIVE"
                                TheArray(giArrayIndex).DriveType = sStoredType
                            END IF
                            IF sStoredKind = "REMOTE" THEN
                                sStoredType = "NETWORK DRIVE"
                                TheArray(giArrayIndex).DriveType = sStoredType
                            END IF
                        ELSE
                            IF sManufacturer = "USB" THEN
                                sStoredType = "USB THUMB"
                                TheArray(giArrayIndex).DriveType = sStoredType
                            ELSE
                                IF sManufacturer = "GENERIC"  OR _
                                   sManufacturer = "GENERIC-" OR _
                                   sManufacturer = "MASS" THEN
                                    IF INSTR(sStoredLabel, "CF_") = 0 THEN
                                        sStoredType = "SD CARD"
                                        TheArray(giArrayIndex).DriveType = sStoredType
                                    ELSE
                                        sStoredType = "CF CARD"
                                        TheArray(giArrayIndex).DriveType = sStoredType
                                    END IF
                                END IF
                            END IF
            
                        END IF
                    END IF
            
                    IF sStoredKind = "CD-ROM" THEN
                        sStoredType = "CD/DVD DRIVE"
                        TheArray(giArrayIndex).DriveType = sStoredType
                    END IF
            
                    IF sStoredKind = "RAMDISK" THEN
                        sStoredType = "RAM DISK"
                        TheArray(giArrayIndex).DriveType = sStoredType
                    END IF
            
                    IF sStoredKind = "UNKNOWN" THEN   'Not Partitioned
                        sStoredType = "UNIDENTIFIED"
                        TheArray(giArrayIndex).DriveType = sStoredType
                    END IF
            
                    IF sStoredKind = "NO ROOT DIR" THEN  'No filesystem found
                        sStoredType = "NO ROOT"
                        TheArray(giArrayIndex).DriveType = sStoredType
                        sStoredFileSystem = "NONE"
                        TheArray(giArrayIndex).FileSystem = sStoredFileSystem
                        sStoredSerial = ""
                        TheArray(giArrayIndex).VolumeSerial = sStoredSerial
                        sStoredSize = "0"
                        TheArray(giArrayIndex).DriveSize = sStoredSize
                    END IF
            
                    CALL DisplayEjectionBanner( _
                                              szRootName        _
                                            , sStoredLabel      _
                                            , sStoredType       _
                                            , sStoredSize       _
                                            , sStoredSerial     _
                                            , sStoredKind       _
                                            , sStoredFileSystem _
                                            , 0)                     'ShowMessage Yes = 1 No = 0
            
                    SELECT CASE sStoredKind
                        CASE "REMOVABLE"
                            giFinalMessage = 2 'is a removable drive so eject it
                            dwAccessFlags = %GENERIC_READ OR %GENERIC_WRITE
            
                        CASE "CD-ROM"
                            giFinalMessage = 5 'is a CD-ROM drive so eject it
                            dwAccessFlags = %GENERIC_READ
            
                        CASE ELSE
                            giFinalMessage = 1 'not a removable drive
                            FUNCTION = %INVALID_HANDLE_VALUE
                            EXIT FUNCTION
                    END SELECT
            
                ELSE
                    TheArray(giArrayIndex).VolumeLabel = ""
                    giFinalMessage = 0 'no drive to eject
                    FUNCTION = %INVALID_HANDLE_VALUE
                    EXIT FUNCTION
                END IF
            
                SetLastError(%ERROR_SUCCESS) 'Clear previous error, if any
                hVolume = %TRUE
                hVolume = CreateFileA ( _
                             szVolumeName                          _
                           , dwAccessFlags                         _
                           , %FILE_SHARE_READ OR %FILE_SHARE_WRITE _
                           , BYVAL %NULL                           _
                           , %OPEN_EXISTING                        _
                           , 0                                     _
                           , %NULL )
            
                IF (hVolume = %INVALID_HANDLE_VALUE) THEN
                    giFinalMessage = 3
                    FUNCTION = %FALSE
                    EXIT FUNCTION
                ELSE
                    '? "1) CreateFile opened and its handle is: " & STR$(hVolume)
                END IF
            
                'If the function succeeds, the return value is an open handle
                'to the specified file, device, named pipe, or mail slot.
                'If the function fails, the return value is INVALID_HANDLE_VALUE.
            
                '2) try to lock the volume with FSCTL_LOCK_VOLUME
                '3) try to dismount it using FSCTL_DISMOUNT_VOLUME
                IF LockVolume(hVolume) AND DismountVolume(hVolume) THEN
                    fRemoveSafely = %TRUE
                    giFinalMessage = 8
                    '4) disable the prevent storage media removal using IOCTL_STORAGE_MEDIA_REMOVAL
                    ' Set prevent removal to false and eject the volume.
                    '5) and finally execute the IOCTL_STORAGE_EJECT_MEDIA function.
                    IF PreventRemovalOfVolume(hVolume, %FALSE) AND AutoEjectVolume(hVolume) THEN
                        fAutoEject = %TRUE
                        giFinalMessage = 7
                    ELSE
                        'If the device doesn't allow automatic ejection, then
                        'IOCTL_STORAGE_EJECT_MEDIA can be skipped and the user
                        'can be instructed to remove the media.
                        giFinalMessage = 4
            
                        SLEEP 1000
            
                        '//get and store the volume's device number
                        DeviceNumber = -1
            
                        dwBytesReturned = 0
                        SetLastError(%ERROR_SUCCESS) 'Clear previous error, if any
                        lReturn = %TRUE
                        lReturn = DeviceIoControl( _
                                hVolume             _
                              , %IOCTL_STORAGE_GET_DEVICE_NUMBER _
                              , BYVAL %NULL                      _
                              , 0                                _
                              , sdn                              _
                              , SIZEOF(sdn)                      _
                              , dwBytesReturned                  _
                              , BYVAL %NULL)
            
                        DeviceNumber = sdn.DeviceNumber
                        IF DeviceNumber = -1 THEN
                            '? "The Device Number was not found!"
                        END IF
            
                        'If the operation completes successfully, the return value is nonzero.
                        CALL ShowErrorText(lReturn, "Device Number Value =" & STR$(DeviceNumber), 0)
            
                        IF lReturn > 0 THEN
                            DeviceNumber = sdn.DeviceNumber
                        END IF
            
                    END IF
            
                    IF DeviceNumber = -1 THEN GOTO ToDoLoo
            
                    CALL UnLockVolume(hVolume) '!!!! This must be here to allow the drive to be removed. !!!!
            
                    '// get the drive type which is required to match
                    '   the device numbers correctly.
                    DriveType = GetDriveTypeA(szRootName)
                    szDosDeviceName = SPACE$(%MAX_PATH)
            
                    ''// get the dos device name like: \Device\HarddiskVolume410 or  \device\floppy0)
                    '    to decide if it's a floppy
                    QueryDosDeviceA( _
                           szDevicePath        _
                         , szDosDeviceName     _
                         , %MAX_PATH)
            
                    '? "QueryDosDeviceA=" & szDosDeviceName
            
                    '// get the device instance handle of the storage
                    '   volume by means of a SetupDi enum and matching
                    '   the device number.
            
                    IsFloppy = INSTR(szDosDeviceName, "\\Floppy") > 0
            
                    SELECT CASE DriveType
                        CASE %DRIVE_REMOVABLE
                            IF IsFloppy THEN
                                StorageGUID = $GUID_DEVINTERFACE_FLOPPY
                            ELSE
                                StorageGUID = $GUID_DEVINTERFACE_DISK
                            END IF
                            GOTO ToDoLoo
            
                        CASE %DRIVE_FIXED
                            IF sStoredKind = "REMOVABLE" THEN
                                StorageGUID = $GUID_DEVINTERFACE_DISK
                            ELSE
                                GOTO ToDoLoo
                            END IF
            
                        CASE %DRIVE_CDROM
                            StorageGUID = $GUID_DEVINTERFACE_CDROM
                            GOTO ToDoLoo
            
                        CASE ELSE
                            GOTO ToDoLoo
            
                    END SELECT
            
                    '? GUIDTXT$(StorageGUID)
            
                    '// Get device interface info set handle for
                    '   all devices attached to the system.
                    hDevInfo = SetupDiGetClassDevsA( _
                                  StorageGUID        _
                                , BYVAL %NULL        _
                                , 0                  _
                                , %DIGCF_PRESENT OR %DIGCF_DEVICEINTERFACE)
            
                    IF hDevInfo <> %INVALID_HANDLE_VALUE THEN
                        '// Retrieve a context structure for a device
                        '   interface of a device information set
                        dwIndex = 0
            
                        'Declare and populate SP_DEVICE_INTERFACE_DATA TYPE
                        LOCAL spdid              AS SP_DEVICE_INTERFACE_DATA
                        spdid.cbSize = SIZEOF(SP_DEVICE_INTERFACE_DATA)
            
                        'Enumerate drives
                        DO
            
                            LOCAL spdd               AS SP_DEVINFO_DATA
                            lReturn = SetupDiEnumDeviceInterfaces( _
                                        hDevInfo    _
                                      , BYVAL %NULL _
                                      , StorageGUID _
                                      , dwIndex     _
                                      , spdid)
            
                            IF lReturn = 0 THEN LastDevice = %TRUE
            
                            Last_Error = GetLastError
                            IF Last_Error = %ERROR_NO_MORE_ITEMS THEN EXIT DO
                            INCR dwIndex
            
                            IF lReturn <> 0 THEN
            
                                LOCAL pspdidd      AS SP_DEVICE_INTERFACE_DETAIL_DATA_A POINTER
                                LOCAL sDetailData  AS STRING
                                LOCAL RequiredSize AS LONG
            
                                'do once to check the buffer size
                                lReturn = SetupDiGetDeviceInterfaceDetailA( _
                                          hDevInfo     _
                                        , spdid        _
                                        , BYVAL %NULL  _
                                        , 0            _
                                        , RequiredSize _
                                        , BYVAL %NULL)
            
                                Last_Error = GetLastError
            
                                sDetailData = NUL$(RequiredSize)
                                pspdidd = STRPTR(sDetailData)
                                @pspdidd.cbSize = SIZEOF(SP_DEVICE_INTERFACE_DETAIL_DATA_A)
            
                                'Declare and populate SP_DEVINFO_DATA TYPE
                                spdd.cbSize = SIZEOF(SP_DEVINFO_DATA)
            
                                lReturn = SetupDiGetDeviceInterfaceDetailA( _
                                          hDevInfo         _
                                        , spdid            _
                                        , BYVAL pspdidd    _
                                        , LEN(sDetailData) _
                                        , RequiredSize     _
                                        , spdd)                ' this must be here
            
                                Last_Error = GetLastError
            
                                pszDevicePathName = VARPTR(@pspdidd.DevicePath(0))
                                szDevicePathName = @pszDevicePathName
            
                                'This is the drive device ID
                                '\\?\SCSI#DISK&VEN_JMICRON&PROD_#000000#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
                                '? "szDevicePathName=" & UCASE$(szDevicePathName)
            
                                '// open the disk or cdrom or floppy
                                SetLastError(%ERROR_SUCCESS) 'Clear previous error, if any
                                lReturn = %TRUE
                                hDrive = CreateFileA( _
                                          RTRIM$(szDevicePathName, CHR$(0))     _
                                        , 0                                     _ 'this must be 0
                                        , %FILE_SHARE_READ OR %FILE_SHARE_WRITE _
                                        , BYVAL %NULL                           _
                                        , %OPEN_EXISTING                        _
                                        , 0                                     _
                                        , BYVAL %NULL)
            
                                IF hDrive = %INVALID_HANDLE_VALUE THEN
                                    ? "Could not open file."
                                ELSE
                                    '? "3) CreateFile opened and its handle is: " & STR$(hDrive)
            
                                   'If the function succeeds, the return value is an open handle
                                   'to the specified file, device, named pipe, or mail slot.
                                   'If the function fails, the return value is INVALID_HANDLE_VALUE.
            
                                    '? "got here!"
                                    '// get its device number
                                    dwBytesReturned = 0
                                    SetLastError(%ERROR_SUCCESS) 'Clear previous error, if any
                                    lReturn = %TRUE
                                    lReturn = DeviceIoControl( _
                                              hDrive                  _
                                            , %IOCTL_STORAGE_GET_DEVICE_NUMBER _
                                            , BYVAL %NULL                      _
                                            , 0                                _
                                            , sdn                              _
                                            , SIZEOF(sdn)                      _
                                            , dwBytesReturned                  _
                                            , BYVAL %NULL)  'NIL
            
                                    'If the operation completes successfully, the return value is nonzero.
                                    CALL ShowErrorText( _
                                             lReturn    _
                                           , "Target Device Number Value =" & STR$(DeviceNumber) & $CRLF & "This device number =" & STR$(sdn.DeviceNumber) & $CRLF, 0)
            
                                    IF lReturn > 0 THEN
                                        '? "MADE IT HERE"
                                        IF DeviceNumber = sdn.DeviceNumber THEN
                                            '// match the given device number with the
                                            '   one of the current device.
                                            DevInst = spdd.DevInst  'IS A DWORD
                                            MyDeviceDetected = %TRUE
                                        END IF
                                    END IF
            
                                    CALL CLOSE_THIS_HANDLE(hDrive, "Drive handle closed.", 0)
                                END IF
            
                            END IF
            
                        LOOP UNTIL (giAppRunning = 0) OR (MyDeviceDetected = %TRUE) OR (LastDevice = %TRUE)
                        lReturn = SetupDiDestroyDeviceInfoList(hDevInfo)
            
                    END IF
            
                    IF DevInst = 0 THEN GOTO ToDoLoo
            
                    VetoType = %PNP_VetoTypeUnknown
                    bSuccess = %FALSE
            
                    '// get drives's parent, e.g. the USB bridge, the SATA port,
                    '   an IDE channel with two drives!
                    DevInstParent = 0
                    resCM = CM_Get_Parent( _
                                DevInstParent _
                              , DevInst       _
                              , 0)
            
                    FOR tries = 0 TO 3
                        '// sometimes we need some tries...
                        VetoName = SPACE$(%MAX_PATH)
            
                        resCM = CM_Request_Device_EjectA( _
                                      DevInstParent       _
                                    , VetoType            _
                                    , VetoName            _
                                    , LEN(VetoName)       _
                                    , 0)
            
                        resCM = CM_Request_Device_EjectA( _
                                      DevInstParent       _
                                    , BYVAL %NULL         _
                                    , BYVAL %NULL         _
                                    , 0                   _
                                    , 0) '// optional -> shows messagebox (W2K, Vista) or balloon (XP)
            
                        bSuccess = resCM = %CR_SUCCESS AND VetoType = %PNP_VetoTypeUnknown
                        IF ( bSuccess )  THEN
                            EXIT FOR
                        END IF
            
                        SLEEP(500) '// required to give the next tries a chance!
                    NEXT
            
                    IF ( bSuccess ) THEN
                        '? "Success"
                        giFinalMessage = 2
                    ELSE
                        '? "Failed"
                        giFinalMessage = 6
                    END IF
            
                    'Close the volume handle obtained in the first step or issue the FSCTL_UNLOCK_VOLUME
                    ' Close the volume so other processes can use the drive.
            
                    ToDoLoo:
                    CALL CLOSE_THIS_HANDLE(hVolume, "Volume handle closed.", 0)
            
                    FUNCTION = %TRUE
                END IF
            END FUNCTION
            '_________________________________________________________________
            '
            ' SUB CLOSE_THIS_HANDLE
            '_________________________________________________________________
            
            SUB CLOSE_THIS_HANDLE(hMyHandle AS DWORD, sInfo AS STRING, ShowMessage AS LONG)
                CloseHandle(hMyHandle)
                IF ShowMessage > 0 THEN
                    ? sInfo & " " & STR$(hMyHandle)
                END IF
            END SUB
            '_________________________________________________________________
            '
            ' SUB ShowErrorText
            '_________________________________________________________________
            
            SUB ShowErrorText(lReturnX AS DWORD, RoutineName AS STRING, ShowMessage AS LONG)
              LOCAL MyError         AS LONG
            
              IF ShowMessage > 0 THEN
                  IF lReturnX = %FALSE THEN
                      MyError = GetLastError
            
                      SELECT CASE MyError
                          CASE 0
                              ? RoutineName & " = " & "ERROR_SUCCESS"
            
                          CASE 1
                              ? RoutineName & " = " & "ERROR_INVALID_FUNCTION"
            
                          CASE 5
                              ? RoutineName & " = " & "ERROR_ACCESS_DENIED"
            
                          CASE 32
                              ? RoutineName & " = " & "ERROR_SHARING_VIOLATION"
            
                          CASE 122
                              ? RoutineName & " = " & "ERROR_INSUFFICIENT_BUFFER"    'DeviceIoControl
            
                          CASE 234
                              ? RoutineName & " = " & "ERROR_MORE_DATA"              'DeviceIoControl
            
                          CASE ELSE
                              ? RoutineName & " = " & "REMOVE_ERROR_UNKNOWN_ERROR (ErrorCode = " & STR$(MyError) & ")"
            
                      END SELECT
                  ELSE
                    ? RoutineName & " Return value = " & STR$(lReturnX)
                  END IF
              END IF
            END SUB

            Comment


            • #7
              EjectDrive SDK VER. 2.0

              Click image for larger version  Name:	New Bitmap Image.jpg Views:	1 Size:	56.8 KB ID:	785866

              Comments here. Please

              New in this version:

              Fixed the focus problem.
              Added Marquee.
              Added rebar.
              Added Microphone detection.
              Added Voice output.
              Added Speech Recognition.
              Added Jarvis Grammar.
              Added AutoFocus (but not implemented).
              Added Mutex.
              Added Ejection Thread.
              Added 12 themes. Total is 14. 7 gradients and 7 flat.
              Added Help file. Click on Help Information label.

              With version 2.0 you get a generic SDK application with these attributes:
              1) Built in speech recognition.
              2) Built in voice output.
              3) Built in Jarvis grammar.
              4) Built in rebar.
              5) Built in 3D listview items.
              6) Built in listview icons.
              7) Built in microphone detection.
              8) Built in AutoFocus.
              9) Built in Marquee.
              10) Built in DLL for graphics files.
              11) Built in printing support.
              12) Built in Help.

              EjectDrive2.zip
              Attached Files

              Comment

              Working...
              X