Direkter Floppyzugriff (DeviceIOControl-API)
Zum Code

Hier haben wir mal ein kleines Beispiel zum Einsatz der DeviceIOControl-Api,
hauptsächlich um damit auf das Diskettenlaufwerk zuzugreifen. Das Ganze
funktioniert erst ab Windows 2000, Windows 98 geht meines Wissens nach nicht!

Der erste Button "Festplattenspeed" funktioniert nur, wenn ihr zwei Festplatten
drin habt, er legt dabei ein kleines Image eurer ersten Platte auf die zweite
ab, jedoch nur ein paar Megabyte.

Ich denke, die anderen Buttons Floppyiamge, Floppygeometrie und Floppyformat
(Lowlevel) erklären sich von selbst. Viel Spaß damit

27.12.2002 Hinzugefügt

Autor: Dominik Auras <Dominik_auf_vbinside.de>

Code aus Floppy.bas
Option Explicit

Private Declare Function DeviceIoControl Lib "kernel32" (ByVal _
hDevice As Long, ByVal dwIoControlCode As Long, lpInBuffer As _
Any, ByVal nInBufferSize As Long, ByRef lpOutBuffer As Any, _
ByVal nOutBufferSize As Long, ByRef lpBytesReturned As Long, _
lpOverlapped As Any) As Long
Private Declare Function CreateFile Lib "kernel32" Alias _
"CreateFileA" (ByVal lpFileName As String, ByVal _
dwDesiredAccess As Long, ByVal dwShareMode As Long, _
lpSecurityAttributes As Any, ByVal dwCreationDisposition As _
Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile _
As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject _
As Long) As Long
Private Declare Function VirtualAlloc Lib "kernel32" (lpAddress As _
Any, ByVal dwSize As Long, ByVal flAllocationType As Long, _
ByVal flProtect As Long) As Long
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As _
Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, _
lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As _
Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, _
lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long
Private Declare Function LocalAlloc Lib "kernel32" (ByVal wFlags _
As Long, ByVal wBytes As Long) As Long
Private Declare Function LocalFree Lib "kernel32" (ByVal hMem As _
Long) As Long

Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const OPEN_EXISTING = 3
Private Const Handle = 0
Private Const INVALID_HANDLE_VALUE = ((Handle) - 1)
Private Const FILE_DEVICE_FILE_SYSTEM As Long = &H9
Private Const METHOD_BUFFERED As Long = 0
Private Const FILE_ANY_ACCESS As Long = 0
Private Const CREATE_ALWAYS As Long = 2
Private Const MEM_COMMIT As Long = &H1000
Private Const PAGE_READWRITE As Long = &H4
Private Const CREATE_NEW As Long = 1
Private Const LMEM_ZEROINIT As Long = &H40
Private Const FILE_READ_ACCESS As Long = (&H1)
Private Const FILE_WRITE_ACCESS As Long = (&H2)

Private Type LARGE_INTEGER
lowpart As Long
highpart As Long
End Type

Public Type DISK_GEOMETRY
Cylinders As LARGE_INTEGER
MediaType As MEDIA_TYPE
TracksPerCylinder As Long
SectorsPerTrack As Long
BytesPerSector As Long
End Type

Public Enum MEDIA_TYPE
Unknown
F5_1Pt2_512
F3_1Pt44_512
F3_2Pt88_512
F3_20Pt8_512
F3_720_512
F5_360_512
F5_320_512
F5_320_1024
F5_180_512
F5_160_512
RemovableMedia
FixedMedia
End Enum

Public Type FORMAT_PARAMETERS
MediaType As MEDIA_TYPE
StartCylinderNumber As Long
EndCylinderNumber As Long
StartHeadNumber As Long
EndHeadNumber As Long
End Type

Public Sub ShowGeometry(d As String)
Dim Drive As String, hDrive As Long, lpGeometry As DISK_GEOMETRY

Drive = "\\.\" & d
hDrive = CreateFile(Drive, GENERIC_READ Or GENERIC_WRITE, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0, _
OPEN_EXISTING, 0, ByVal 0)

If hDrive = INVALID_HANDLE_VALUE Then
Debug.Print "Fehler 1"
CloseHandle hDrive
End
End If

If Not LockVolume(hDrive) Then
Debug.Print "Fehler 2"
CloseHandle hDrive
End
End If

If Not GetDiskGeometry(hDrive, lpGeometry) Then
Debug.Print "Fehler 3"
CloseHandle hDrive
End
End If

PrintGeometry lpGeometry

CloseHandle hDrive
End Sub

Public Function LockVolume(hDisk As Long) As Boolean
Dim ReturnedByteCount As Long, FSCTL_LOCK_VOLUME As Long

FSCTL_LOCK_VOLUME = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, _
METHOD_BUFFERED, FILE_ANY_ACCESS)

LockVolume = DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, ByVal _
0, 0, ByVal 0, 0, ReturnedByteCount, ByVal 0)
End Function

Public Function UnlockVolume(hDisk As Long) As Boolean
Dim ReturnedByteCount As Long, FSCTL_UNLOCK_VOLUME As Long

FSCTL_UNLOCK_VOLUME = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, _
METHOD_BUFFERED, FILE_ANY_ACCESS)

UnlockVolume = DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME, 0, _
0, 0, 0, ReturnedByteCount, 0)
End Function

Private Function CTL_CODE(lngDeviceType As Long, lngFunction As _
Long, lngMethod As Long, lngAccess As Long) As Long
CTL_CODE = ((lngDeviceType * (2 ^ 16)) Or (lngAccess * (2 ^ _
14)) Or (lngFunction * (2 ^ 2)) Or lngMethod)
End Function

Public Function GetDiskGeometry(hDisk As Long, lpGeometry As _
DISK_GEOMETRY) As Boolean
Dim IOCTL_DISK_GET_DRIVE_GEOMETRY As Long, ReturnedByteCount As Long

IOCTL_DISK_GET_DRIVE_GEOMETRY = CTL_CODE(7, 0, _
METHOD_BUFFERED, FILE_ANY_ACCESS)

GetDiskGeometry = DeviceIoControl(hDisk, _
IOCTL_DISK_GET_DRIVE_GEOMETRY, ByVal 0, 0, lpGeometry, _
Len(lpGeometry), ReturnedByteCount, ByVal 0)
End Function

Public Function DismountVolume(hDisk As Long) As Boolean
Dim ReturnedByteCount As Long, FSCTL_DISMOUNT_VOLUME As Long

FSCTL_DISMOUNT_VOLUME = CTL_CODE(8, 0, METHOD_BUFFERED, _
FILE_ANY_ACCESS)

DismountVolume = DeviceIoControl(hDisk, FSCTL_DISMOUNT_VOLUME, _
ByVal 0, 0, ByVal 0, 0, ReturnedByteCount, ByVal 0)
End Function

Public Sub PrintGeometry(lpGeometry As DISK_GEOMETRY)
Dim MediaType As String

Select Case lpGeometry.MediaType
Case F5_1Pt2_512
MediaType = "5.25, 1.2MB, 512 bytes/sector"
Case F3_1Pt44_512
MediaType = "3.5, 1.44MB, 512 bytes/sector"
Case F3_2Pt88_512
MediaType = "3.5, 2.88MB, 512 bytes/sector"
Case F3_20Pt8_512
MediaType = "3.5, 20.8MB, 512 bytes/sector"
Case F3_720_512
MediaType = "3.5, 720KB, 512 bytes/sector"
Case F5_360_512
MediaType = "5.25, 360KB, 512 bytes/sector"
Case F5_320_512
MediaType = "5.25, 320KB, 512 bytes/sector"
Case F5_320_1024
MediaType = "5.25, 320KB, 1024 bytes/sector"
Case F5_180_512
MediaType = "5.25, 180KB, 512 bytes/sector"
Case F5_160_512
MediaType = "5.25, 160KB, 512 bytes/sector"
Case RemovableMedia
MediaType = "Removable media other than floppy"
Case FixedMedia
MediaType = "Fixed hard disk media"
Case Else
MediaType = "Unknown"
End Select

Debug.Print "Mediatype: " & MediaType
Debug.Print "Cylinders " & lpGeometry.Cylinders.lowpart & " " & _
"Tracks/Cylinder " & lpGeometry.TracksPerCylinder & " " & _
"Sectors/Track " & lpGeometry.SectorsPerTrack
End Sub

Public Sub DiskImage(Source As String, Destination As String)
Dim SourceIsDrive As Boolean, Drive As String, DriveName As _
String, DiskImage As String
Dim hDrive As Long, Geometry As DISK_GEOMETRY, hDiskImage As _
Long, b As Boolean
Dim BytesRead As Long, BytesWritten As Long, FileSize As Long, _
VirtBufSize As Long
Dim NumBufs As Long, IoBuffer As Long, t1 As Single, t2 As Single

SourceIsDrive = False
If Right$(Source, 1) = ":" Then
SourceIsDrive = True
Drive = "\\.\" & Source
DriveName = Source
DiskImage = Destination
End If

If Right$(Destination, 1) = ":" Then
If SourceIsDrive Then
Debug.Print "Fehler 1"
Exit Sub
End If

SourceIsDrive = False
Drive = "\\.\" & Destination
DriveName = Destination
DiskImage = Source
Else
If Not SourceIsDrive Then
Debug.Print "Fehler 2"
Exit Sub
End If
End If

hDrive = CreateFile(Drive, GENERIC_READ Or GENERIC_WRITE, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0, _
OPEN_EXISTING, 0, ByVal 0)

If hDrive = INVALID_HANDLE_VALUE Then
Debug.Print "Fehler 3"
CloseHandle hDrive
Exit Sub
End If

If Not LockVolume(hDrive) Then
Debug.Print "Fehler 4"
CloseHandle hDrive
Exit Sub
End If

If Not GetDiskGeometry(hDrive, Geometry) Then
Debug.Print "Fehler 5"
CloseHandle hDrive
Exit Sub
End If

hDiskImage = CreateFile(DiskImage, GENERIC_READ Or _
GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal _
0, IIf(SourceIsDrive, CREATE_ALWAYS, OPEN_EXISTING), 0, ByVal 0)

If hDiskImage = INVALID_HANDLE_VALUE Then
Debug.Print "Fehler 6"
CloseHandle hDrive
Exit Sub
End If

If SourceIsDrive Then
NumBufs = Geometry.Cylinders.lowpart
VirtBufSize = Geometry.TracksPerCylinder * _
Geometry.SectorsPerTrack * Geometry.BytesPerSector

IoBuffer = VirtualAlloc(ByVal 0, VirtBufSize, MEM_COMMIT, _
PAGE_READWRITE)

If IoBuffer = 0 Then
Debug.Print "Fehler 7"
CloseHandle hDrive
CloseHandle hDiskImage
Exit Sub
End If

If NumBufs > 10 Then
NumBufs = 10
End If
For NumBufs = NumBufs To 1 Step -1
t1 = Timer
b = ReadFile(hDrive, ByVal IoBuffer, VirtBufSize, _
BytesRead, ByVal 0)
t2 = Timer

Debug.Print BytesRead / (t2 - t1) / 1000 & " Kilobytes/s lesen"

If b And BytesRead <> 0 Then
t1 = Timer
b = WriteFile(hDiskImage, ByVal IoBuffer, BytesRead, _
BytesWritten, ByVal 0)
t2 = Timer

If t2 - t1 <> 0 Then
Debug.Print BytesRead / (t2 - t1) / 1000 & " " & _
"Kilobytes/s schreiben"
End If

If Not b And (BytesRead <> BytesWritten) Then
Debug.Print "Fehler 8"
CloseHandle hDrive
CloseHandle hDiskImage
Exit Sub
End If
Else
Debug.Print "Fehler 9"
CloseHandle hDrive
CloseHandle hDiskImage
Exit Sub
End If
Next NumBufs
Else
Debug.Print "Formatieren und kopieren"
End If

DismountVolume hDrive
UnlockVolume hDrive

CloseHandle hDrive
CloseHandle hDiskImage

Debug.Print "Fertig"
End Sub

Public Function LowLevelFormat(hDisk As Long, lpGeometry As _
DISK_GEOMETRY) As Boolean
Dim FormatParameters As FORMAT_PARAMETERS, lpBadTrack As Long
Dim i As Long, b As Boolean, ReturnedByteCount As Long, _
IOCTL_DISK_FORMAT_TRACKS As Long

IOCTL_DISK_FORMAT_TRACKS = CTL_CODE(7, &H6, METHOD_BUFFERED, _
FILE_READ_ACCESS Or FILE_WRITE_ACCESS)

FormatParameters.MediaType = lpGeometry.MediaType
FormatParameters.StartHeadNumber = 0
FormatParameters.EndHeadNumber = lpGeometry.TracksPerCylinder - 1
lpBadTrack = LocalAlloc(LMEM_ZEROINIT, _
lpGeometry.TracksPerCylinder * 2)

For i = 0 To lpGeometry.Cylinders.lowpart - 1
FormatParameters.StartCylinderNumber = i
FormatParameters.EndCylinderNumber = i

b = DeviceIoControl(hDisk, IOCTL_DISK_FORMAT_TRACKS, _
FormatParameters, Len(FormatParameters), lpBadTrack, _
lpGeometry.TracksPerCylinder * LenB(lpBadTrack), _
ReturnedByteCount, ByVal 0)

If Not b Then
LocalFree lpBadTrack
LowLevelFormat = b
Exit Function
End If
Next i

LocalFree lpBadTrack
LowLevelFormat = True
End Function

Public Sub Format(Drive As String)
Dim SourceIsDrive As Boolean, DriveName As String
Dim hDrive As Long, Geometry As DISK_GEOMETRY

DriveName = Drive
Drive = "\\.\" & Drive

hDrive = CreateFile(Drive, GENERIC_READ Or GENERIC_WRITE, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0, _
OPEN_EXISTING, 0, ByVal 0)

If hDrive = INVALID_HANDLE_VALUE Then
Debug.Print "Fehler 3"
CloseHandle hDrive
Exit Sub
End If

If Not LockVolume(hDrive) Then
Debug.Print "Fehler 4"
CloseHandle hDrive
Exit Sub
End If

If Not GetDiskGeometry(hDrive, Geometry) Then
Debug.Print "Fehler 5"
CloseHandle hDrive
Exit Sub
End If


If LowLevelFormat(hDrive, Geometry) Then
Debug.Print "Formatiert"
Else
Debug.Print "Fehler"
End If


DismountVolume hDrive
UnlockVolume hDrive

CloseHandle hDrive

Debug.Print "Fertig"
End Sub