vb.netwinapistdoutstdinkernel32

VB.NET 2008 or higher: Memory violation reading STDIN via winapi


I am trying to port a VB6 application to VB.NET. This is a console application that reads data from STDIN, modifies the data and writes it to STDOUT.

Google is my friend, so I have spend days now on finding a solution. This search provided me with several versions of the WinApi ReadFile and I tried them all. Also I have tried several versions of .NET. However.....In every combination that I have tried, I keep getting memory violation errors. Errors differ a little bit depending on the ReadFile variant im using, but the are all similar.

See for instance this variant of the error:

makeDataFilter < Test.in > Test.Out

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at makeDataFilter.Filter_IO.ReadFile(Int64 hFile, String& lpBuffer, Int64 nNumberOfBytesToRead, Int64 lpNumberOfBytesRead, String& lpOverlapped)
   at makeDataFilter.Filter_IO.GetData() in C:\Projects\.NET 2019\makeDataFilter\Filter_IO.vb:line 229
   at makeDataFilter.Filter_IO.Main() in C:\Projects\.NET 2019\makeDataFilter\Filter_IO.vb:line 118
   
   

I use this to get a handle:

Public Const STD_INPUT_HANDLE = -10&
Public Const STD_OUTPUT_HANDLE = -11&

' Open en handle to StdIn or StdOut
    Private Declare Function GetStdHandle Lib "kernel32.dll" (
        ByVal nStdHandle As Int32
    ) As IntPtr

Here is the variant of the ReadFile API call that produces the error above:

<DllImport("kernel32")>
Declare Function ReadFile(
    ByVal hFile As Long,
    lpBuffer As String,
    nNumberOfBytesToRead As Long,
    lpNumberOfBytesRead As Long,
    lpOverlapped As String
) As String

And here are all the other variations that I found and tried. All give similar errors:

' Read from Stdin
'Declare Function ReadFile Lib "kernel32.dll" (
'    ByVal hFile As Long,
'    lpBuffer As Any,
'    ByVal nNumberOfBytesToRead As Long,
'    lpNumberOfBytesRead As Long,
'    lpOverlapped As Any
') As Long

'Declare Function ReadFile Lib "kernel32" (
'      ByVal hFile As Long,
'      lpBuffer As String,
'      ByVal nNumberOfBytesToRead As Long,
'      lpNumberOfBytesRead As Long,
'      ByVal lpOverlapped As String
') As Long

'Declare Auto Function ReadFile Lib "Kernel32.dll" (
'    ByVal hndRef As Integer,
'    ByVal lpBuffer As StringBuilder,
'    ByVal numberOfBytesToRead As Integer,
'    ByRef numberOfBytesRead As Integer,
'    ByVal flag As Integer
') As Boolean

'Declare Function ReadFile Lib "kernel32" (
'        ByVal hFile As Integer,
'        ByVal lpBuffer As Integer,
'        ByVal nNumberOfBytesToRead As Integer,
'        lpNumberOfBytesRead As Integer,
'        ByVal lpOverlapped As Integer
') As Integer

The way I use it in my code is here:

Sub GetData()
    Dim sBuff As String         
    Dim lBytesRead As Long      
    Dim rc As Long              
                                
    lContentLength = 256        
    sBuff = lContentLength      
    Do
        rc = ReadFile(hStdIn, sBuff, lContentLength, lBytesRead, 0&)
        sFilterData &= Left$(sBuff, lBytesRead)
    Loop While rc = 1
End Sub

Can somebody please assist me in finding a working way to read from STDIN and write to STDOUT in VB.NET please?


Solution

  • I am wondering...

    The .NET Framework provides a System.Console class, which contains functionality for reading/writing the standard input/output streams. Is there a special reason for not using that functionality?

    I guess your GetData method could be rewritten to something like this:

    Sub GetData()
        sFilterData = Console.In.ReadToEnd()
    End Sub
    

    However, it might be more efficient (especially for memory usage) to process the input stream data "on the fly" instead of reading and storing the entire input stream into a string first and then start processing.