Atlanta Custom Software Development 

 
   Search        Code/Page
 

User Login
Email

Password

 

Forgot the Password?
Services
» Web Development
» Maintenance
» Data Integration/BI
» Information Management
Programming
  Database
Automation
OS/Networking
Graphics
Links
Tools
» Regular Expr Tester
» Free Tools


Visual Basic can create applications that communicate to other processes by means of Named Pipes. The Named Pipe must be created on Windows 2000 or Windows NT; however, you can read from and write to that pipe from any 32-bit platform.

This article demonstrates Client/Server communication using a Named Pipe in Visual Basic.

In this article, the process creating the NamedPipe is called the server, and the process connecting to the named pipe is called the client.

There are six steps to creating a named pipe server:

  1. Create a security token for the pipe to allow access to it (to make a Named Pipe available to any process by creating a security token with a Discretionary Access Control List (DACL) that has zero entries in it).
  2. Create the Named Pipe.
  3. Call ConnectNamedPipe to block until a client connects.
  4. Call ReadFile and/or WriteFile to communicate over the pipe.
  5. Call DisconnectNamedPipe when the process is finished using the pipe.
  6. Either CloseHandle on the named pipe, or go back to step 4.

There are three steps to use a Named Pipe from the Named Pipe client:
  1. Call CreateFile to get a handle to the Named Pipe.
  2. Call ReadFile and/or WriteFile to communicate over the pipe.
  3. Call CloseHandle on the filehandle created in CreateFile.


Alternatively, you could call CallNamedPipe, which performs a one-time transaction over the pipe. CallNamedPipe opens the pipe, writes to it, reads from it, then closes the pipe. This is what the client below does.

The following sample demonstrates how to create a Named Pipe Server and Client. It implements only the most rudimentary functions necessary to do so, with a minimal amount of error checking. A fully-functional program should check the return values of the API's that are called, rather than assuming they were successful.

Named Pipe Server

- Create a new standard exe project. Form1 is created by default.
- Add one command button and one textbox to form1
- Add the following code to the form:

Form1.frm (Server)

Click here to copy the following block
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 Command1_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(Text1, 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

Private Sub Form_Load()
  Text1.Text = "\\.\pipe\test"
  Command1.Caption = "Create Pipe"
End Sub

- Create a new module and add the following declarations:

Module1.frm (Server)

Click here to copy the following block
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

- Save the form.

Now we will implement Named Pipe Client

Named Pipe Client

- Create a standard exe project
- Add 1 commandbutton and 3 textboxes. Text3 with multiline=true.
- Add the following code to form1

Click here to copy the following block
Option Explicit
Private Const 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 Command1_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 = Text2.Text
  If Text2.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(Text1, 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
    Text3.Text = temp
  Else
    MsgBox "Error number " & Err.LastDllError & _
        " attempting to call CallNamedPipe.", vbOKOnly
  End If
End Sub

Private Sub Form_Load()
  Text1 = "\\.\pipe\test"
  Text2 = 500
  Command1.Caption = "Send Data"
End Sub

- Note that if the server is running on a machine other than where the client is, you need to change the '.' in the variable szPipeName to the name of the server machine.
- Save the form. To test the code above, first start the server and click anywhere on the form. The server application is now blocking and will appear to have hung, but it is actually waiting for the client to connect. Then start the client application and click the "Call Named Pipe." The client should send the value 500 to the server, which will respond with 500 bytes of data. You can set the value in the cbBytes text box from 0 to 20000 bytes. To stop the server, simply send 0 (Zero) from the client. The client might receive error 233 (ERROR_PIPE_NOT_CONNECTED), but this is normal.

Another improvement to the sample might include the use of IO Completion Ports and/or Non-Blocking Reads and Writes using Overlapped IO. You can find more information on these subjects in the Microsoft Platform SDK.


Submitted By : Nayan Patel  (Member Since : 5/26/2004 12:23:06 PM)

Job Description : He is the moderator of this site and currently working as an independent consultant. He works with VB.net/ASP.net, SQL Server and other MS technologies. He is MCSD.net, MCDBA and MCSE. In his free time he likes to watch funny movies and doing oil painting.
View all (893) submissions by this author  (Birth Date : 7/14/1981 )


Home   |  Comment   |  Contact Us   |  Privacy Policy   |  Terms & Conditions   |  BlogsZappySys

© 2008 BinaryWorld LLC. All rights reserved.