The following code gets an error when trying to execute the last line
boost::shared_ptr<boost::asio::io_service> ioServicePtr(new boost::asio::io_service());
//setup the terminal with stdin and stdout
int inFD = ::dup(STDIN_FILENO);
int outFD = ::dup(STDOUT_FILENO);
HANDLE osfhandle = (HANDLE)_get_osfhandle(inFD);//osfhandle is valid
boost::asio::windows::stream_handle inputStream(*ioServicePtr, osfhandle); //error
the error is:
uncaught exception of type N5boost16exception_detail10clone_implINS0_19error_info_injectorINS_6system12system_errorEEEEE
- assign: The parameter is incorrect
Appreciate your input.
#sehe
I tried
hstdhandle = GetStdHandle(STD_OUTPUT_HANDLE);
and got the same error
So then I tried
HANDLE handle=
CreateFile(
"CONIN$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
boost::asio::windows::stream_handle inputStream(*ioServicePtr, handle);
and the error was
-assign handle invalid
You might use GetStdHandle, so:
HANDLE isfhandle = GetStdHandle(STD_INPUT_HANDLE);
However, I don't think consoles support asynchronous IO in windows:
The handle must be to an object that supports overlapped I/O.
If a handle is provided, it has to have been opened for overlapped I/O completion. For example, you must
specify the FILE_FLAG_OVERLAPPED flag when using the CreateFile function to obtain the handle
But further the docs for CreateFile say that CreateFile ignores file flags when creating a handle to a console buffer.
So, you will need to emulate stdin/stdout async IO.
Note that on Linux, asynchronous IO to the standard IO handles is only possible in certain situations anyway - depending on the input/output being redirected: Strange exception throw - assign: Operation not permitted
Related
I've got a pair of windows processes that communicate via named pipes. The server calls CreateNamedPipeW and the client calls CreateFileW to open the same named pipe. Some times this works fine, and then can send messages back and forth. Some times this fails with the error ERROR_PIPE_BUSY on both ends.
I'm pretty sure there is exactly one copy of each of the server and client process. I'm also sure that there is exactly one thread on each end that does the pipe management. i.e. I don't think my problem is that there are multiple producers or consumers.
server:
OVERLAPPED openServerOverlapped;
...
SECURITY_ATTRIBUTES sa;
// ...
server = CreateNamedPipeW(
pipeName.c_str(),
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1,
PIPE_BUFFER_SIZE,
PIPE_BUFFER_SIZE,
NMPWAIT_USE_DEFAULT_WAIT,
&sa
);
if (server != INVALID_HANDLE_VALUE) {
auto lastError = ConnectNamedPipe(server, &openServerOverlapped) == FALSE
? GetLastError()
: ERROR_PIPE_CONNECTED;
if (lastError == ERROR_IO_PENDING) {
DWORD bytesTransferred = 0;
lastError = GetOverlappedResultEx(
server, &openServerOverlapped, &bytesTransferred,
CLIENT_CONNECT_TIMEOUT, FALSE
) == FALSE
? GetLastError()
: ERROR_PIPE_CONNECTED;
}
if (lastError == ERROR_PIPE_CONNECTED) {
// start reading messages
} else {
// error handling, looks like "ConnectNamedPipe error..."
}
} else {
// error handling, looks like "CreateNamedPipeW error..."
}
We sometimes get errors like the following
got error: CreateNamedPipeW error: LastError=000000e7, All pipe instances are busy.
e7 is ERROR_PIPE_BUSY, which matches the erorr message we got from FormatMessage
When this is happening we get similar errors out of our client. Client is actually c#, but uses marshalling to call the same win32 APIs.
client:
while (true) {
// ...
pipeHandle = CreateFileW(fileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
IntPtr.Zero
);
if (pipeHandle.ToInt32() == INVALID_HANDLE_VALUE) {
// error handling, looks like "Failed to create pipe client..."
Thread.Sleep(5000);
continue;
}
// ...
}
We get logging like:
Failed to create pipe client, win32 error: 231
231 = e7, so same error: ERROR_PIPE_BUSY
According to the documentation:
Named Pipe Client
A named pipe client uses the CreateFile function to open a handle to a named pipe. If the pipe exists but all of its instances are busy, CreateFile returns INVALID_HANDLE_VALUE and the GetLastError function returns ERROR_PIPE_BUSY.
The reason for the error is that all of its instances are busy.
I suggest you try to use the CreateNamedPipe() function to create another instance of a named pipe. And also try to use the DisconnectNamedPipe function to disconnect the server end of a named pipe instance from a client process, and then you can connect that instance to another client by using the ConnectNamedPipe() function.
I suggest you refer to the example: Multithreaded Pipe Server
I know lots of similar questions on this topic have been asked before but so far I have been unable to find a solution that actually works. I want to start a console program from my program and capture its output. My implementation should be in a way that is compatible with WaitForMultipleObjects(), i.e. I want to get notified whenever there is new data to read in the pipe.
My implementation is based on this example from MSDN. However, I had to modify it a little because I need overlapped I/O in order to be able to wait for ReadFile() to finish. So I'm using named pipes created using Dave Hart's MyCreatePipeEx() function from here.
This is my actual code. I have removed error checks for readability reasons.
HANDLE hReadEvent;
HANDLE hStdIn_Rd, hStdIn_Wr;
HANDLE hStdOut_Rd, hStdOut_Wr;
SECURITY_ATTRIBUTES saAttr;
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
OVERLAPPED ovl;
HANDLE hEvt[2];
DWORD mask, gotbytes;
BYTE buf[4097];
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
MyCreatePipeEx(&hStdOut_Rd, &hStdOut_Wr, &saAttr, 0, FILE_FLAG_OVERLAPPED, FILE_FLAG_OVERLAPPED);
MyCreatePipeEx(&hStdIn_Rd, &hStdIn_Wr, &saAttr, 0, FILE_FLAG_OVERLAPPED, FILE_FLAG_OVERLAPPED);
SetHandleInformation(hStdOut_Rd, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation(hStdIn_Wr, HANDLE_FLAG_INHERIT, 0);
memset(&piProcInfo, 0, sizeof(PROCESS_INFORMATION));
memset(&siStartInfo, 0, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = hStdOut_Wr;
siStartInfo.hStdOutput = hStdOut_Wr;
siStartInfo.hStdInput = hStdIn_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess(NULL, "test.exe", NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo);
hReadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
for(;;) {
int i = 0;
hEvt[i++] = piProcInfo.hProcess;
memset(&ovl, 0, sizeof(OVERLAPPED));
ovl.hEvent = hReadEvent;
if(!ReadFile(hStdOut_Rd, buf, 4096, &gotbytes, &ovl)) {
if(GetLastError() == ERROR_IO_PENDING) hEvt[i++] = hReadEvent;
} else {
buf[gotbytes] = 0;
printf("%s", buf);
}
mask = WaitForMultipleObjects(i, hEvt, FALSE, INFINITE);
if(mask == WAIT_OBJECT_0 + 1) {
if(GetOverlappedResult(hStdOut_Rd, &ovl, &gotbytes, FALSE)) {
buf[gotbytes] = 0;
printf("%s", buf);
}
} else if(mask == WAIT_OBJECT_0) {
break;
}
}
The problem with this code is the following: As you can see, I'm reading in chunks of 4kb using ReadFile() because I obviously don't know how much data the external program test.exe will output. Doing it this way was suggested here:
To read a variable amount of data from the client process just issue
read requests of whatever size you find convenient and be prepared to
handle read events that are shorter than you requested. Don't
interpret a short but non-zero length as EOF. Keep issuing read
requests until you get a zero length read or an error.
However, this doesn't work. The event object passed to ReadFile() as part of the OVERLAPPED structure will only trigger once there are 4kb in the buffer. If the external program just prints "Hello", the event won't trigger at all. There need to be 4kb in the buffer for hReadEvent to actually trigger.
So I thought I should read byte by byte instead and modified my program to use ReadFile() like this:
if(!ReadFile(hStdOut_Rd, buf, 1, &gotbytes, &ovl)) {
However, this doesn't work either. If I do it like this, the read event is not triggered at all which is really confusing me. When using 4096 bytes, the event does indeed trigger as soon as there are 4096 bytes in the pipe, but when using 1 byte it doesn't work at all.
So how am I supposed to solve this? I'm pretty much out of ideas here. Is there no way to have the ReadFile() event trigger whenever there is some new data in the pipe? Can't be that difficult, can it?
Just for the record, while there are some problems with my code (see discussion in comments below the OP), the general problem is that it's not really possible to capture the output of arbitrary external programs because they will typically use block buffering when their output is redirected to a pipe, which means that output will only arrive at the capturing program once that buffer is flushed so real time capturing is not really possible.
Some workarounds have been suggested though:
1) (Windows) Here is a workaround that uses GetConsoleScreenBuffer() to capture the output from arbitrary console programs but it currently only supports one console page of output.
2) (Linux) On Linux, it's apparently possible to use pseudo-terminals to force the external program to use unbuffered output. Here is an example.
My code opens a virtual NIC device using CreateFile. After that I am calling SetHandleInformation on the handle returned by CreateFile to avoid leaking the handle to child processes. The problem is, SetHandleInformation fails with error code 5 (ERROR_ACCESS_DENIED).
Following is the piece of code where I am opening the device and calling SetHandleInformation:
handle = CreateFile(dev_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,NULL);
if (handle != INVALID_HANDLE_VALUE) {
if (!(SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0))) {
printf("SetHandleInformation error, code: %u\n", GetLastError());
}
}
I am observing this failure on Windows 10. My application is running with Administrator privileges. I am able to successfully use the handle for read and write even after this failure, which indicates that CreateFile is working fine.
What could be the possible reason of this failure? I could not find much information on SetHandleInformation failure with error code 5.
Under Linux, my program would do something like this:
Process 1 opens a file (e.g. by mapping it into memory). Let's call this file#1
Process 2 unlinks the file, and creates a new file with the same name. Let's call this file#2.
Process 1 continues to work with file#1. When it is closed, it is deleted (since it has no links). Process 1 continues to work with the content in file#1, and does not see content from file#2.
When both processes have exited, file#2 remains on disk.
I want to achieve the same semantics in Windows. After reading this question, I think FILE_SHARE_DELETE does basically this. Is opening the file with FILE_SHARE_DELETE enough, or do I need to consider something more?
The above execution flow is just an example, I know there are other ways of solving that exact problem in Windows, but I want to understand how to make such code portable between Windows and Linux.
Edit: to clarify: The use cases would be to reuse a filename for different unrelated files, but let existing processes keep their data (think transactional update of a config file for example), and to make a file anonymous (unnamed), but continue to use it like an anonymous memory map. Again I know both are possible on Windows through other means, but I am trying to find a way that is portable across platforms.
You can achieve this by using a combination of CreateFile, CreateFileMapping and MapViewOfFile calls. MapViewOfFile will give you a memory-mapped buffer of the file backed by the file on disk.
Following code when executed from different processes, will write the process id of last closing process in the file at c:\temp\temp.txt
int main()
{
TCHAR szMsg[256];
HANDLE hMapFile;
LPCTSTR pBuf;
HANDLE hFile = CreateFileW(
L"C:\\Temp\\temp.txt",
GENERIC_WRITE|GENERIC_READ,
FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,NULL);
hMapFile = CreateFileMapping(
hFile, // Handle of file opened with rw access
NULL, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
BUF_SIZE, // maximum object size (low-order DWORD)
szName); // name of mapping object
if (hMapFile == NULL)
{
printf( "Could not create file mapping object (%d).\n", GetLastError());
return 1;
}
pBuf = (LPTSTR) MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
BUF_SIZE);
if (pBuf == NULL)
{
printf("Could not map view of file (%d).\n", GetLastError());
CloseHandle(hMapFile);
return 1;
}
wsprintfW(szMsg, L"This is process id %d", GetCurrentProcessId());
CopyMemory((PVOID)pBuf, szMsg, (wcslen(szMsg) * sizeof(TCHAR)));
MessageBoxW(NULL, szMsg, L"Check", MB_OK);
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
CloseHandle(hFile);
return 0;
}
Make sure you open the file with GENERIC_READ|GENERIC_WRITE access and allow FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE access to subsequent opens.
Also note the use of CREATE_ALWAYS in CreateFile which will delete the old file and open a new one every-time CreateFile is called. This is the 'unlink' effect you talk about.
Code inspired from Creating Named Shared Memory at msdn.
I am trying to get access to a file descriptor which receives input from the console. I am currently using
HANDLE fd = CreateFile(
"CONIN$",
GENERIC_READ | GENERIC_WRITE,
TRUE,
0,
OPEN_EXISTING,
0,
0);
SetConsoleMode(fd, ENABLE_WINDOW_INPUT);
And returning the fd to a program that reads (based on libuv) the input from the console.
This works fine when the process is executed in the console, but reading from the fd crashes when I pipe input into the program
echo hello | inputProgram
I have a suspicion that there is no console associated with the input process, but I'm not certain. How do I properly read the input into the cmd window when executing in this way?
So I a am binding to this C++ program in Node.js. I call
var ReadStream = require("tty").ReadStream();
var TTY = process.binding("tty_wrap").TTY;
module.exports = function () {
var opentty = require("./bin/opentty.node") // program returns the fd int
var fd = opentty();
var t = new _TTY(fd, true);
return new ReadStream(t);
}
opentty returns 3 in redirected input mode for the file handle. The code that deals with this file handle can be found here
https://github.com/joyent/node/blob/master/src/tty_wrap.cc#L185
which essentially calls into uv_tty_init found here
https://github.com/joyent/node/blob/master/deps/uv/src/win/tty.c#L99
The stream errors with Error: read EBADF, syscall: read
Looking through the Node repository it seems clear that new _TTY(fd, true) is expecting a C file descriptor, but you're passing it a Win32 handle.
The _open_osfhandle function creates a file descriptor from a handle.
So, you should try
var t = new _TTY(_open_osfhandle(fd), true);
(as discussed in the comments, this will only work if you're sharing the C runtime with libuv.)
Ideally you would use libuv's open function, but unfortunately there's a bug in fs__open:
case _O_RDWR:
access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
This is where it decides which access permissions to request. FILE_GENERIC_WRITE and FILE_GENERIC_READ are, as the names suggest, specific to files, and can't be used to open CONIN$. It should be
case _O_RDWR:
access = GENERIC_READ | GENERIC_WRITE;
which will work for both files and other types of objects such as the console input and output. (I've reproduced this in a simple C program; on my system, using the FILE_* permissions definitely prevents you from opening CONIN$.)