DuplicateHandle in WINAPI returns ERROR_ACCESS_DENIED - winapi

I have two anonymous pipe handles. I want to pass one of them to a child process.
It works correctly if I call DuplicateHandle to make the handle inheritable for a write handle of the pipe like:
DuplicateHandle(myHandle, fdCP[1], myHandle, &fdCP[1], DUPLICATE_SAME_ACCESS, 1, DUPLICATE_CLOSE_SOURCE);
However when doing it for a read handle of another pipe I get a 0x00000000 value in the result handle.
GetLastError in this case is 5 (ERROR_ACCESS_DENIED). I tried to provide SECURITY_ATTRIBUTES of GENERIC_ALL|SPECIFIC_RIGHTS_ALL when created the pipe. However it didn't help.
I noted that DuplicateHandle works as expected if called in on the read handle as follows:
DuplicateHandle(myHandle, fdPC[0], myHandle, &fdPC[0], 0, 1, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
In both cases myHandle is GetCurrentProcess().
So the question is this an error in WINAPI? And is this a correct workaround?

Related

Windows DuplicateHandle named pipe handle strange error 183 "file already exists"

I have a problem with DuplicateHandle (Win32). I try to duplicate a named pipe handle and I always get the Error 183 "file already exists". I do not understand this error message, because I try to create a copy of a file handle and the new file handle does not exist before. (Is there a start value required to overwrite?) This is my call:
return DuplicateHandle (MeshellProcessHandle, sourcehandle, HelperProcess, targethandle, 0, TRUE, DUPLICATE_SAME_ACCESS) != 0;
To understand what I am doing, I have to explain more extensively: I am working on a convenient editor frontend for the command line program cmd.exe. This project already works fine on the OS/2 Operating System which is very familiar with Win32, because from a historical point of view, the two OS were developed together until one year before finishing, where Microsoft and IBM went different ways.
The implementation of this program was quite tricky: There's a windowed front end editor program. This program creates named pipes for stderr, stdout and stderr, but from the reverse point of view (output from cmd.exe is input for the editor). Because of limited communication between different sessions, I had to program a "cmd helper program" which is a tiny commandline program holding several API calls and running in the same session as the cmd.exe program. The helper gets the editor process ID via commandline parameter and opens the existing pipes created by the windowed editor program and then redirects stdin/stdout/stderr to the pipes. The helper gets the process handle of the editor from the editor process ID via "OpenProcess" API call. Then the helper executes cmd.exe which automatically inherits the stdin/stdout/stderr handles and now cmd.exe writes to and reads from the pipe.
Another option would be to parse the full pipe names to cmd.exe without using DuplicateHandle, but I would prefer to be as close as to my solution which already works fine on the OS/2 Operating System.
I am still not sure why I have no access rights to duplicate the pipe handles. But I have found another solution: My helper console program starts the child process (cmd.exe) and within this child process, I want to use the named pipes instead of stdin/stdout/stderr - this is the reason why I want to use DuplicateHandle. Windows offers a convenient solution when starting the child process by using
CreateProcess (...)
With CreateProcess, you have always to hold parameters in the STARTUPINFO structure. And there are three handle variables you can set to redirect stdin/stdout/stderr to the three named pipes cmd_std*:
STARTUPINFO StartupInfo;
HFILE cmd_stdout, cmd_stdin, cmd_stderr;
//Open the existing pipes with CreateFile
//Start child process program
StartupInfo.hStdOutput = &cmd_stdout;
StartupInfo.hStdInput = &cmd_stdin;
StartupInfo.hStdError = &cmd_stderr;
CreateProcess (..., &StartupInfo, ...);
This solution has much less code than the variant with DuplicateHandle, because I also have to save and to restore the original file handles, so this way replaces 9 DuplicateHandle calls.
I did program the changes now but my new code described above does not work. If I set the "handle inheritance flag" in CreateProcess to TRUE, cmd.exe does not get executed, but CreateProcess returns TRUE (=OK). Here's my detailed code:
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInformation;
HFILE cmd_stdout, cmd_stdin, cmd_stderr;
char *pprogstr, *pargstr;
//Open the existing pipes with CreateFile
//Start child process program cmd.exe
StartupInfo.hStdOutput = &cmd_stdout;
StartupInfo.hStdInput = &cmd_stdin;
StartupInfo.hStdError = &cmd_stderr;
StartupInfo.dwFlags = STARTF_USESTDHANDLES;
pprogstr = "C:\\WINDOWS\\system32\\cmd.exe";
pargstr = "/K";
CreateProcess (
pprogstr, // pointer to name of executable module
pargstr, // pointer to command line string
NULL, // pointer to process security attributes
NULL, // pointer to thread security attributes
TRUE, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
NULL, // pointer to current directory name
&StartupInfo, // pointer to STARTUPINFO
&ProcessInformation) // pointer to PROCESS_INFORMATION
Any idea?

Is dialogue possible through pipes between mother and child process on Windows?

I use CreateProcess and CreatePipe to spawn a child process and set up pipes between mother and child to communicate through. Then I use WriteFile to write to the write handle of the child's input pipe and ReadFile to read from the read handle of the child's output pipe. After having finished writing to the child I do CloseHandle on the write handle of the input pipe.
This all works well. However, I don't want it to work like this. I want to feed one line to the child, have the child compute something and output the results as a line of output, and then read that line of output from the mother. Then feed another line of input to the child and so on.
Unfortunately, when I skip the CloseHandle function call the two processes hang and nothing happens. So how can I reuse the pipes and avoid closing them? If I close them I have to create the child process again, right? That's a heavy operation, I suppose, and I really want to avoid that. Is there a good solution using pipes? I want the child process to run indefinitely and the communication to be a dialogue, alternating between writes and reads.
I solved it by using Windows kernel ReadFile and WriteFile instead of standard C functions in the child code. Here is the child code:
HANDLE inp = (HANDLE)_get_osfhandle(0);
HANDLE out = (HANDLE)_get_osfhandle(1);
char buffer[0x400];
unsigned long N;
while (ReadFile(inp, buffer, sizeof(buffer), &N, NULL) && N > 0)
{
WriteFile(out, buffer, N, &N, NULL);
}
And here is the mother code:
process app("child.exe");
app.write(string("hello\n"));
app.read().print();
app.write(string("world\n"));
app.read().print();
It prints:
hello
world

Reading pipe asynchronously using ReadFile

I think I need some clarification on how to read from a named pipe and have it return immediately, data or not. What I am seeing is ReadFile fails, as expected, but GetLastError returns either ERROR_IO_PENDING or ERROR_PIPE_NOT_CONNECTED, and it does this until my surrounding code times out. I get these errors EVEN THOUGH THE DATA HAS IN FACT ARRIVED. I know this by checking my read buffer and seeing what I expect. And the pipe keeps working. I suspect I am not using the overlapped structure correctly, I'm just setting all fields to zero. My code looks like this:
gPipe = CreateFile(gPipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
pMode = PIPE_READMODE_MESSAGE;
bret = SetNamedPipeHandleState(gPipe, &pMode, NULL, NULL);
OVERLAPPED ol;
memset(&ol, 0, sizeof(OVERLAPPED));
// the following inside a loop that times out after a period
bret = ReadFile(gPipe, &tmostat, sizeof(TMO64STAT), NULL, &ol);
if (bret) break;
err = GetLastError();
// seeing err == ERROR_IO_PENDING or ERROR_PIPE_NOT_CONNECTED
So I can do what I want by ignoring the errors and checking for arrived data, but it troubles me. Any idea why I am getting this behavior?
Windows OVERLAPPED I/O doesn't work like the non-blocking flag on other OSes (For example on Linux, the closest equivalent is aio_*() API, not FIONBIO)
With OVERLAPPED I/O, the operation hasn't failed, it proceeds in the background. But you are never checking on it... you just try again. There's a queue of pending operations, you're always starting new ones, never checking on the old ones.
Fill in the hEvent field in the OVERLAPPED structure, and use it to detect when the operation completes. Then call GetOverlappedResult() to get the number of bytes actually transferred.
Another important note -- the OS owns the OVERLAPPED structure and the buffer until the operation completes, you must take care to make sure these stay valid and not deallocate them or use them for any other operation until you confirm that the first operation completed.
Note that there is an actual non-blocking mode for Win32 pipes, but Microsoft strongly recommends against using it:
The nonblocking-wait mode is supported for compatibility with Microsoft LAN Manager version 2.0. This mode should not be used to achieve overlapped input and output (I/O) with named pipes. Overlapped I/O should be used instead, because it enables time-consuming operations to run in the background after the function returns.
Named Pipe Type, Read, and Wait Modes

CreateFile Returns negative handle

Any ideas why the createfile() function would be returning -1.
Handle = CreateFile(filename, &H80000000, 0, 0, 3, &H80, 0)
This is run a few times. I was thinking perhaps maybe the file is not being closed properly?
EDIT
Err.LastllError returns 32.
You are probably right about not closing the file someplace. I would start by looking where I am opening the file and making sure I have an error handling routine in place. In the error handler I would check the value of "Handle" and if it's valid call CloseHandle(Handle). Also, since you are opening the file for read access, you could change you dwShareMode parameter to 1 to allow subsequent open for read operations on the same file.
Error 32 is ERROR_SHARING_VIOLATION (reference) which means some other process still has the file open.

win32 api for Process.BeginOutputReadLine

i wanted to know the c++ equivalent of c#'s Process.BeginOutputReadLine, where i aynchronously read from the standardoutput of another process. Is there any API for it?
To read the standard output of a process you need to assign an appropriate handle to an instance of STARTUPINFO passed to CreateProcess. Remember to include the STARTF_USESTDHANDLES flag.
Usually an anonymous pipe is used, created via CreatePipe.
See "Creating a Child Process with Redirected Input and Output" for an example.
You can use the normal Win32 approaches (OVERLAPPED + event, IOCompleteion Port,...) to reading the output handle asynchronously.

Resources