2013-12-19 52 views
0

我一整天都在關注這個問題,並且我無法理解關於此的各種(有時是衝突的)文檔。爲了增加混淆,在白天的某個時候,這確實(有點)工作 - 即沒有發出訪問違規錯誤。但是管道另一端的數據是無稽之談,所以我懷疑這只是偶然發生的。在命名管道上從visual basic .net 2010調用WriteFile的錯誤

我有一個vb.net程序(使用.net 3.0所以不支持System.IO.NamedPipes :()它創建一個命名管道,並等待另一個應用程序來連接和發送一些數據作爲'ack' ,然後我想讓vb程序發送收到的消息的總長度,我可以創建管道,等待連接並接收消息,但是它會嘗試使用WriteFile發送'ack'。我使用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聲明:使用Marshal.AllocHGlobal(txReq)ByVal lpBuffer as IntPtr
  • 清分數據出,並使用Marshal.WriteInt16()
  • 分配的dataOut大的緩衝初始化(1024個字節)並將它們初始化爲零

要清楚,來自其他應用程序的消息可以完美接收,並且recvBuffer與發送的字符串完全相同。我無法說服WriteFile進行合作(除了一次,也許偶然,我無法重複)。我希望這只是變量的聲明或初始化 - 任何線索?

+1

您的標註聲明不好。使用pinvoke.net網站找到好的。 –

+0

謝謝 - pinvoke.net是我一直在提到的網站之一 - 雖然它有3個不同的WriteFile簽名,ReadFile的返回類型顯示爲SafeFileHandle,而在MSDN上顯示爲布爾值。所以我沒有真正相信它......但是,使用StringBuilder作爲傳輸緩衝區類型的版本終於允許我從雙方發送乾淨的數據,所以感謝指針。 – dsl101

回答

0

根據Hans的建議使用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 
+0

嘿,你在這裏的答案可能會幫助我解決我正在做的事情。但是我有個問題......當你調用'CreateNamedPipe'時,'OpenMode'和'pipeMode'應該是什麼?謝謝! – Rob

+1

哇!必須清除一些文件才能找到!我現在已經開始使用套接字 - 如果這對您來說是一種可能性,那麼它會更加整潔。然而,這裏是我的代碼中使用上述聲明,是說大部分工作: 昏暗的openMode = PIPE_ACCESS_DUPLEX或者FILE_FLAG_FIRST_PIPE_INSTANCE 昏暗pipeMode = PIPE_WAIT或者PIPE_TYPE_MESSAGE或者PIPE_READMODE_MESSAGE 你可以在這裏找到所有的選項:HTTP ://msdn.microsoft.com/en-gb/library/windows/desktop/aa365150(v = vs.85)的.aspx – dsl101