我整天都在喋喋不休地谈论这个问题,而我却无法理解这方面的各种(有时相互矛盾的)文档。为了增加混乱,在白天的某个时刻,这确实(某种程度上)工作 - 即没有抛出访问冲突错误。但管道另一端的数据是胡说八道,所以我怀疑它只是偶然“起作用”。
我有一个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
的声明,以便声明WriteFile
:lpBuffer
ByVal lpBuffer as IntPtr
分配dataOut并使用Marshal.AllocHGlobal(txReq)
Marshal.WriteInt16()
(1024字节)分配大缓冲区并将其初始化为零要清楚,来自其他应用程序的消息已完全收到,dataOut
的字符串与发送完全一致。我只是不能说服WriteFile合作(除了一次,也许是偶然的,我无法重复它)。我希望它只是声明或变量初始化中的一些东西 - 任何线索?
答案 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