File io 在命名管道上从visual basic.net 2010调用WriteFile时出错

File io 在命名管道上从visual basic.net 2010调用WriteFile时出错,file-io,vb.net-2010,named-pipes,.net-3.0,File Io,Vb.net 2010,Named Pipes,.net 3.0,我整天都在讨论这个问题,我就是搞不懂关于这个问题的各种文档(有时相互冲突)。更让人困惑的是,在白天的某个时候,这确实(某种程度上)起了作用——即没有抛出访问冲突错误。但管道另一端的数据毫无意义,因此我怀疑它只是偶然“起作用” 我有一个vb.net程序(使用.net 3.0,因此不支持System.IO.NamedPipes:()它创建一个命名管道,并等待另一个应用程序连接并发送一些数据。作为“确认”,我希望vb程序发回收到的消息的总长度。我可以创建管道,等待连接并接收消息,但它会阻止尝试使用Wr

我整天都在讨论这个问题,我就是搞不懂关于这个问题的各种文档(有时相互冲突)。更让人困惑的是,在白天的某个时候,这确实(某种程度上)起了作用——即没有抛出访问冲突错误。但管道另一端的数据毫无意义,因此我怀疑它只是偶然“起作用”

我有一个vb.net程序(使用.net 3.0,因此不支持System.IO.NamedPipes:()它创建一个命名管道,并等待另一个应用程序连接并发送一些数据。作为“确认”,我希望vb程序发回收到的消息的总长度。我可以创建管道,等待连接并接收消息,但它会阻止尝试使用
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)
一旦代码到达
WriteFile
,它就会抛出一个AccessViolationException——“尝试读取或写入受保护的内存”。我假设这是对
dataOut
参数的抱怨,但它没有给出进一步的细节。到目前为止,我尝试过的内容包括:

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

需要说明的是,来自另一个应用程序的消息被完美地接收,并且
recvBuffer
的字符串与发送的字符串完全相同。我只是无法说服WriteFile合作(除了一次,可能是偶然的,我无法重复).我希望这只是声明或变量初始化中的一些东西-有什么线索吗?

根据Hans关于使用pinvoke.net的建议,这里是签名和调用的组合,最终对我有效-以防其他人可以使用它。我知道我可能应该将前3个声明转换为follow与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
声明函数CreateNamedPipe Lib“kernel32”别名“CreateNamedPipe”(_
ByVal lpName作为字符串,ByVal dwOpenMode作为整数_
ByVal dwPipeMode为整数,ByVal Nmaxinstance为整数_
ByVal nOutBufferSize为整数,ByVal nInBufferSize为整数_
ByVal nDefaultTimeOut为整数,ByVal lpSecurityAttributes为IntPtr)_
作为安全文件句柄
声明函数ConnectNamedPipe Lib“kernel32”(_
ByVal hNamedPipe作为安全文件句柄,ByVal lpOverlapped作为System.Threading.NativeOverlapped)_
作为安全文件句柄
声明函数CloseHandle Lib“kernel32”(_
ByVal hFile作为安全文件句柄)_
作为整数
好友共享函数写入文件(_
ByVal文件作为SafeFileHandle_
ByVal缓冲区作为System.Text.StringBuilder_
ByVal NumberOfBytesToWrite为整数_
ByRef NumberOfBytes写入整数_
ByRef重叠为System.Threading.NativeOverlapped)作为布尔值
端函数
好友共享函数读取文件(_
ByVal文件作为SafeFileHandle_
ByVal缓冲区作为System.Text.StringBuilder_
ByVal NumberOfBytesToRead为整数_
ByRef numberOfBytes读取为整数_
ByRef重叠为System.Threading.NativeOverlapped)作为布尔值
端函数
...
pipeN2Q=CreateNamedPipe(“\\.\pipe\N2Q”,openMode,pipeMode,10,1024,1024,2000,IntPtr.Zero)
如果没有管道N2Q.IsInvalid,则
如果未连接NamedPipe(pipeN2Q,无)。则为无效
Dim RX计数为整数=0
Dim txCount As Integer=0
Dim dataIn作为新System.Text.StringBuilder
res=ReadFile(pipeN2Q、数据输入、256、rxCount、Nothing)
如果是0那么
作为新的StringBuilder(dataIn.Length.ToString)调整数据输出
res=WriteFile(pipeN2Q、dataOut、dataOut.Length、txCount、Nothing)
其他的
Debug.Print(“读取文件错误:&Err.LastDllError”)
如果结束
其他的
Debug.Print(“ConnectNamedPipe错误:&Err.LastDllError”)
如果结束
如果关闭手柄(pipeN2Q)为0,则
Debug.Print(“管道关闭”)
其他的
Debug.Print(“CloseHandle ERRPR:&Err.LastDllError”)
如果结束
其他的
Debug.Print(“CreateNamedPipe错误:&Err.LastDllError)
如果结束

你的pinvoke声明不好。请使用pinvoke.net网站查找好的声明。谢谢-pinvoke.net是我提到的网站之一-尽管它有3个不同的WriteFile签名,ReadFile的返回类型显示为SafeFileHandle,而在MSDN上它显示为Boolean。所以我并不真正信任它…Howev呃,使用StringBuilder作为传输缓冲区类型的版本终于允许我从两侧发送干净的数据,因此感谢指针。嘿,你在这里的回答可能对我正在做的事情有所帮助。但是我有一个问题…当你调用
CreateNamedPipe
时,应该如何
OpenMode
pipeMode
be?谢谢!哇!我必须清理一些文件才能找到它!我现在开始使用套接字-如果你有可能的话,这是一个更简洁的解决方案。不过,下面是我在上面代码中使用的声明,它们大部分都有效:Dim openMode=PIPE\u ACCESS\u DUPLEX或FILE\u FLAG\u FIRST\u PIPE\u INSTANCE Dim pipeMode=PIPE\u WAIT或PIPE_TYPE_MESSAGE或PIPE_READMODE_MESSAGE您可以在此处找到所有选项: