27

I am trying to create a simple comunication between 2 processes in C++ ( Windows ) like FIFO in linux. This is my server:

int main()
{
    HANDLE pipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"), GENERIC_READ, 0, NULL, OPEN_EXISTING,    FILE_FLAG_OVERLAPPED, NULL);
    ConnectNamedPipe(pipe, NULL);
    while(TRUE){
        string data;
        DWORD numRead =1 ;
        ReadFile(pipe, &data, 1024, &numRead, NULL);
        cout << data << endl;

}
    CloseHandle(pipe);
    return 0;
}

And this is my client:

int main()
{
    HANDLE pipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    ConnectNamedPipe(pipe, NULL);
    string message = "TEST";
    DWORD numWritten;
    WriteFile(pipe, message.c_str(), message.length(), &numWritten, NULL);
    return 0;
}

The code does't work , how can i fixed it to like FIFO ?

phuclv
  • 37,963
  • 15
  • 156
  • 475
user3052078
  • 487
  • 1
  • 8
  • 20

1 Answers1

78

You cannot create a named pipe by calling CreateFile(..).

Have a look at the pipe examples of the MSDN. Since these examples are quite complex I've quickly written a VERY simple named pipe server and client.

int main(void)
{
    HANDLE hPipe;
    char buffer[1024];
    DWORD dwRead;


    hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
                            PIPE_ACCESS_DUPLEX,
                            PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,   // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
                            1,
                            1024 * 16,
                            1024 * 16,
                            NMPWAIT_USE_DEFAULT_WAIT,
                            NULL);
    while (hPipe != INVALID_HANDLE_VALUE)
    {
        if (ConnectNamedPipe(hPipe, NULL) != FALSE)   // wait for someone to connect to the pipe
        {
            while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
            {
                /* add terminating zero */
                buffer[dwRead] = '\0';

                /* do something with data in buffer */
                printf("%s", buffer);
            }
        }

        DisconnectNamedPipe(hPipe);
    }

    return 0;
}

And here is the client code:

int main(void)
{
    HANDLE hPipe;
    DWORD dwWritten;


    hPipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"), 
                       GENERIC_READ | GENERIC_WRITE, 
                       0,
                       NULL,
                       OPEN_EXISTING,
                       0,
                       NULL);
    if (hPipe != INVALID_HANDLE_VALUE)
    {
        WriteFile(hPipe,
                  "Hello Pipe\n",
                  12,   // = length of string + terminating '\0' !!!
                  &dwWritten,
                  NULL);

        CloseHandle(hPipe);
    }

    return (0);
}

You should replace the name of the pipe TEXT("\\\\.\\pipe\\Pipe") by a #define which is located in a commonly used header file.

gmargari
  • 171
  • 1
  • 9
Lukas Thomsen
  • 3,089
  • 2
  • 17
  • 23
  • 1
    I've receive an error where is `FILE_FLAG_FIRST_PIPE_INSTANCE` : 'FILE_FLAG_FIRST_PIPE_INSTANCE' was not declared in this scope but i've read on msdn and it shouldn't be any error here. – user3052078 Oct 25 '14 at 12:04
  • after first client , the server don't read any other messsage, why he is not able to pass thorught first if ? – user3052078 Oct 25 '14 at 12:13
  • 1
    @user3052078 I've made some changes and now it works if the client runs another time. Further note that if your're sending multiple messages from the client the server may read the data with one single `ReadFile(..)` (= 5x WriteFile by client != 5x ReadFile by server). Therefore if the strings sent by the client contain '\0' characters a simple `printf("%s", buffer);` as within this example wouldn't work since printf stops at the first '\0'. – Lukas Thomsen Oct 25 '14 at 14:39
  • `CreateFile` returns `INVALID_HANDLE_VALUE` on failure. And `INVALID_HANDLE_VALUE != NULL`. – David Heffernan Feb 12 '15 at 19:47
  • @LukasThomsen The server code assumes that buffer will be null-terminated after the call to ReadFile(). That assumption is not justified. The server needs to pass in sizeof(buffer)-1 (to leave room for adding a null-terminator) and then add: buffer[dwRead] = 0; prior to the printf call. Also, David Hefferman's comment is correct. – Bruce Dawson Mar 10 '15 at 20:27
  • @DavidHeffernan Houups I've missed that one. Thanks for pointing it out. – Lukas Thomsen Apr 12 '15 at 06:29
  • @BruceDawson You're right adding a terminating zero is important and not done in my example. I didn't do it since the string written to the pipe by the client is zero terminated. I've added your suggestion to my original post to avoid confusion. – Lukas Thomsen Apr 12 '15 at 06:33
  • fyi PIPE_TYPE_BYTE and PIPE_READMODE_BYTE are for the third parameter, not the second. They're both defined as 0 though, so technically the semantics are the same. – Millie Smith Nov 26 '16 at 00:14
  • 4
    I'm late to the party, but if `CreateNamedPipe` succeeds, the outer loop will never exit. Even after calling `DisconnectNamedPipe`, the value of `hPipe` is unchanged. Still, it's a good example that people can work with. – Doug Cuthbertson Feb 16 '17 at 21:12
  • @DougCuthbertson You are right. I've copied this code from a program of mine in which I use the handle to escape the reading loop. – Lukas Thomsen Feb 21 '17 at 19:19
  • The `FILE_FLAG_FIRST_PIPE_INSTANCE` flag comment is misplaced: it should be with the second argument (`dwOpenMode`). – Frerich Raabe Jun 21 '19 at 13:44
  • Does it virtualize the pipe with the `nMaxInstances` parameter? seems like [CreateNamedPipe](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createnamedpipea) is having multiple instances for different clients. – Tony Tannous Oct 24 '19 at 06:28
  • How can i get this to work across 2 machines on the same network? Running 2 windows 10 vms, how can i get this to work with the server on 1 machine and the client on the other. I tried replacing `\\\\.\\pipe\\Pipe` in the client with `\\\\WINDEV1905EVAL2\\pipe\\Pipe` and the client never connects. – prolink007 Mar 18 '20 at 01:28
  • Can someone clarify the reason for 1024 * 16? Why * 16? – scrollout Jul 03 '20 at 17:57
  • @scrollout The 1024*16 parameters of CreateNamedPipe(..) in my example define the size of the input/output buffers of the pipe. So therefore 1024*16 is just an arbitrary value. I've never tested the behaviour with small buffer sizes... Too small values probably result in blocking WriteFile(..) calls when writing to the pipe? – Lukas Thomsen Jul 03 '20 at 18:42