I've successfully made an handle that gets the output from an external program and then exports out to a file. I want to do this with an stringstream or equivalent instead. Here's a code snippet to show what I want to do
//std::string OUTPATH = _FilePath + L"out";
std::string filestream{};
//HANDLE h = CreateFileA(LuaBuffer.data(),
// FILE_APPEND_DATA,
// FILE_SHARE_WRITE | FILE_SHARE_READ,
// &sa,
// CREATE_ALWAYS,
// FILE_ATTRIBUTE_NORMAL,
// NULL);
si.hStdOutput = filestream.data();
si.dwFlags |= STARTF_USESTDHANDLES;
If this is impossible, then what is the fastest approach to getting an output from an external console program? Many thanks.
You cannot use a std::string/stream with the STARTUPINFO::hStdOut field. What you CAN do is create a pipe via CreatePipe() instead, and then your app can read from the pipe and append the data to your std::string/stream.
See MSDN's documentation for an example of using CreatePipe() with CreateProcess() to capture a child process's output.
Creating a Child Process with Redirected Input and Output
Simply change the code to write the captured output to your std::string/stream instead of to the parent process's stdout.
Related
What I would like to do is use MiniDumpWriteDump() write to a named pipe and then read/write it myself. I am able to perform the dump successfully if I write the contents to a file directly. However, while writing to the named pipe has been successful the subsequent read/write operation does not go so well. I can read all the data out of the pipe but then when it's written the DMP file appears to be corrupted.
Here is the ReadFile() logic:
while (ReadFile(hInboundPipe, &vecBuffer[dwOffset], vecBuffer.size() - dwOffset, &dwRead, NULL)) {
dwOffset += dwRead;
while (dwOffset >= vecBuffer.size()) {
vecBuffer.resize(vecBuffer.size() + iBuffer * sizeof(char));
}
}
Here is the WriteFile() logic:
HANDLE hDumpFile = CreateFileW(L"C:\\test.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(hDumpFile , &vecBuffer[0], dwOffset, &dwOutBytes, NULL);
CloseHandle(hDumpFile);
I'm not certain if it's applicable to the root cause but here is the named pipe setup:
HANDLE hInboundPipe = CreateNamedPipe(
szPipeName,
PIPE_ACCESS_DUPLEX,
PIPE_WAIT | PIPE_TYPE_BYTE,
PIPE_UNLIMITED_INSTANCES,
0,
0,
(DWORD)-1,
&SecAttrib);
There are not any errors being reported back from GetLastError(). Am I missing something obvious?
EDIT: Adding how the MiniDumpWriteDump() is being done in response to a comment.
HANDLE hDump = CreateFile(szPipeName, GENERIC_ALL, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
MiniDumpWriteDump(hProcess, pid, hDump, mdValue, NULL, NULL, NULL);
CloseHandle(hDump);
UPDATE:
I was under the impression that reading by chunks was somehow dropping data. To test this I increased the buffer of the named pipe to accommodate the entire dump without any resizing. I also increased the vecBuffer size to match. Now when performing the ReadFile() operation I receive the entire dump but it is still off. I'm still playing with various named pipe settings trying to figure out what needs to be done to get MiniDumpWriteDump() to provide valid output to a named pipe.
It appears this cannot be done. See the comments for more information. Writing directly to a named pipe from MiniDumpWriteDump() cannot be done because the handle that is passed in must have the ability to seek. Named pipes do not have that functionality, therefore you must use a legitimate file handle.
I am trying to redirect the stdout of a child process in Windows. Both are console programs. I don't have the source code of the child process, so I can't force it to flush the buffer. As discussed here and here, for the implementation of printf and similar, the C runtime buffers everything except consoles and printers. So the solution is apparently to create a console screen buffer using, appropriately enough, CreateConsoleScreenBuffer. I'm using the approach from codeproject.
PROCESS_INFORMATION pi;
HANDLE hConsole;
const COORD origin = { 0, 0 };
// Default security descriptor. Set inheritable.
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; // So the child can use it
// Create and initialize screen buffer
hConsole = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE, // Desired access
FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode to child processes
&sa, // SECURITY_ATTRIBUTES
CONSOLE_TEXTMODE_BUFFER, // Must be this.
NULL // Reserved. Must be NULL
);
DWORD dwDummy;
FillConsoleOutputCharacter(hConsole, '\0', MAXLONG, origin, &dwDummy)
Now I direct the child's stdout to the console and start the process
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES; // first one prevents cursor from showing loading.
si.hStdOutput = hConsole;
//...
// Get the command line and environmental block
//...
if (! CreateProcess(
NULL, // module name.
(char*)command_line.c_str(), // command line
NULL, // process SECURITY_ATTRIBUTES
NULL, // thread SECURITY_ATTRIBUTES
TRUE, // inherit handles
NULL, // creation flags
enviros, // environmentBlock (enviros=NULL for testing)
cDir, // working directory
&si, // STARTUP_INFO object
&pi // PROCESSINFO
) ){
auto test = GetLastError();
CloseHandle(hConsole);
return false;
}
CloseHandle(pi.hThread);
Then, in a loop, I can use ReadConsoleOutputCharacter to grab output, as shown at the codeproject link. It looks like
//... some initialization
GetConsoleScreenBufferInfo(hConsole, &csbi);
DWORD count = (csbi.dwCursorPosition.Y - lastpos.Y)*lineWidth + csbi.dwCursorPosition.X - lastpos.X;
LPTSTR buffer = (LPTSTR)LocalAlloc(0, count * sizeof(TCHAR));
ReadConsoleOutputCharacter(hConsole, buffer, count, lastpos, &count);
DWORD dwDummy;
FillConsoleOutputCharacter(hConsole, '\0', count, lastpos, &dwDummy);
//... Now move the cursor and grab the data from `buffer`
On Windows 7/8.1 this works fine for all programs. On Windows 10, some programs seem to be bypassing the supplied handles and printing directly to the parent console, preventing me from grabbing the output as I need.
I do have an additional clue. If I force the process to create a new console window, i.e.
CreateProcess(NULL, (char*)command_line.c_str(), NULL, NULL, TRUE, CREATE_NEW_CONSOLE, enviros, cDir, &si, &pi)
but still redirect the handles in the STARTUPINFO object, the new console will display a single line that says The system cannot write to the specified device, which just happens to be the exact wording of Windows error code ERROR_WRITE_FAULT = 29 in the MSDN docs. This happens only for those programs which aren't working as expected. Other programs, the new console is blank and they still function as expected.
My first thought is a permissions problem, but I have wide open permissions on the directories of the relevant executables.
Things I've tried
A different computer with Windows 10
Different versions of MS Visual C++ runtime
Setting the working directory explicitly in CreateProcess
Adding a super-permissive DACL to a SECURITY_ATTRIBUTES object passed to CreateProcess
Adding a super-permissive DACL to a SECURITY_ATTRIBUTES object passed to CreateConsoleScreenBuffer
Moving everything to a newly created directory under my Windows user directory
Running as administrator
Deeper
Thank you #PaulSanders for your suggestion.
To aid with anyone who might want to assist, I've made available a modified version of the RTConsole code from the codeproject page. It should compile in Visual Studio with just a retarget, I think. Around line 135, I've prepended a little string to the front of the output which takes the expected path. I've provided a pre-compiled version in there for convenience, as well.
One example of software that doesn't work is EWBF miner. For a quick test using the code I provided above, you could run
RTConsole2.exe "path\to\ewbf.exe" --help
You'll see that the prepended flag is not present in the output.
On the other hand, with ccminer, you'll get the expected behavior when running
RTConsole2.exe "path\to\ccminer.exe" --help
The new console implementation in Windows 10 has a bug in which high-level WriteConsole and WriteFile to a non-active screen buffer instead always writes to the active screen buffer. Low-level WriteConsoleOutput[Character] works correctly. Using the legacy console also works. You can enable the legacy console in the properties dialog.
Note that a process cannot use an inherited handle for a screen buffer in the parent's console if it allocates a new console due to the CREATE_NEW_CONSOLE flag. Trying to write to the screen-buffer file will fail because it's not bound to the caller's attached console (i.e. instance of conhost.exe).
Console files that are bound include "CON", "CONIN$", "CONOUT$", and a new screen buffer from CreateConsoleScreenBuffer. There are also unbound input and output console files, which are set as the standard handles when allocating a new console (e.g. via AllocConsole()). These handles access the input buffer and active screen buffer of any attached console [*]. Note that a process can have handles for console files that are bound to multiple consoles and can switch between consoles using AttachConsole.
Note also that some programs open "CONOUT$" instead of writing to the StandardOutput and StandardError handles, especially if they require a console instead of whatever the standard handles might be (e.g. a pipe or disk file). In this case it is not enough to set hStdOutput in STARTUPINFO. You have to temporarily make the new screen buffer active via SetConsoleActiveScreenBuffer. This does not affect the caller's standard handles. It sets the active screen buffer in the attached console, which is what "CONOUT$" opens. The previous screen buffer can be restored after the child process exits, or after you know the child has already opened and written to the new screen buffer.
[*] In Windows 8+, these console files are implemented by the condrv.sys device driver and opened on "\Device\ConDrv". They are respectively named "Console", "CurrentIn", "CurrentOut", "ScreenBuffer", "Input", and "Output". The filename for the console connection itself is "Connect". Internally the latter is opened as the process ConsoleHandle, which is used implicitly by the console API in some cases (e.g. GetConsoleWindow, GetConsoleCP, and GetConsoleTitle).
On the MSDN documentation, see https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx a sample is shown using anonymous pipes.
In the description can be read:
"...Note that named pipes can also be used to redirect process I/O."
Now, I am struggling to make this happen
For stdin, I do something like
serverPipe = CreateNamedPipe(
szPipeName,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1,
sizeof(TCHAR) * BUFSIZE,
sizeof(TCHAR) * BUFSIZE,
PIPE_TIMEOUT,
lpSa ); //lpSa has its inherited attribute set, just like in the msdn sample.
clientPipe = CreateFile(szPipeName, GENERIC_READ | GENERIC_WRITE, 0, lpSa, OPEN_EXISTING, 0, NULL);
Both pipes create fine, later I close the server (parent process) pipe
CloseHandle(serverPipe);
So the call to ConnectNamedPipe does not return error "there is already a process at the other end of the pipe".
Here is the code for ConnectNamedPipe
do
{
bSuccess = ConnectNamedPipe(serverPipe, &ol);
if (!bSuccess)
{
DWORD dwCode = GetLastError();
if (dwCode == ERROR_NO_DATA) continue;
if (dwCode == ERROR_PIPE_CONNECTED) break;
report_error(NULL);
}
} while (!bSuccess);
The problem is that it always returns error with ERROR_NO_DATA (The pipe is being closed). So never finished the loop.
NOTE: I need to inherit to the child process the handles to the pipes already opened, because I dont have the source of the children and thus cannot change it.
So, can someone point the right way to do this? or the a full working sample using named pipes for IO redirection for a child process using Win32 API?
PS. The reason I need named pipes is because I want to use Overlapped IO, which doesnt seem to be configurable in anonymous pipes.
I've coded two processes using C++. One is the GUI process that is called by my console app using CreateProcess API. I need to pass text from the GUI app (child) to the console app (parent.) The amount of text could be arbitrary -- from a few lines to KBs of text.
What is the easiest way to do it?
PS. I have access to the source code of both processes.
Console application can create a WinAPI window (non-visible), such that it can receive messages (idea taken from AllocateHWND function in Delphi).
Another solution is to use named pipes.
Another solution is to send data locally via TCP/IP.
If these strings are only a debug ones, consider using OutputDebugString function from WinAPI and capturing them with a program like SysInternals' DbgView.
If the GUI application is truly graphical only, you don't really use the standard output stream (i.e. std::cout). This can the be reused for output to your console application.
First you need to create an anonymous pipe using CreatePipe:
HANDLE hPipeRead;
HANDLE hPipeWrite;
CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0);
Now you have to handles that can be used as a normal file handle; One to read from and the other to write to. The write-handle should be set as the standard output for the new process you create:
STARTUPINFO startupInfo = { 0 };
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.hStdOutput = hPipeWrite; // Standard output of the new process
// is set to the write end of the pipe
CreateProcess(
lpApplicationName,
lpCommandLine,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&startupInfo, // Use our startup information
&processInfo);
Now whenever the child process needs to write to the parent, it only have to use standard output:
std::cout << "In child process, are you getting this parent?";
The parent uses ReadFile to read from the read-end of the pipe:
char buffer[256];
DWORD bytesRead = 0;
ReadFile(hPipeRead, buffer, sizeof(buffer), &bytesRead, NULL);
Note: I haven't done WIN32 programming in some time, so might be wrong on some details. But should hopefully be enough to get you started.
There are of course many other ways if Inter Process Communications (IPC), including (but not limited to) sockets, files, shared memory, etc.
The easy way is probably to make the child actually a console application, even though it also creates windows.
In that case, you can have your parent spawn the child using _popen, and the child can just write the output to its normal stdout/std::cout. _popen returns a FILE *, so the parent can read the child's output about like it'd normally read a file (well, normally for C anyway).
Various methods can be used, some of them were given above. Which one is simplest depends on you task.
I can also suggest you filemapping technics which is widely used in IPC, and for ex. dll are implemented using filemapping.
It allows mutliply processes to share the same resources simultaniously, access is random not consequntial.
Here are main steps of implementation:
1. Process A creates a file;
2. Process A creates a named system object mappedfile to the file (mappedfile allocates memory);
3. Process A creates a system object a viewOfMapped file(this allows to map some area of the process A to the pages in the main memory which were allocated by mappedFile);
4. Process B creates the named system object mappedfile(name should be similar to the one of process A used), viewOfMapped file;
5. By pointers returned by viewOfMapped processes can share the same memory.
Example:
Process A:
/* 1. file creation */
hFile = CreateFile(0, GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
NULL);
/* 2. Create file mapping */
wchar_t lpName[] = L"fileMappingObject0";
HANDLE hfileMappingObject;
hfileMappingObject = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 1024, lpName);
/* 3. Create MappedFileViewOfFile */
void* p = (MapViewOfFile(hfileMappingObject, FILE_MAP_ALL_ACCESS, 0, 0, 0));
Process B:
/* 2. Create file mapping */
wchar_t lpName[] = L"fileMappingObject0";
HANDLE hfileMappingObject;
hfileMappingObject = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 1024, lpName);
/* 3. Create MappedFileViewOfFile */
void* p = (MapViewOfFile(hfileMappingObject, FILE_MAP_ALL_ACCESS, 0, 0, 0));
This method is rather simple and also powerfull.
I am using CreateProcess() to run an external console application in Windows from my GUI application. I would like to somehow gather the output to know whether there were errors. Now I know I have to do something with hStdOutput, but I fail to understand what. I am new to c++ and an inexperienced programmer and I actually don't know what to do with a handle or how to light a pipe.
How do I get the output to some kind of variable (or file)?
This is what I have a the moment:
void email::run(string path,string cmd){
WCHAR * ppath=new(nothrow) WCHAR[path.length()*2];
memset(ppath,' ',path.length()*2);
WCHAR * pcmd= new(nothrow) WCHAR[cmd.length()*2];
memset(pcmd,' ',cmd.length()*2);
string tempstr;
ToWCHAR(path,ppath); //creates WCHAR from my std::string
ToWCHAR(cmd,pcmd);
STARTUPINFO info={sizeof(info)};
info.dwFlags = STARTF_USESHOWWINDOW; //hide process
PROCESS_INFORMATION processInfo;
if (CreateProcess(ppath,pcmd, NULL, NULL, FALSE, 0, NULL, NULL, &info, &processInfo))
{
::WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
delete[](ppath);
delete[](pcmd);
}
This code probably makes any decent programmer scream, but (I shouldn't even say it:) It works ;-)
The Question: How do I use hStdOutput to read the output to a file (for instance)?
Microsoft has an example in its knowledge base that demonstrates how to capture the output of a child console process. The basic principle is that the parent process creates pipes (one per standard handle to redirect) and passes the handles to CreateProcess.
The child process does not need to be modified for this to work, which is important if you do not have control over the child's source.
More information: How to spawn console processes with redirected standard handles