如何使用名为 Visual Basic 的 32 位程序中的管道
文章编号: 177696 -
查看本文应用于的产品
Visual Basic 可以创建与其他进程通信通过命名管道的应用程序。
必须在 Windows 2000 或 Windows NT ; 创建命名管道
但是,您可以读取和写入该管道从任何 32 位平台。
本文演示如何在 Visual Basic 中使用命名管道客户端/服务器通信。
在本文中,创建命名管道的过程被称为服务器,并连接到命名管道的过程被称为客户端。
有六个步骤创建一个命名的管道服务器:
- 创建安全令牌管道允许对它 (以使通过创建安全令牌与自由访问控制列表 (DACL) 包含零个条目的任何进程可用的命名管道) 的访问。
- 创建命名的管道。
- 调用 ConnectNamedPipe,阻止直到客户端连接。
- 调用 ReadFile 和/或写文件通过管道进行通信。
- 在完成该过程调用 DisconnectNamedPipe 使用管道。
- 任一 CloseHandle 上的命名的管道或转到步骤 4。
有三个步骤,使用命名管道客户端从命名管道:
- 调用 CreateFile 以获取命名管道的句柄。
- 调用 ReadFile 和/或写文件通过管道进行通信。
- 在 CreateFile 中创建的文件句柄上调用 CloseHandle。
或者,可以调用 CallNamedPipe,通过管道执行一次性交易记录。
CallNamedPipe 打开管道,将写入到它,读取它,然后关闭管道。
这是下面的客户端所做的事情。
下面的示例演示如何创建命名管道服务器和客户端。
它实现了只有最基本必需的功能为此,请使用少量的错误检查。
全功能的程序应该检查的 api 的调用时,返回的值,而不是假定它们成功。
命名的管道服务器
- 创建新的项目。默认情况下,将创建 Form1。
- 向表单中添加以下代码:
Option Explicit
Private Const szPipeName = "\\.\pipe\bigtest"
Private Const BUFFSIZE = 20000
Private BigBuffer(BUFFSIZE) As Byte, pSD As Long
Private sa As SECURITY_ATTRIBUTES
Private hPipe As Long
Private Sub Form_Click()
Dim i As Long, dwOpenMode As Long, dwPipeMode As Long
Dim res As Long, nCount As Long, cbnCount As Long
For i = 0 To BUFFSIZE - 1 'Fill an array of numbers
BigBuffer(i) = i Mod 256
Next i
'Create the NULL security token for the pipe
pSD = GlobalAlloc(GPTR, SECURITY_DESCRIPTOR_MIN_LENGTH)
res = InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)
res = SetSecurityDescriptorDacl(pSD, -1, 0, 0)
sa.nLength = LenB(sa)
sa.lpSecurityDescriptor = pSD
sa.bInheritHandle = True
'Create the Named Pipe
dwOpenMode = PIPE_ACCESS_DUPLEX Or FILE_FLAG_WRITE_THROUGH
dwPipeMode = PIPE_WAIT Or PIPE_TYPE_MESSAGE Or PIPE_READMODE_MESSAGE
hPipe = CreateNamedPipe(szPipeName, dwOpenMode, dwPipeMode, _
10, 10000, 2000, 10000, sa)
Do 'Wait for a connection, block until a client connects
res = ConnectNamedPipe(hPipe, ByVal 0)
'Read/Write data over the pipe
cbnCount = 4
res = ReadFile(hPipe, nCount, LenB(nCount), cbnCount, ByVal 0)
If nCount <> 0 Then
If nCount > BUFFSIZE Then 'Client requested nCount bytes
nCount = BUFFSIZE 'but only send up to 20000 bytes
End If
'Write the number of bytes requested
res = WriteFile(hPipe, BigBuffer(0), nCount, cbnCount, ByVal 0)
'Make sure the write is finished
res = FlushFileBuffers(hPipe)
End If
'Disconnect the NamedPipe
res = DisconnectNamedPipe(hPipe)
Loop Until nCount = 0
'Close the pipe handle
CloseHandle hPipe
GlobalFree (pSD)
End
End Sub
- 创建一个新的模块并添加以下声明:
Option Explicit
Public Const FILE_ATTRIBUTE_NORMAL = &H80
Public Const FILE_FLAG_NO_BUFFERING = &H20000000
Public Const FILE_FLAG_WRITE_THROUGH = &H80000000
Public Const PIPE_ACCESS_DUPLEX = &H3
Public Const PIPE_READMODE_MESSAGE = &H2
Public Const PIPE_TYPE_MESSAGE = &H4
Public Const PIPE_WAIT = &H0
Public Const INVALID_HANDLE_VALUE = -1
Public Const SECURITY_DESCRIPTOR_MIN_LENGTH = (20)
Public Const SECURITY_DESCRIPTOR_REVISION = (1)
Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Public Const GMEM_FIXED = &H0
Public Const GMEM_ZEROINIT = &H40
Public Const GPTR = (GMEM_FIXED Or GMEM_ZEROINIT)
Declare Function GlobalAlloc Lib "kernel32" ( _
ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
Declare Function CreateNamedPipe Lib "kernel32" Alias _
"CreateNamedPipeA" ( _
ByVal lpName As String, _
ByVal dwOpenMode As Long, _
ByVal dwPipeMode As Long, _
ByVal nMaxInstances As Long, _
ByVal nOutBufferSize As Long, _
ByVal nInBufferSize As Long, _
ByVal nDefaultTimeOut As Long, _
lpSecurityAttributes As Any) As Long
Declare Function InitializeSecurityDescriptor Lib "advapi32.dll" ( _
ByVal pSecurityDescriptor As Long, _
ByVal dwRevision As Long) As Long
Declare Function SetSecurityDescriptorDacl Lib "advapi32.dll" ( _
ByVal pSecurityDescriptor As Long, _
ByVal bDaclPresent As Long, _
ByVal pDacl As Long, _
ByVal bDaclDefaulted As Long) As Long
Declare Function ConnectNamedPipe Lib "kernel32" ( _
ByVal hNamedPipe As Long, _
lpOverlapped As Any) As Long
Declare Function DisconnectNamedPipe Lib "kernel32" ( _
ByVal hNamedPipe As Long) As Long
Declare Function WriteFile Lib "kernel32" ( _
ByVal hFile As Long, _
lpBuffer As Any, _
ByVal nNumberOfBytesToWrite As Long, _
lpNumberOfBytesWritten As Long, _
lpOverlapped As Any) As Long
Declare Function ReadFile Lib "kernel32" ( _
ByVal hFile As Long, _
lpBuffer As Any, _
ByVal nNumberOfBytesToRead As Long, _
lpNumberOfBytesRead As Long, _
lpOverlapped As Any) As Long
Declare Function FlushFileBuffers Lib "kernel32" ( _
ByVal hFile As Long) As Long
Declare Function CloseHandle Lib "kernel32" ( _
ByVal hObject As Long) As Long
- 保存该窗体。
命名的管道客户端
- 创建新的项目。默认情况下,将创建 Form1。
- 向表单中添加下列控件:
Type Name Caption/Default Value
---- ---- ---------------------
TextBox cbBytes 500
CommandButton cmdCallNamedPipe Call Named Pipe
TextBox txtReceive
- 向表单中添加以下代码:
Option Explicit
Private Const szPipeName = "\\.\pipe\bigtest", BUFFSIZE = 20000
Private Declare Function CallNamedPipe Lib "kernel32" Alias _
"CallNamedPipeA" ( _
ByVal lpNamedPipeName As String, _
lpInBuffer As Any, _
ByVal nInBufferSize As Long, _
lpOutBuffer As Any, _
ByVal nOutBufferSize As Long, _
lpBytesRead As Long, _
ByVal nTimeOut As Long) As Long
Private Sub cmdCallNamedPipe_Click()
Dim res As Long, myStr As String, i As Long, cbRead As Long
Dim numBytes As Long, bArray() As Byte, temp As String
numBytes = cbBytes.Text
If cbBytes.Text < 0 Then
MsgBox "Value must be at least 0.", vbOKOnly
Exit Sub
End If
If numBytes > BUFFSIZE Then
numBytes = BUFFSIZE
End If
ReDim bArray(numBytes) 'Build the return buffer
'Call CallNamedPipe to do the transaction all at once
res = CallNamedPipe(szPipeName, numBytes, LenB(numBytes), _
bArray(0), numBytes, _
cbRead, 30000) 'Wait up to 30 seconds for a response
If res > 0 Then
temp = Format(bArray(0), " 000")
For i = 1 To cbRead - 1
If (i Mod 16) = 0 Then temp = temp & vbCrLf
temp = temp & " " & Format(bArray(i), "000")
Next i
txtReceive.Text = temp
Else
MsgBox "Error number " & Err.LastDllError & _
" attempting to call CallNamedPipe.", vbOKOnly
End If
End Sub
- 请注意是否服务器正在运行而不是客户端所在的计算机上,您需要更改。 为服务器计算机的名称变量 szPipeName 中。
- 保存该窗体。若要测试上面的代码,第一次启动服务器,并在窗体上的任意位置单击。服务器应用程序现在阻止即会显示已中断,但实际上正在等待客户端连接。然后启动客户端应用程序并单击"呼叫命名管道"。客户端应将 500 的值发送到服务器将响应 500 字节的数据。您可以设置值的 cbBytes 文本框中从 0 到 20000 个字节。要停止服务器,只需从客户端发送 0 (零)。客户端可能会收到错误 233 (ERROR_PIPE_NOT_CONNECTED),但这是正常现象。
该示例的另一改进可能包括使用 IO 完成端口和/或非阻塞读取和写入使用重叠 IO。您可以在 Microsoft 平台 SDK 中发现这些主题的详细信息。
有几种进程间通信 (IPC) 方法在 Windows 2000、 Windows NT 和允许单向或双向传输数据的多个进程之间的 Windows 95 中可用。
每个平台上可用的 IPC 方法的完整列表,请参阅 Microsoft 知识库中相应的文章:
95900
: Windows NT、 Windows 95 和 win32 进程间通信
|