Seite 1 von 1

Festplatte(n) an USB (auch 3.0) auswerfen ???

Verfasst: 22.01.2013 22:55
von al90
Hi Leuts,

Hab ein kleines problem. Folgendes habe ich mir aus dem E-Forum rausgesucht.

Code: Alles auswählen

;  USB Device remove... !!!

#IOCTL_STORAGE_EJECT_MEDIA  = $2D4808

Procedure EjectCD(LW.s)
    Protected hLwStatus.l
    hLwStatus = CreateFile_("\\.\"+LW,#GENERIC_READ|#GENERIC_WRITE, 0, 0, #OPEN_EXISTING, 0, 0)
    If hLwStatus
      DeviceIoControl_(hLwStatus,#IOCTL_STORAGE_EJECT_MEDIA,0,0,0,0,@Ret,0)
      CloseHandle_(hLwStatus)
      ProcedureReturn #True
    EndIf
EndProcedure
;--------------------------------------------------
If EjectCD("Z:") = #True
     MessageRequester("USB","device can be safely removed.",#MB_ICONINFORMATION)
Else
    MessageRequester("USB","The device can be disconnected !.",#MB_ICONEXCLAMATION)
EndIf
Das klappt mit Sticks auch ohne probleme. Aber wie kann ich es machen das sich auch Platten am USB (auch 3.0) auswerfen lassen ???
Bin für jeden Tip Dankbar. :praise:

Re: Festplatte(n) an USB (auch 3.0) auswerfen ???

Verfasst: 22.01.2013 23:00
von RSBasic
Hast du alle Code, die im folgenden Thread zu finden sind, ausprobiert?
http://www.purebasic.fr/english/viewtop ... 13&t=40654

Re: Festplatte(n) an USB (auch 3.0) auswerfen ???

Verfasst: 23.01.2013 18:32
von al90
Ja alle bis auf das erste da ich keine externe Datei einbeziehen wollte. Das ganze sollte auch so gehen. Zur not auch
mit einer systemdatei. Diese sollte dann aber schon existent sein. (Ähnlich wie RunDLL e.t.c.)

Re: Festplatte(n) an USB (auch 3.0) auswerfen ???

Verfasst: 23.01.2013 20:43
von _JON_
al90 hat geschrieben:Hi Leuts,
Das klappt mit Sticks auch ohne probleme
Nicht wirklich, hier bleibt ein verstecktes Laufwerk im Arbeitsplatz und mein Sandisk Cruzer leuchtet fröhlich weiter.

Probiere mal das hier USB drive safe removal by drive letter

Es funktioniert mit meiner USB 3.0 HDD. :mrgreen:

Re: Festplatte(n) an USB (auch 3.0) auswerfen ???

Verfasst: 24.01.2013 21:50
von al90
Hallo @_JON_

Ja das funktioniert super!!! Danke Dir :allright: :D

Allerdings klappt das wohl nur mit der 32Bit version von PB. Naja muss dann wohl noch angepasst werden.
Aber damit komme ich jetzt weiter.

BTW:
Eine kleine frage bleibt da aber doch noch. Wie kann man eigentlich alle Drives ermitteln die auch auswerfbar sind?
GetDriveType_(Lfwrk) gibt nähmlich #DRIVE_FIXED zurück statt #DRIVE_REMOVABLE. Darunter würden
dann auch die Bootplatten fallen, die sich aber natürlich nicht auswerfen lassen. :roll:

Beispiel zum auflisten der Drives:

Code: Alles auswählen

Lfwrk.S 
FileSystem.S 
VolName.S 

For i=65 To 90 
  Lfwrk=Chr(i)+":\" 
  type =GetDriveType_(Lfwrk) 
  FileSystem = Space(256) 
  VolName= Space(256) 
  GetVolumeInformation_(@Lfwrk, @VolName, 255, @Serial, 0, 0, @FileSystem, 255) 
  Select type 
    Case 0 
      Debug Lfwrk+" The drive type cannot be determined." 
    Case 2 
      Debug Lfwrk+" = DRIVE_REMOVABLE, "+VolName+", "+FileSystem+", "+  Hex(Serial) 
    Case 3 
      Debug Lfwrk+" = DRIVE_FIXED, "+VolName+", "+FileSystem+", "+  Hex(Serial) 
    Case 4 
      Debug Lfwrk+" = DRIVE_REMOTE, "+VolName+", "+FileSystem+", "+  Hex(Serial) 
    Case 5 
      Debug Lfwrk+" = DRIVE_CDROM, "+VolName+", "+FileSystem+", "+  Hex(Serial) 
    Case 6 
      Debug Lfwrk+" =  DRIVE_RAMDISK,   "+VolName+", "+FileSystem+", "+  Hex(Serial) 
  EndSelect 
Next 

Re: Festplatte(n) an USB (auch 3.0) auswerfen ???

Verfasst: 24.01.2013 23:29
von _JON_
So, sollte nun auch als x64 laufen :D
al90 hat geschrieben:Hallo @_JON_
Eine kleine frage bleibt da aber doch noch. Wie kann man eigentlich alle Drives ermitteln die auch auswerfbar sind?
GetDriveType_(Lfwrk) gibt nähmlich #DRIVE_FIXED zurück statt #DRIVE_REMOVABLE. Darunter würden
dann auch die Bootplatten fallen, die sich aber natürlich nicht auswerfen lassen. :roll:
Hmm, schau mal im Code nach CM_Get_Device_ID.
Der DeviceIdString sollte bei allem was an einem USB Port angeschlossen ist mit "USBSTOR" anfangen.

Code: Alles auswählen

;
; RemoveDriveByLetter.cpp by Uwe Sieber - www.uwe-sieber.de
;
; Simple demonstration how to prepare a disk drive for save removal
;
; Works with removable and fixed drives under W2K, XP, W2K3, Vista
;
; Console application - expects the drive letter of the drive to remove as parameter
;
; you are free to use this code in your projects
;

EnableExplicit


Macro CTL_CODE(DeviceType, Function, Method, Access)
  (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
EndMacro

#FILE_DEVICE_MASS_STORAGE = $0000002d
#IOCTL_STORAGE_BASE = #FILE_DEVICE_MASS_STORAGE
#FILE_ANY_ACCESS = 0
#METHOD_BUFFERED = 0
#IOCTL_STORAGE_GET_DEVICE_NUMBER = CTL_CODE(#IOCTL_STORAGE_BASE, $0420, #METHOD_BUFFERED, #FILE_ANY_ACCESS)

#CM_REMOVE_NO_RESTART = $00000002

#DIGCF_PRESENT         = $00000002
#DIGCF_ALLCLASSES      = $00000004
#DIGCF_PROFILE         = $00000008
#DIGCF_DEVICEINTERFACE = $00000010

#PNP_VetoTypeUnknown = 0
#CR_SUCCESS = 0

Structure PSP_DEVICE_INTERFACE_DETAIL_DATA
  cbSize.l
  DevicePath.s{1024}
EndStructure

Structure SP_DEVINFO_DATA
  cbSize.l
  ClassGuid.GUID
  DevInst.l
  Reserved.i
EndStructure

; Structure SP_DEVICE_INTERFACE_DATA
;   cbSize.l
;   InterfaceClassGuid.GUID
;   Flags.l
;   Reserved.l
; EndStructure

; Structure STORAGE_DEVICE_NUMBER
;   DeviceType.l      ;// The FILE_DEVICE_XXX type For this device.
;   DeviceNumber.l    ;// The number of this device
;   PartitionNumber.l ;// If the device is partitionable, the partition number of the device. Otherwise -1
; EndStructure

Prototype.l CM_Get_Parent(*DevInst, DevInst, Flags)
; CM_Get_Parent(
;              OUT PDEVINST pdnDevInst,
;              IN  DEVINST  dnDevInst,
;              IN  ULONG    ulFlags
;              );
Prototype.l CM_Get_Device_IDW(DevInst, DeviceIdString.s, BufferLen, Flags)
; CM_Get_Device_IDW(
;              IN  DEVINST  dnDevInst,
;              OUT PWCHAR   Buffer,
;              IN  ULONG    BufferLen,
;              IN  ULONG    ulFlags
;              );
Prototype.l CM_Request_Device_EjectW(DevInst, *VetoType, VetoName.s, NameLength, Flags)
; CM_Request_Device_EjectW(
;             IN  DEVINST         dnDevInst,
;             OUT PPNP_VETO_TYPE  pVetoType,
;             OUT LPWSTR          pszVetoName,
;             IN  ULONG           ulNameLength,
;             IN  ULONG           ulFlags
;             );
Prototype.l CM_Query_And_Remove_SubTreeW(Ancestor, *VetoType, VetoName.s, NameLength, Flags)
; CM_Query_And_Remove_SubTreeW(
;              IN  DEVINST        dnAncestor,
;              OUT PPNP_VETO_TYPE pVetoType,
;              OUT LPWSTR         pszVetoName,
;              IN  ULONG          ulNameLength,
;              IN  ULONG          ulFlags
;              );
Prototype.l SetupDiEnumDeviceInterfaces(DeviceInfoSet, DeviceInfoData, *InterfaceClassGuid, MemberIndex, *DeviceInterfaceData)
; SetupDiEnumDeviceInterfaces(
;     IN  HDEVINFO                   DeviceInfoSet,
;     IN  PSP_DEVINFO_DATA           DeviceInfoData,     OPTIONAL
;     IN  CONST GUID                *InterfaceClassGuid,
;     IN  DWORD                      MemberIndex,
;     OUT PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData
;     );
Prototype.l SetupDiGetDeviceInterfaceDetailW(DeviceInfoSet, DeviceInterfaceData, *DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, *RequiredSize, *DeviceInfoData)
; SetupDiGetDeviceInterfaceDetailW(
;     IN  HDEVINFO                           DeviceInfoSet,
;     IN  PSP_DEVICE_INTERFACE_DATA          DeviceInterfaceData,
;     OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,     OPTIONAL
;     IN  DWORD                              DeviceInterfaceDetailDataSize,
;     OUT PDWORD                             RequiredSize,                  OPTIONAL
;     OUT PSP_DEVINFO_DATA                   DeviceInfoData                 OPTIONAL
;     );

Global CM_Get_Parent.CM_Get_Parent
Global CM_Get_Device_ID.CM_Get_Device_IDW
Global CM_Request_Device_EjectW.CM_Request_Device_EjectW
Global CM_Query_And_Remove_SubTreeW.CM_Query_And_Remove_SubTreeW
Global SetupDiEnumDeviceInterfaces.SetupDiEnumDeviceInterfaces
Global SetupDiGetDeviceInterfaceDetail.SetupDiGetDeviceInterfaceDetailW


; ----------------------------------------------------------------------
;  returns the device instance handle of a storage volume or 0 on error
; ----------------------------------------------------------------------
Procedure.l GetDrivesDevInstByDeviceNumber(DeviceNumber, DriveType, DosDeviceName.s)
   Protected IsFloppy, *guid, Index, res, Size, hDevInfo
   Protected pspdidd.PSP_DEVICE_INTERFACE_DETAIL_DATA, spdid.SP_DEVICE_INTERFACE_DATA, spdd.SP_DEVINFO_DATA
  Protected sdn.STORAGE_DEVICE_NUMBER
  Protected hDrive, BytesReturned
  
   IsFloppy = FindString(DosDeviceName, "\Floppy", 1)  ; // who knows a better way?
  
   Select DriveType
     Case #DRIVE_REMOVABLE
        If IsFloppy
           *guid = ?GUID_DEVINTERFACE_FLOPPY
        Else
           *guid = ?GUID_DEVINTERFACE_DISK
      EndIf
     Case #DRIVE_FIXED
       *guid = ?GUID_DEVINTERFACE_DISK
     Case #DRIVE_CDROM
        *guid = ?GUID_DEVINTERFACE_CDROM
     Default
        ProcedureReturn 0
   EndSelect

   ; Get device interface info set handle for all devices attached to system
   hDevInfo = SetupDiGetClassDevs_(*guid, 0, 0, #DIGCF_PRESENT|#DIGCF_DEVICEINTERFACE)
  
   If hDevInfo = #INVALID_HANDLE_VALUE
      ProcedureReturn 0
   EndIf

   ; Retrieve a context structure for a device interface of a device information set
  
   spdid\cbSize = SizeOf(SP_DEVICE_INTERFACE_DATA)
  
   Repeat
      res = SetupDiEnumDeviceInterfaces(hDevInfo, 0, *guid, Index, @spdid)

      If res = 0
         Break
      EndIf
      
      SetupDiGetDeviceInterfaceDetail(hDevInfo, @spdid, 0, 0, @Size, 0) ; check the buffer size
      If Size<>0 And Size<=SizeOf(PSP_DEVICE_INTERFACE_DETAIL_DATA)
         
         
         CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
            pspdidd\cbSize = 8
         CompilerElse
            pspdidd\cbSize = 6    ;For Unicode. ASCII=5
         CompilerEndIf
         
         spdd\cbSize = SizeOf(SP_DEVINFO_DATA)
      
      ;res = SetupDiGetDeviceInterfaceDetail(hDevInfo, @spdid, @pspdidd, Size, @Size, @spdd)
         res = SetupDiGetDeviceInterfaceDetail(hDevInfo, @spdid, @pspdidd, Size, 0, @spdd)
         If res
            ; in case you are interested in the USB serial number:
            ; the device id string contains the serial number if the device has one,
            ; otherwise a generated id that contains the '&' char...
;         Protected DevInstParent, DeviceIdString.s=Space(#MAX_PATH)
;              CM_Get_Parent(@DevInstParent, spdd\DevInst, 0)
;              CM_Get_Device_ID(DevInstParent, DeviceIdString, #MAX_PATH, 0)
;         Debug "DeviceId= " + DeviceIdString

            ; open the disk or cdrom or floppy
            hDrive = CreateFile_(@pspdidd\DevicePath, 0, #FILE_SHARE_READ|#FILE_SHARE_WRITE, 0, #OPEN_EXISTING, 0, 0)
            If hDrive <> #INVALID_HANDLE_VALUE
               ; get its device number
               BytesReturned = 0
               res = DeviceIoControl_(hDrive, #IOCTL_STORAGE_GET_DEVICE_NUMBER, 0, 0, @sdn, SizeOf(STORAGE_DEVICE_NUMBER), @BytesReturned, 0)
               If res
                  If DeviceNumber = sdn\DeviceNumber  ; match the given device number with the one of the current device
                     CloseHandle_(hDrive)
                     SetupDiDestroyDeviceInfoList_(hDevInfo)
                     ProcedureReturn spdd\DevInst
                  EndIf
               EndIf
               CloseHandle_(hDrive)
            EndIf
         EndIf
      EndIf
      Index + 1
   ForEver

   SetupDiDestroyDeviceInfoList_(hDevInfo)

   ProcedureReturn 0
EndProcedure

Procedure RemoveDrive(drive$)
  Protected RootPath.s, DevicePath.s, VolumeAccessPath.s, hVolume
  Protected sdn.STORAGE_DEVICE_NUMBER, res, DriveType, DeviceNumber=-1
  Protected DosDeviceName.s
  Protected DevInst, BytesReturned, DevInstParent
  Protected VetoType, VetoNameW.s, tries, bSuccess=#False
  
  drive$ = Left(UCase(drive$), 1)
  If drive$<"A" Or drive$>"Z" : Goto exit : EndIf
  
  DevicePath = drive$ + ":"       ; "X:"   -> for QueryDosDevice
  RootPath = DevicePath + "\"     ; "X:\"  -> for GetDriveType
  VolumeAccessPath = "\\.\" + DevicePath  ; "\\.\X:"  -> to open the volume
  
  ; open the storage volume
  hVolume = CreateFile_(VolumeAccessPath, 0, #FILE_SHARE_READ|#FILE_SHARE_WRITE, 0, #OPEN_EXISTING, 0, 0)
  
  If hVolume <> #INVALID_HANDLE_VALUE
     ; get the volume's device number
     res = DeviceIoControl_(hVolume, #IOCTL_STORAGE_GET_DEVICE_NUMBER, 0, 0, @sdn, SizeOf(STORAGE_DEVICE_NUMBER), @BytesReturned, 0)
     If res
        DeviceNumber = sdn\DeviceNumber
     EndIf
     CloseHandle_(hVolume)
  
     If DeviceNumber = -1
        Goto exit
     EndIf
  
     ; get the drive type which is required To match the device numbers correctely
     DriveType = GetDriveType_(RootPath)
  
     ; get the dos device name (like \device\floppy0) to decide if it's a floppy or not - who knows a better way?
     DosDeviceName = Space(#MAX_PATH)
     res = QueryDosDevice_(DevicePath, DosDeviceName, #MAX_PATH)
     
     If res = 0
        Goto exit
     EndIf
  
     ; get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number
     DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber, DriveType, DosDeviceName)
  
     If DevInst = 0
        Goto exit
     EndIf
    
     ;VetoType = #PNP_VetoTypeUnknown  ;#PNP_VetoTypeUnknown=0
     VetoNameW = Space(#MAX_PATH)
    
     ; get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives!
     res = CM_Get_Parent(@DevInstParent, DevInst, 0) 
  
     For tries = 1 To 3  ; sometimes we need some tries...
        
  
        ; CM_Query_And_Remove_SubTree doesn't work for restricted users
        ;res = CM_Query_And_Remove_SubTreeW(DevInstParent, @VetoType, VetoNameW, #MAX_PATH, #CM_REMOVE_NO_RESTART); ; CM_Query_And_Remove_SubTreeA is not implemented under W2K!
        ;res = CM_Query_And_Remove_SubTreeW(DevInstParent, 0, #NUL$, 0, #CM_REMOVE_NO_RESTART);  ; with messagebox (W2K, Vista) or balloon (XP)
  
        res = CM_Request_Device_EjectW(DevInstParent, @VetoType, VetoNameW, #MAX_PATH, 0)
        ;res = CM_Request_Device_EjectW(DevInstParent, 0, #NUL$, 0, 0); ; with messagebox (W2K, Vista) or balloon (XP)
      
        If res=#CR_SUCCESS And VetoType=#PNP_VetoTypeUnknown
          bSuccess = 1
          Break
        Else
          bSuccess = 0
        EndIf
  
        Sleep_(500) ; required to give the next tries a chance!
     Next
     
     If bSuccess
       Debug "Success"
     Else
       Debug "failed"
       Debug res
       Debug VetoNameW
     EndIf
    
  EndIf
  
  exit:
  
  ProcedureReturn 
EndProcedure


; -----------------------
; test code
; -----------------------

Define drive$
#setupapi = 1

If OpenLibrary(#setupapi, "setupapi.dll")
  CM_Get_Parent = GetFunction(#setupapi, "CM_Get_Parent")
  CM_Get_Device_ID = GetFunction(#setupapi, "CM_Get_Device_IDW")
  CM_Request_Device_EjectW = GetFunction(#setupapi, "CM_Request_Device_EjectW")
  CM_Query_And_Remove_SubTreeW = GetFunction(#setupapi, "CM_Query_And_Remove_SubTreeW")
  SetupDiEnumDeviceInterfaces = GetFunction(#setupapi, "SetupDiEnumDeviceInterfaces")
  SetupDiGetDeviceInterfaceDetail = GetFunction(#setupapi, "SetupDiGetDeviceInterfaceDetailW")
  
  drive$ = "z"    ;any drive letter to want to remove.
  RemoveDrive(drive$)
  
  CloseLibrary(#setupapi)
EndIf

End

DataSection
  GUID_DEVINTERFACE_FLOPPY:
    Data.l $53f56311
    Data.w $b6bf, $11d0
    Data.b $94, $f2, $00, $a0, $c9, $1e, $fb, $8b
  GUID_DEVINTERFACE_DISK:
    Data.l $53f56307
    Data.w $b6bf, $11d0
    Data.b $94, $f2, $00, $a0, $c9, $1e, $fb, $8b
  GUID_DEVINTERFACE_CDROM:
    Data.l $53f56308
    Data.w $b6bf, $11d0
    Data.b $94, $f2, $00, $a0, $c9, $1e, $fb, $8b
EndDataSection

Re: Festplatte(n) an USB (auch 3.0) auswerfen ???

Verfasst: 25.01.2013 18:49
von al90
Danke für den Tip. Werde ich mir mal ansehen bzw. experimentieren. :allright: