CreateFile API call in VB .NET

T

Terry Olsen

I'm trying to create a disk image of a floppy disk. Since I can't open
the device using the system.io methods, i'm trying to use the CreateFile
API to get a handle for me. But the call fails (returning a -1).
Here's the code:

Const GENERIC_READ = &H80000000
Const OPEN_EXISTING = 3
Const FILE_SHARE_READ = &H1
Const FILE_SHARE_WRITE = &H2
Const FILE_ATTRIBUTE_NORMAL = &H80
Const FILE_FLAG_NO_BUFFERING = &H20000000

Declare Function CreateFile Lib "kernel32"
Alias "CreateFileA" (ByVal lpFileName As String, _
ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, _
ByVal lpSecurityAttributes As Long, _
ByVal dwCreationDistribution As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As IntPtr

Dim fh As IntPtr = CreateFile("\\.\A:", _
GENERIC_READ, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, _
0, _
OPEN_EXISTING, _
FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_NO_BUFFERING, _
0)

I'm hoping someone can tell me what's wrong here and help me fix it so I
get a valid handle returned.
 
H

Herfried K. Wagner [MVP]

Terry Olsen said:
I'm trying to create a disk image of a floppy disk. Since I can't open
the device using the system.io methods, i'm trying to use the CreateFile
API to get a handle for me. But the call fails (returning a -1).
Here's the code:

Const GENERIC_READ = &H80000000
Const OPEN_EXISTING = 3
Const FILE_SHARE_READ = &H1
Const FILE_SHARE_WRITE = &H2
Const FILE_ATTRIBUTE_NORMAL = &H80
Const FILE_FLAG_NO_BUFFERING = &H20000000

Declare all of the constants as 'Int32'.
Declare Function CreateFile Lib "kernel32"
Alias "CreateFileA" (ByVal lpFileName As String, _
ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, _
ByVal lpSecurityAttributes As Long, _
ByVal dwCreationDistribution As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As IntPtr

Use this declaration instead (untested):

\\\
Imports System.Runtime.InteropServices
..
..
..
Private Declare Auto Function CreateFile Lub "kernel32.dll" ( _
ByVal lpFileName As String, _
ByVal dwDesiredAccess As Int32, _
ByVal dwShareMode As Int32, _
ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES, _
ByVal dwCreationDistribution As Int32, _
ByVal dwFlagsAndAttributes As Int32, _
ByVal hTemplateFile As IntPtr _
) As IntPtr

<StructLayout(LayoutKind.Sequential)> _
Private Structure SECURITY_ATTRIBUTES
Public nLength As Int32
Public lpSecurityDescriptor As IntPtr
Public bInheritHandle As Boolean
End Structure
///
 
T

Terry Olsen

The error code being returned from Err.lastDLLError is 87, which equates
to "The parameter is incorrect." Now which parameter are we talking
about? Still can't figure it out.
 
R

Rocky

Give this a try,

Declare Auto Function CreateFile Lib "kernel32.dll" (ByVal lpFileName As
String, _
ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer, _
ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As
Integer, _
ByVal dwFlagsAndAttributes As Integer, ByVal hTemplateFile As IntPtr)
As IntPtr

Dim handle As IntPtr
handle = CreateFile("\\.\\A:", GENERIC_READ, FILE_SHARE_READ Or
FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero)
 
T

Terry Olsen

Thanks Herfried & Rocky. I'm getting a valid handle now with the
following function call:

Dim fh As IntPtr = CreateFile("\\.\A:", _
GENERIC_READ, _
FILE_SHARE_READ, _
IntPtr.Zero, _
OPEN_EXISTING, _
FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_NO_BUFFERING, _
0)

All variables are Int32. Great. Now when I try to open a stream for
reading using:

Dim sr As New FileStream(fh, FileAccess.Read)

I get...

Unhandled Exception: System.IO.IOException: The parameter is incorrect.

at System.IO.__Error.WinIOError(Int32 errorCode, String str)
at System.IO.FileStream.get_Length()
at System.IO.FileStream..ctor(IntPtr handle, FileAccess access, Boolean
ownsHandle, Int32 bufferSize, Boolean isAsync)
at System.IO.FileStream..ctor(IntPtr handle, FileAccess access)
 
R

Rocky

You have to use the ReadFile API

Private Declare Function ReadFile Lib "kernel32.dll" (ByVal hFile As
IntPtr, ByVal lpBuffer As IntPtr, ByVal nNumberOfBytesToRead As Int32, ByRef
lpNumberOfBytesRead As Int32, ByVal lpOverlapped As IntPtr) As Int32
 
H

Herfried K. Wagner [MVP]

T

Terry Olsen

You guys have helped me to read from the floppy and create an image.
Thanks! Now I'm trying to create a floppy from the image. You'd think
it would be easy. But now i'm getting another error. Here's the code:

Dim buf(18432) As Byte
Dim fh As IntPtr = CreateFile("\\.\" & cboFloppy.Text, _
GENERIC_WRITE, _
FILE_SHARE_WRITE, _
IntPtr.Zero, _
OPEN_EXISTING, _
FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_NO_BUFFERING, _
0)

If fh.ToInt32 < 0 Then
MsgBox("Bad Disk or No Disk in Drive. Can't continue.",
MsgBoxStyle.Critical)
btnCreate.Enabled = True
Exit Sub
End If

Dim sr As New FileStream(ImageName, FileMode.Open, FileAccess.Read,
FileShare.None)

With ProgressBar1
..Minimum = 0
..Maximum = 80
..Value = 0
End With

For i As Integer = 1 To 80
sr.Read(buf, 0, 18432)
Dim y As Int32 = 0
Dim x As Int32
x = WriteFile(fh, buf, 18432, y, IntPtr.Zero) 'This line give me an
"object reference not set to an instance" message.
Next

This routine is almost identical to the routine that reads from the
floppy and writes to a file. This one just reads from the file and
attempts to write to the floppy. But I'm getting the error above. Hope
you can help. Thanks.
 
H

Herfried K. Wagner [MVP]

Terry Olsen said:
x = WriteFile(fh, buf, 18432, y, IntPtr.Zero) 'This line give me an
"object reference not set to an instance" message.
Next

Post the declaration of 'WriteFile' you are using.
 
T

Terry Olsen

Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As
IntPtr, _
ByVal lpBuffer As Byte(), _
ByVal nNumberOfBytesToWrite As Int32, _
ByVal lpNumberOfBytesWritten As Int32, _
ByVal lpOverlapped As IntPtr) As Int32
 
T

Terry Olsen

Thanks! That worked. Don't know how I missed that. My ReadFile was
correctly declared... go figure...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top