VB.NET 2008 或更高版本:内存违规通过 winapi 读取 STDIN

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

我正在尝试将 VB6 应用程序移植到 VB.NET。 这是一个控制台应用程序,它从STDIN读取数据,修改数据并将其写入STDOUT。

Google 是我的朋友,所以我现在花了几天时间寻找解决方案。 此搜索为我提供了多个版本的 WinApi ReadFile,我尝试了所有版本。 我也尝试了几个版本的 .NET。 但是.....在我尝试过的每一种组合中,我都会不断收到内存冲突错误。 错误因我使用的 ReadFile 变体而略有不同,但都是相似的。

例如,参见错误的这种变体:

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
   
   

我用这个来获取句柄:

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

这是产生上述错误的 ReadFile API 调用的变体:

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

这是我发现并尝试过的所有其他变体。都给出类似的错误:

' 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

我在代码中使用它的方式在这里:

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

有人可以帮我找到一种工作方式来读取 STDIN 并写入 VB.NET 中的 STDOUT 吗?

我想知道...

.NET Framework 提供 System.Console class,其中包含 reading/writing 标准 input/output 流的功能。是否有不使用该功能的特殊原因?

我猜你的 GetData 方法可以改写成这样:

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

但是,“即时”处理输入流数据可能比先将整个输入流读取并存储到字符串中然后再开始处理更有效(尤其是对于内存使用)。