【发布时间】:2020-11-13 09:13:36
【问题描述】:
我正在尝试将 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 吗?
【问题讨论】:
-
System.String 是不可变的,因此它绝不能作为缓冲区参数的类型出现。请改用 StringBuilder。并且一定要避免这段代码中导致AVE的bug,你必须在调用之前设置它的Capacity。
-
StringBuilder....... 请提供代码示例。我是一个偶尔的 .net 程序员 :-)
-
@RensDuijsens 见Default Marshaling for Strings: Fixed Length String Buffers。尽管该示例是为 C# 编写的,但同样的概念也适用于 VB.NET
标签: vb.net winapi stdout stdin kernel32