1

I have the following c code which I took from the first answer to this question, I am compiling it with C89 in VS2008 so I made a couple of changes for the code to work it properly, it compiles just fine, but it's not able to create process after creating the namedpipe successfully (CreateProcessA is not working) returning always error 2 and printing the message in the panic function.

The program that I am trying to run in the CreateProcessA can be downloaded here, and I normally run it and use it as follows:

> C:\qhichwa>cmd.exe /c "C:\qhichwa\flookup.exe -bx C:\qhichwa\qhichwa.fst"
    wasi <user writes wasi>
    wasi <program responds printing wasi>

    hola <user writes hola>
    + ? <program responds printing + ?>

    <pres ctrl + c to terminate program>

> C:\qhichwa>

The lines between < comments > are just comments.

what are the corrections needed in order to to create the named pipe successfully?

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

// name of our glorious pipe
#define PIPE_NAME L"\\\\.\\pipe\\whatever" // bloody unicode string

// exit on fatal error
void panic(const char * msg)
{
    int err = GetLastError();
    fprintf(stderr, "***PANIC*** %s\n", msg);
    printf("In the child thread: Last Error is %lu\n", err);
    exit(-1);
}

// father process
void father(const char * own_name) // name of our own executable to launch a copy of ourselve
{
    printf("Father process starting\n");

    // create a monodirectional father->child named pipe
    HANDLE pipe = CreateNamedPipe(
        PIPE_NAME,            // name of the pipe
        PIPE_ACCESS_OUTBOUND, // send only
        PIPE_TYPE_BYTE,       // send data as a byte stream
        1,                    // only one instance
        0, 0, 0, NULL);       // default junk
    if (pipe == INVALID_HANDLE_VALUE) panic("could not create pipe 1");

    // spawn child process
    {
        STARTUPINFOA si;
        PROCESS_INFORMATION pi;

        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));
        if (!CreateProcessA(    // using ASCII variant to be compatible with argv
            "cmd.exe",           // executable name (ourself) 
            "/c \"C:\\qhichwa\\flookup.exe -bx C:\\qhichwa\\qhichwa.fst\"",            // command line. This will be seen as argv[0]
            NULL, NULL, FALSE,  // default junk
            CREATE_NEW_CONSOLE, // launch in another console window
            NULL, NULL,         // more junk
            &si, &pi))          // final useless junk
            panic("could not create child process 2");
    }

    // connect to child process
    BOOL result = ConnectNamedPipe(pipe, NULL);
    if (!result) panic("could not connect to child process");

    // talk to child
    for (;;)
    {
        // read an input line
        char line[100];
        printf("Say something >");
        if (fgets(line, sizeof(line), stdin) == NULL)
            panic("could not read from standard input");

        // exit on an empty line
        if (!strcmp(line, "\n")) break;

        // send the line to the child
        DWORD written = 0;
        if (!WriteFile(
            pipe,
            line,         // sent data
            strlen(line), // data length
            &written,     // bytes actually written
            NULL))
            panic("could not write to pipe");
    }

    // close the pipe
    CloseHandle(pipe);
}


void child(void)
{
    printf("Child process starting\n");

    // retrieve communication pipe
    HANDLE pipe = CreateFile(
        PIPE_NAME,      // name of the pipe
        GENERIC_READ,   // read ONLY access (or else the call will fail) 
        0, NULL,        // junk
        OPEN_EXISTING,  // opens existing pipe 
        0, NULL);       // more junk 
    if (pipe == INVALID_HANDLE_VALUE) panic("could not connect to the pipe");

    // read father's input
    for (;;)
    {
        char buffer[80];
        DWORD read = 0;
        if (!ReadFile(
            pipe,
            buffer,           // read data
            sizeof(buffer)-1, // max length (leave room for terminator)
            &read,            // bytes actually read
            NULL))
            break; // exit if the pipe has closed

        // display what our father said
        buffer[read] = '\0'; // make sure what we just read will be displayable as a string
        printf("Father said: %s", buffer);
    }

    // close pipe
    CloseHandle(pipe);
}

int main(int argc, char *argv[])
{
    // wait for a <return> keypress on exit
    atexit(getchar);
    father(argv[0]);
    // decide whether we are the father or the child
    //if (!strcmp(argv[0], "child")) child();
    //else                            father(argv[0]);

    printf("Done\n");
    return 0;
}
Community
  • 1
  • 1
richardtk_1
  • 751
  • 3
  • 11
  • 33
  • What does `GetLastError()` say? "`CreateNamedPipe` - If the function fails, the return value is `INVALID_HANDLE_VALUE`. To get extended error information, call `GetLastError`." – parrowdice May 23 '14 at 13:08
  • I added the line printf("In the child thread: Last Error is %lu\n", GetLastError()); I get the following: Father process starting In the child thread: Last Error is 123 ***PANIC*** could not create pipe – richardtk_1 May 23 '14 at 16:35
  • How do I solved this error? ERROR_INVALID_NAME 123 (0x7B) The filename, directory name, or volume label syntax is incorrect. – richardtk_1 May 23 '14 at 16:42
  • 1
    `ERROR_INVALID_NAME` means the name you provided is not valid. My guess is that a kernel object named `name` already exists in another kernel namespace. Use a more unique name for your pipe. – Remy Lebeau May 23 '14 at 16:50
  • I changed it but the error continuous – richardtk_1 May 23 '14 at 23:00
  • I pasted your code into VS 2013. The pipe creation works for me (which makes me suspec that @RemyLebeau is correct about a name conflict). (The CreateProcess command fails for me with the `ERROR_INVALID_NAME` code, which is not surprising because I don't have that executable on my machine.) – Adrian McCarthy May 25 '14 at 16:50
  • I updated my question to provide more details – richardtk_1 May 26 '14 at 12:01

1 Answers1

7

The problem is located here:

fprintf(stderr, "***PANIC*** %s\n", msg);
printf("In the child thread: Last Error is %lu\n", GetLastError());

This is a standard Windows programming bug, every programmer makes this mistake once. Just once, this is so hard to diagnose that you'll never forget losing the week of your life trying the discover it.

The underlying issue is the way GetLastError() works. It returns the value of an internal global variable, it is stored in the TEB (Thread Environment Block). It has the so common problem with global variables, every call you make to a winapi function is liable to change it, including ones that don't actually fail. Windows itself uses the variable as well. And ERROR_INVALID_NAME is a very popular internal error code.

This is compounded by you not being able to see these winapi calls being made. What is ruining the error code is fprintf(). It is implemented in the CRT with winapi calls. Necessarily so, I/O is an operating system duty.

So what is absolutely essential is that you immediately obtain the error code, before you do anything else. While it is preferable that you pass the value to your panic() function, since it cannot predict what other code runs before it, the quick fix is to rewrite it like this:

int err = GetLastError();
fprintf(stderr, "***PANIC*** %s\n", msg);
printf("In the child thread: Last Error is %lu\n", err);

You'll now get the true error code, the one produced by CreateNamedPipe(). Ought to give you a much better shot at diagnosing the problem. Update your question if you still have a problem interpreting it.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Not exactly sure what I'm supposed to look at. Does look like congratulations are in order, fixing the error reporting seems to have unblocked you. ERROR_FILE_NOT_FOUND is of course a very common error, particularly when you use CreateProcess(). I can't help you find the file back of course. – Hans Passant May 26 '14 at 12:12