I am trying to redirect the output of a child process and return a FILE* to the parent.
I am essentially following the code example at Creating a Child Process with Redirected Input and Output. The only modification is that i encapsulated the whole thing in a function and do
return _fdopen(_open_osfhandle((intptr_t)g_hChildStd_OUT_Rd, _O_RDONLY), "rb");
The problem is that I want to cleanup and fclose is throwing an error. Was I supposed to close handle after I did the _fdopen? How am I supposed to clean up here?
The correct way to close a file stream opened with _fdopen is to call fclose. If that's not working for you, then you have other problems.
Do not close the file descriptor after calling _fdopen. The documentation doesn't exactly say, but the FILE object owns that file descriptor and will close it when you call fclose. Likewise, the file descriptor owns the file handle, so you shouldn't call CloseHandle, either.
May be quite late to answer, but just adding for reference. I looked into call stack of fclose, and it is actually making a call to CloseHandle
auto NThdl = CreateFileW(L"D:\\s.txt", GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (NThdl != INVALID_HANDLE_VALUE)
{
int iohdl = _open_osfhandle((intptr_t) NThdl, O_RDWR | O_BINARY);
if (iohdl != 0xFFFFFFFF)
{
FILE *hLstFile = _wfdopen(iohdl, L"w+bc");
fwrite("Bogus", 5, 1, hLstFile);
fclose(hLstFile);
// Exception
CloseHandle(NThdl);
}
}
And attempt to call CloseHandle after fclose would cause an exception saying that Handle is invalid.
Related
So, I am trying to Copy a File after locked it! But I got the GetLastError() = 32 - "The process cannot access the file because it is being used by another process."
By order, Is the same process using the file because it was locked first. I am working with multi-process application and using LockFileEx exclude the other process handle the equal file information . Besides, I have been reading the LockFileEx documentation and did not find something related to impossibility to CopyFile after lock it.
HANDLE cfile;
bool alreadyExistFile = FALSE;
OVERLAPPED sOverlapped;
sOverlapped.Offset = 1;
sOverlapped.OffsetHigh = 0;
cfile = CreateFile(TEXT("CounterSeedAssincrono.csv.csv"),
GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
LockFileEx(cfile, LOCKFILE_EXCLUSIVE_LOCK |
LOCKFILE_FAIL_IMMEDIATELY, 0, 10000, 0, &sOverlapped);
CopyFile(TEXT("CounterSeedAssincrono.csv"),
TEXT("CounterSeedAssincrono_A.csv"), alreadyExistFile);
if (alreadyExistFile == FALSE)
cout << "CopyFile Failed -> " << GetLastError() << endl;
UnlockFileEx(cfile, 0, 10000, 0, &sOverlapped);
CloseHandle(cfile);
Someone know if it is possible to do what i am trying? I am using Windows and VS 2015.
You call CreateFile passing 0 as dwShareMode flags therefore blocking all read and write access to it until this file handle is closed. And LockFileEx is not really necessary.
PS cfile is left uninitialized, did you mean cfile = CreateFile(...? Also GetLastError must be called immediately after failed call, otherwise the value returned might be altered. And you don't check result of LockFileEx and other methods at all.
I'm trying to monitor file changes but I am not really sure on how to read the filename in the FILE_NOTIFY_INFORMATION struct:
HANDLE dwChangeHandles[2];
DWORD dwWaitStatus;
wChangeHandles[0] = FindFirstChangeNotification(dirname.c_str(), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
if (dwChangeHandles[0] == INVALID_HANDLE_VALUE) printerr(__FILE__,__LINE__,"FindFirstChangeNotification function failed.\n");
...
if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL)) //final validation
printerr(__FILE__,__LINE__,"Unexpected NULL from FindFirstChangeNotification.\n");
while (TRUE) {
std::cout << "Waiting for notification...\n";
dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles, FALSE, INFINITE);
if(dwWaitStatus==WAIT_OBJECT_0){
std::cout << "Something changed\n";
DWORD BytesReturned;
size_t bufLen = 1024;
FILE_NOTIFY_INFORMATION buffer[bufLen];
if (ReadDirectoryChangesW(dwChangeHandles[0], buffer, bufLen, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, &BytesReturned, NULL, NULL)){
std::wcout << std::wstring(buffer->FileName)<< std::endl; //THERE IS NOTHING IN THE EXPECTED OUTPUT HERE
}
if (FindNextChangeNotification(dwChangeHandles[0]) == FALSE ) printerr(__FILE__,__LINE__,"FindNextChangeNotification function failed.\n");
}
else if(dwWaitStatus==WAIT_TIMEOUT) printerr(__FILE__,__LINE__,"No changes in the timeout period.\n");
else printerr(__FILE__,__LINE__,"Unhandled dwWaitStatus.\n");
}
Is there something I am doing wrong
You have a number of problems that I can see immediately:
According to the docs for the ReadDirectoryChangesW function, the buffer needs to be DWORD-aligned. As you are using a buffer on the stack this isn't guaranteed - you should allocate one from the heap instead.
You don't seem to be using the function correctly. Normally you would call ReadDirectoryChangesW first, and then wait on the event. Not the other way around. When ReadDirectoryChangesW returns for an asynchronous call there is usually no data in the buffer at that point. You need to wait for notification that the request has been completed before using the buffer contents.
FindNextChangeNotification is only used with FindFirstChangeNotification, so this is completely wrong. When the ReadDirectoryChangesW completes you need to use the NextEntryOffset field in the FILE_NOTIFY_INFORMATION structure to loop through the returned events.
Edit: Since you've added more code to your question it's now obvious that you are mixing the two APIs. FindFirstChangeNotification and FindNextChangeNotification are one API, and ReadDirectoryChangesW is another. I believe you've been confused by this passage in the docs:
This function does not indicate the change that satisfied the wait
condition. To retrieve information about the specific change as part
of the notification, use the ReadDirectoryChangesW function.
I guess your confusion is understandable, but the two APIs can't be used together. If you're using FindFirstChangeNotification then all you get is a notification that something changed, and you have to re-read the directory to find out what it was. If you want specific notifications at the file level then you have to use ReadDirectoryChangesW to do the monitoring.
In Unix, if you have a file descriptor (e.g. from a socket, pipe, or inherited from your parent process), you can open a buffered I/O FILE* stream on it with fdopen(3).
Is there an equivalent on Windows for HANDLEs? If you have a HANDLE that was inherited from your parent process (different from stdin, stdout, or stderr) or a pipe from CreatePipe, is it possible to get a buffered FILE* stream from it? MSDN does document _fdopen, but that works with integer file descriptors returned by _open, not generic HANDLEs.
Unfortunately, HANDLEs are completely different beasts from FILE*s and file descriptors. The CRT ultimately handles files in terms of HANDLEs and associates those HANDLEs to a file descriptor. Those file descriptors in turn backs the structure pointer by FILE*.
Fortunately, there is a section on this MSDN page that describes functions that "provide a way to change the representation of the file between a FILE structure, a file descriptor, and a Win32 file handle":
_fdopen, _wfdopen: Associates a stream with a file that was
previously opened for low-level I/O and returns a pointer to the open
stream.
_fileno: Gets the file descriptor associated with a stream.
_get_osfhandle: Return operating-system file handle associated
with existing C run-time file descriptor
_open_osfhandle: Associates C run-time file descriptor with an
existing operating-system file handle.
Looks like what you need is _open_osfhandle followed by _fdopen to obtain a FILE* from a HANDLE.
Here's an example involving HANDLEs obtained from CreateFile(). When I tested it, it shows the first 255 characters of the file "test.txt" and appends " --- Hello World! --- " at the end of the file:
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <cstdio>
int main()
{
HANDLE h = CreateFile("test.txt", GENERIC_READ | GENERIC_WRITE, 0, 0,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if(h != INVALID_HANDLE_VALUE)
{
int fd = _open_osfhandle((intptr_t)h, _O_APPEND | _O_RDONLY);
if(fd != -1)
{
FILE* f = _fdopen(fd, "a+");
if(f != 0)
{
char rbuffer[256];
memset(rbuffer, 0, 256);
fread(rbuffer, 1, 255, f);
printf("read: %s\n", rbuffer);
fseek(f, 0, SEEK_CUR); // Switch from read to write
const char* wbuffer = " --- Hello World! --- \n";
fwrite(wbuffer, 1, strlen(wbuffer), f);
fclose(f); // Also calls _close()
}
else
{
_close(fd); // Also calls CloseHandle()
}
}
else
{
CloseHandle(h);
}
}
}
This should work for pipes as well.
Here is a more elegant way of doing this instead of CreateFile: specify "N" in fopen(). It's a Microsoft-specific extension to fopen, but since this code is platform-specific anyway, it's ok. When called with "N", fopen adds _O_NOINHERIT flag when calling _open internally.
Based on this:
Windows C Run-Time _close(fd) not closing file
I'm trying to read from stderr of a child process. The data is lines of text created with sprintf(stderr, "some debug info\n"). I'm using ReadFileEx with a completion routine. I don't know how many lines of text or how long each line will be. So, what do I put as the nNumberOfBytesToRead parameter?
My guess is I put the max size of my buffer, which I will make 4k; although I don't know if that's an optimal size. I'm guessing that if the line written to stderr is shorter than 4k, the completion routine won't fire. I'm guessing that when the 4k is reached but more data remains, I have to fire off another ReadFileEx within the completion routine. I'll know this is the case because GetLastError will return ERROR_MORE_DATA. I'm hoping that I get a call when the buffer isn't full, but the child process has exited. I'm not sure I get a completion callback when the child process exits, because I passed the stderr write handle to the child when I created it; maybe I get the callback when I close that handle. Are there any race conditions when the child closes wrt to my reading stderr?
Here is the psuedo code of how the process and handles are created:
Attr.bInheritHandle = true
CreatePipe(&hr, &hw, &Attr, 0) and SetHandleInformation(hX, HANDLE_FLAG_INHERIT) on hX the child uses.
Si.hStdXXX = handles from CreatePipe that child uses
CreateProcess(inherit=true, &Si)
Details (Tx extension is a wrapper that throws errors):
HANDLE Create() {
STARTUPINFO SI, *pSI = NULL;
bool fInherit = m_fInherit;
if (m_fStdOut || m_fStdIn || m_fStdErr) {
fInherit = true;
SECURITY_ATTRIBUTES Attr;
Attr.nLength = sizeof(SECURITY_ATTRIBUTES);
Attr.bInheritHandle = TRUE;
Attr.lpSecurityDescriptor = NULL;
if (m_fStdOut) // Create a pipe for the child process's STDOUT. The child will use the write.
CHandle::CreatePipe(m_hStdOutR, m_hStdOutW, &Attr, CP_INHERIT_WRITE);
if (m_fStdErr) // Create a pipe for the child process's STDERR. The child will use the write.
CHandle::CreatePipe(m_hStdErrR, m_hStdErrW, &Attr, CP_INHERIT_WRITE);
if (m_fStdIn) // Create a pipe for the child process's STDIN. The child will use the read.
CHandle::CreatePipe(m_hStdInR, m_hStdInW, &Attr, CP_INHERIT_READ);
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
ZeroStruct(SI);
SI.cb = sizeof(STARTUPINFO);
SI.hStdError = m_hStdErrW, SI.hStdOutput = m_hStdOutW, SI.hStdInput = m_hStdInR;
SI.dwFlags |= STARTF_USESTDHANDLES;
pSI = &SI;
}
// m_fCpu, m_fNuma are masks to set affinity to cpus or numas
CreateProcessTx(NULL, m_szCmdLine, fInherit, m_fFlags, pSI, &m_pi, m_fCpu, m_fNuma, 5);
m_hProc = m_pi.hProcess;
m_hThread = m_pi.hThread;
if (!m_fThread)
m_hThread.Close();
return m_hProc;
}
static void CreatePipe(CHandle &hRead, CHandle &hWrite, SECURITY_ATTRIBUTES* pAttr, BYTE fInheritMask) {
HANDLE hReadTmp = NULL, hWriteTmp = NULL;
CreatePipeTx(hReadTmp, hWriteTmp, pAttr);
SetHandleInformation(hReadTmp, HANDLE_FLAG_INHERIT, (fInheritMask&CP_INHERIT_READ) ? HANDLE_FLAG_INHERIT : 0);
SetHandleInformation(hWriteTmp, HANDLE_FLAG_INHERIT, (fInheritMask&CP_INHERIT_WRITE) ? HANDLE_FLAG_INHERIT : 0);
hRead = hReadTmp;
hWrite = hWriteTmp;
}
Anonymous pipes created with CreatePipe can't used asynchronously. From the Windows SDK documentation:
Asynchronous (overlapped) read and write operations are not supported by anonymous pipes.
This means that you cannot use the ReadFileEx and WriteFileEx functions with anonymous pipes. >In addition, the lpOverlapped parameter of ReadFile and WriteFile is ignored when these >functions are used with anonymous pipes.
Basically CreatePipe doesn't accept a FILE_FLAG_OVERLAPPED flag, and asynchronous I/O requires that you use the flag when creating the file handle.
You'll have to use CreateNamedPipe to create named pipes. The question Overlapped I/O on anonymous pipe has answer with a link to a replacement function MyCreatePipeEx you can use.
Your completion port should receive a zero length read event after attempting to read from a pipe that has been closed on the other end.
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.
Also WaitForMultipleObjects won't work with completion routines, as they're only called while the thread is in an alterable state. Use WaitForMultipleObjectEx with the bAlertable argument set to to true. This function will return WAIT_IO_COMPLETION after running one or more completion routines. In that case you'll probably want to immediately call WaitForMultipleObjectEx again.
I have this
static std::string exec(char* cmd) {
FILE* pipe = _popen(cmd, "r");
if (!pipe) return "ERROR -22";
char buffer[128];
std::string result = "";
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
_pclose(pipe);
return result;
}
But the problem i have is that i want to hide the program that lunches how can I do that? thx
As Hans Passant mentioned in the comments, you have to use CreateProcess to spawn the child process instead of _popen, since _popen does not give you any control over the window creation process.
To hide the console window, use the CREATE_NO_WINDOW process creation flag for the dwCreationFlags parameter.
In order to capture the output of the process, you need to create a pipe for its standard output stream with CreatePipe. Assign that pipe handle to the hStdOutput member of the STARTUPINFO structure you pass in, and make sure to set the STARTF_USESTDHANDLES flag in the startup info's dwFlags so it knows that that member is valid. Then, to read data, you just use ReadFile on the pipe handle.
Hans also provided a link to a good example of creating pipes with a child process here, although that example is doing more than you need to do—it's creating pipes for all three streams (stdin, stdout, and stderr), whereas you only need to capture stdout.