Pipes have been useful for decades for interprocess communication. At a Windows Command prompt, you can type “dir | more”, which just creates a pipe between the DIR command and the MORE command. The standard output for the left side of the pipe is redirected through a pipe to the standard input of the MORE command.

You can use the CreateNamedPipe function to create a named pipe to communicate easily between 2 processes, perhaps on different machines.

Run the sample below.  It creates some code for a “server” to run, then creates an instance of VFP as the server and runs it. The server creates a named pipe and waits for a request for data.

 

The client code then calls the Named pipe with a parameter of “A” to get some data. The server gets the request and responds by sending a string back to the client.

 

To run the server on machine B, you can copy the code to machine B, then change the code so the server code always runs (change the “IF _vfp.StartMode line to “IF .t.” so it always runs)

 

On the client, change the pipe name to the name of the server. For me, I changed it to:

cPipeName="\\calvinh6\pipe\mypipe"  && the name of the server is calvinh6

 

Keep the pipename on the server as \\.\pipe\mypipe

 

 

 

 

 

CLEAR ALL

CLEAR

 

*from Winbase.h:

#define INVALID_HANDLE_VALUE              -1

#define FILE_FLAG_WRITE_THROUGH         0x80000000

#define FILE_FLAG_OVERLAPPED            0x40000000

#define FILE_FLAG_NO_BUFFERING          0x20000000

#define FILE_FLAG_RANDOM_ACCESS         0x10000000

#define FILE_FLAG_SEQUENTIAL_SCAN       0x08000000

#define FILE_FLAG_DELETE_ON_CLOSE       0x04000000

#define FILE_FLAG_BACKUP_SEMANTICS      0x02000000

#define FILE_FLAG_POSIX_SEMANTICS       0x01000000

#define FILE_FLAG_OPEN_REPARSE_POINT    0x00200000

#define FILE_FLAG_OPEN_NO_RECALL        0x00100000

#define FILE_FLAG_FIRST_PIPE_INSTANCE   0x00080000

 

#define NMPWAIT_WAIT_FOREVER            0xffffffff

#define NMPWAIT_NOWAIT                  0x00000001

#define NMPWAIT_USE_DEFAULT_WAIT        0x00000000

 

#define CREATE_NEW          1

#define CREATE_ALWAYS       2

#define OPEN_EXISTING       3

#define OPEN_ALWAYS         4

#define TRUNCATE_EXISTING   5

 

#define PIPE_ACCESS_INBOUND         0x00000001

#define PIPE_ACCESS_OUTBOUND        0x00000002

#define PIPE_ACCESS_DUPLEX          0x00000003

 

#define PIPE_CLIENT_END             0x00000000

#define PIPE_SERVER_END             0x00000001

 

 

#define PIPE_WAIT                   0x00000000

#define PIPE_NOWAIT                 0x00000001

#define PIPE_READMODE_BYTE          0x00000000

#define PIPE_READMODE_MESSAGE       0x00000002

#define PIPE_TYPE_BYTE              0x00000000

#define PIPE_TYPE_MESSAGE           0x00000004

 

 

#define PIPE_UNLIMITED_INSTANCES    255

 

*From winerror.h:

#define ERROR_FILE_NOT_FOUND             2

#define ERROR_INVALID_HANDLE             6

#define ERROR_BROKEN_PIPE                109

#define ERROR_BAD_PIPE                   230

#define ERROR_PIPE_BUSY                  231

#define ERROR_NO_DATA                    232

#define ERROR_PIPE_NOT_CONNECTED         233

#define ERROR_MORE_DATA                  234

 

 

DECLARE  integer CreateNamedPipe IN WIN32API ;

  string lpPipeName,;

  integer  dwOpenMode,;

  integer  dwPipeMode,;

  integer  nMaxInstances,;

  integer  nOutBufferSize,;

  integer  nInBufferSize,;

  integer  nDefaultTimeOut,;

  integer  lpSecurityAttributes

DECLARE integer CallNamedPipe IN WIN32API ;

      string lpPipeName,;

      string  lpInBuff,;

      integer nInBuffSize,;

      string @ lpOutBuff,;

      integer nOutBuffSize,;

      integer @lpBytesRead,;

      integer nTimeout

     

DECLARE integer ConnectNamedPipe IN WIN32API integer hNamedPipe, string @ lpOverLapped 

DECLARE integer SetNamedPipeHandleState IN WIN32API integer hNamedPipe,;

      integer @ lpMode,;

      integer @ lpMaxCollectionCount,;

      integer @ lpCollectDataTimeout

 

DECLARE integer PeekNamedPipe IN WIN32API integer hNamedPipe, string @ lpBuffer, integer nBuffSize,   ;

            integer @ lpBytesRead,;

            integer @ lpTotalBytesAvail,;

            integer @ lpBytesLeftThisMessage

 

DECLARE integer ReadFile IN WIN32API integer hFile, string @ lpBuffer, ;

      integer nBytesToRead, integer @ nBytesRead, string @ lpOverLapped

DECLARE integer WriteFile IN WIN32API integer hFile, string  lpBuffer, ;

      integer nBytesToWrite, integer @ nBytesWritten, string @ lpOverLapped

DECLARE integer CloseHandle IN WIN32API integer

DECLARE integer GetLastError IN win32api

 

cPipeName="\\.\pipe\mypipe"

*cPipeName="\\calvinh6\pipe\mypipe" && the name of the server is calvinh6

IF _vfp.StartMode >0    && if we're on the server

 

      *     IF ConnectNamedPipe(hPipe,0) > 0    && wait for client to connect

      *           ?"connected"

      *     ENDIF

      DO WHILE .t.

            hPipe = CreateNamedPipe(cPipeName,;

                  PIPE_ACCESS_DUPLEX + FILE_FLAG_FIRST_PIPE_INSTANCE, ;

                  PIPE_TYPE_MESSAGE + PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,100,100,100,0)

 

            ?"hp=",hPipe

            IF hPipe=INVALID_HANDLE_VALUE

                  ?"CreateNamedPipe GetLastError",GetLastError(),DATETIME()

            ELSE

                  DO WHILE !CHRSAW(.5)

                        IF PeekNamedPipe(hPipe,0,0,0,0,0)=0

                              ?"Peek no data ",GetLastError(),DATETIME()

                        ELSE

                              ?"Peek got data",DATETIME()

                              cBuff=SPACE(1)    && read 1 char from pipe

                              dwRead = 0

                              IF ReadFile(hPipe,@cBuff,LEN(cBuff),@dwRead,0)>0

                                    ?"data read= ",cBuff

                                    DO CASE

                                    CASE cBuff='A'

                                          nBytes=0

                                          cResult=TRANSFORM(DATETIME())+" From Server "+GETENV("COMPUTERNAME")

                                          IF WriteFile(hPipe,cResult, LEN(cResult),@nBytes,0)=0 OR nBytes != LEN(cResult)

                                                ?"Write File GetLastError",GetLastError()

                                          ENDIF

                                    ENDCASE

                              ENDIF

                              CloseHandle(hPipe)

                              hPipe=0

                              INKEY(.5)

                              EXIT

                        ENDIF

                  ENDDO

                  IF hPipe>0

                        CloseHandle(hPipe)

                  ENDIF

                  IF INKEY()>0

                        IF _vfp.StartMode>0

                              QUIT  && if we were started on same machine

                        ELSE

                              EXIT

                        ENDIF

                  ENDIF

            ENDIF

      ENDDO

      RETURN

ENDIF

 

*Client code: create the server and have it DO this program

 

IF LEFT(cPipeName,3)="\\."    && if on the same machine, start the server

      LOCAL ovfp as VisualFoxpro.Application

      ovfp=CREATEOBJECT("VisualFoxpro.Application")

      ovfp.visible=1

      ovfp.left=0

      ovfp.DoCmd("set development off")   && server doesn't need to compile to fxp

      INKEY(.5)

      ovfp.DoCmd("keyboard 'do " + PROGRAM()+"'+CHR(13)")   && start the prg asynchronously

 

      INKEY(2)

ENDIF

FOR i = 1 TO 5

      cBuf=SPACE(50)

      nBytes=0

      IF CallNamedPipe(cPipeName,"A",1,@cbuf,LEN(cBuf),@nBytes,NMPWAIT_USE_DEFAULT_WAIT)>0

            ?"Got data: ",cBuf

      ELSE

            ?"CallNamedPipe GetLastError",GetLastError()

      ENDIF

      INKEY(.5)

ENDFOR

?"done"