在命名管道上从visual basic .net 2010调用WriteFile的错误

时间:2013-12-19 20:58:33

标签: file-io vb.net-2010 named-pipes .net-3.0

我整天都在喋喋不休地谈论这个问题,而我却无法理解这方面的各种(有时相互矛盾的)文档。为了增加混乱,在白天的某个时刻,这确实(某种程度上)工作 - 即没有抛出访问冲突错误。但管道另一端的数据是胡说八道,所以我怀疑它只是偶然“起作用”。

我有一个vb.net程序(使用.net 3.0,因此不支持System.IO.NamedPipes :()创建命名管道并等待另一个应用程序连接并发送一些数据。作为'确认',然后我希望vb程序发送回收到的消息的总长度。我能够创建管道,等待连接并接收消息,但它试图使用{{1发送'确认'我用于WriteFile的(当前)定义基于相应的WriteFile,这似乎工作正常:

ReadFile

剥离的代码(错误检查和调试打印已删除)如下所示:

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

Declare Function WriteFile Lib "kernel32" ( _
    ByVal hFile As Long, _
    ByRef lpBuffer As Byte, _
    ByVal nNumberOfBytesToWrite As Integer, _
    ByRef lpNumberOfBytesWritten As Integer, _
    ByVal lpOverlapped As Integer) _
    As Integer

一旦代码到达Dim openMode = PIPE_ACCESS_DUPLEX Or FILE_FLAG_FIRST_PIPE_INSTANCE Dim pipeMode = PIPE_WAIT Or PIPE_TYPE_MESSAGE Or PIPE_READMODE_MESSAGE Dim res ' Result of dll calls pipeN2Q = CreateNamedPipe("\\.\pipe\N2Q", openMode, pipeMode, 10, 1024, 1024, 2000, IntPtr.Zero) res = ConnectNamedPipe(pipeN2Q, 0) Dim rxCount As Integer = 0 ' To hold the number of bytes received Dim txCount As Integer = 0 ' To hold the number of bytes sent Dim txReq As Integer = 2 ' To hold the number of bytes we're going to ask to be sent during the 'ack' Dim dataIn(256) As Byte res = ReadFile(pipeN2Q, dataIn(0), 256, rxCount, Nothing) Dim recvBuffer As String = System.Text.Encoding.ASCII.GetString(dataIn, 0, rxCount) Dim dataOut(2) As Byte dataOut(0) = 42 dataOut(1) = 43 res = WriteFile(pipeN2Q, dataOut(0), txReq, txCount, Nothing) ,它就会抛出一个AccessViolationException - “试图读取或写入受保护的内存”。我假设这是抱怨WriteFile参数,但它没有提供进一步的细节。到目前为止我尝试过的事情包括:

  • 更改dataOut的声明,以便声明WriteFilelpBuffer
  • 使用ByVal lpBuffer as IntPtr分配dataOut并使用Marshal.AllocHGlobal(txReq)
  • 进行初始化
  • Marshal.WriteInt16()(1024字节)分配大缓冲区并将其初始化为零

要清楚,来自其他应用程序的消息已完全收到,dataOut的字符串与发送完全一致。我只是不能说服WriteFile合作(除了一次,也许是偶然的,我无法重复它)。我希望它只是声明或变量初始化中的一些东西 - 任何线索?

1 个答案:

答案 0 :(得分:0)

基于汉斯关于使用pinvoke.net的建议,这里是签名和电话的组合,最终对我有用 - 以防万一其他人可以使用它。我知道我应该将前3个声明转换为与ReadFile / WriteFile相同的格式,但它现在正在工作......

Declare Function CreateNamedPipe Lib "kernel32" Alias "CreateNamedPipeA" ( _
    ByVal lpName As String, ByVal dwOpenMode As Integer, _
    ByVal dwPipeMode As Integer, ByVal nMaxInstances As Integer, _
    ByVal nOutBufferSize As Integer, ByVal nInBufferSize As Integer, _
    ByVal nDefaultTimeOut As Integer, ByVal lpSecurityAttributes As IntPtr) _
    As SafeFileHandle

Declare Function ConnectNamedPipe Lib "kernel32" ( _
    ByVal hNamedPipe As SafeFileHandle, ByVal lpOverlapped As System.Threading.NativeOverlapped) _
    As SafeFileHandle

Declare Function CloseHandle Lib "kernel32" ( _
    ByVal hFile As SafeFileHandle) _
    As Integer

<DllImport("kernel32.dll", SetlastError:=True)> Friend Shared Function WriteFile( _
ByVal File As SafeFileHandle, _
ByVal Buffer As System.Text.StringBuilder, _
ByVal NumberOfBytesToWrite As Integer, _
ByRef NumberOfBytesWritten As Integer, _
ByRef Overlapped As System.Threading.NativeOverlapped) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

<DllImport("kernel32.dll")> Friend Shared Function ReadFile( _
ByVal File As SafeFileHandle, _
ByVal Buffer As System.Text.StringBuilder, _
ByVal NumberOfBytesToRead As Integer, _
ByRef NumberOfBytesRead As Integer, _
ByRef Overlapped As System.Threading.NativeOverlapped) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

...

pipeN2Q = CreateNamedPipe("\\.\pipe\N2Q", openMode, pipeMode, 10, 1024, 1024, 2000, IntPtr.Zero)
If Not pipeN2Q.IsInvalid Then
    If Not ConnectNamedPipe(pipeN2Q, Nothing).IsInvalid Then

        Dim rxCount As Integer = 0
        Dim txCount As Integer = 0

        Dim dataIn As New System.Text.StringBuilder

        res = ReadFile(pipeN2Q, dataIn, 256, rxCount, Nothing)
        If res <> 0 Then
            Dim dataOut As New StringBuilder(dataIn.Length.ToString)

            res = WriteFile(pipeN2Q, dataOut, dataOut.Length, txCount, Nothing)
        Else
            Debug.Print("ReadFile ERROR: " & Err.LastDllError)
        End If
    Else
        Debug.Print("ConnectNamedPipe ERROR: " & Err.LastDllError)
    End If
    If CloseHandle(pipeN2Q) <> 0 Then
        Debug.Print("Pipe closed")
    Else
        Debug.Print("CloseHandle ERRPR: " & Err.LastDllError)
    End If
Else
    Debug.Print("CreateNamedPipe ERROR: " & Err.LastDllError)
End If