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.
Related
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.
In my current work, we have several threads running simultaneously,
Through one of the thread we have open a file:
std::ofstream fs;
fs.open(filename.c_str(), std::ofstream::out);
if( fs.is_open() ){
// do some file operation and write
fs.close();
}
while a separate thread also access the same file:
HANDLE handle = CreateFileW(filename.c_str(), GENERIC_READ,0, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
it fails and gives error ERROR_SHARING_VIOLATION.
I know, we can overcome the issue using synchronisation mechanism,
But can we handle it using file sharing mechanism while opening the file, since one thread is using stream API to open the file, while other uses createFile.
Any input is appreciable.
Your CreateFile() call is setting the dwShareMode parameter to 0, so it is trying to open the file for exclusive access, which will fail if the file is already open.
You need to specify sharing rights that are compatible with how the ofstream opens the file, eg:
HANDLE handle = CreateFileW(filename.c_str(), GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
I know how to do this through an anonymous pipe, just create an anonymous pipe and before executing createprocess(), set the startupInfo as follow:
startupInfo.hStdInput = hstdinRead;//hstdinRead is the handle of the pipe
startupInfo.hStdOutput = hstdoutWrite;
But can I do the same when I use a named pipe?
I have tried to create a named pipe through CreateNamedPipeA function and do similar above, but things don't seem to work at all.
Should I do some pre-settings or is it just impossible to communicate between a process and it's child process through a named pipe?
And : My child process is an unchangable .exe, so I must do all these things before createprocess() function in the parent process.
20180804: thanks for your comments, I am still polishing my English, and my codes using named pipes are like these.
First I create two named pipes and I have confirmed they succeed:
inFileWrite = CreateNamedPipeA("\\\\.\\pipe\\cmder_in", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 10, 4096, 4096, 0, &saAttr);//for writting to the child process
outFileRead = CreateNamedPipeA("\\\\.\\pipe\\cmder_out", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 10, 4096, 4096, 0, &saAttr);//for reading from the child process
Then I try to connect to these pipes in the same process(I am a bit confused about this step)
inFileRead = CreateFileA("\\\\.\\pipe\\cmder_in", GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, &saAttr)
outFileWrite = CreateFileA("\\\\.\\pipe\\cmder_out", GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, &saAttr);
After some other init steps, I create a STARTUPINFO struct for childprocess, in which I try to redirect its std input/output:
startupInfo.hStdInput = inFileRead;
startupInfo.hStdOutput = outFileWrite;
Finally it's the createprocess:
char cmdLine[] = { "cmd" };
CreateProcess(NULL,
cmdLine,
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&startupInfo,
&procInfo);
These all codes seem to work well, but when I write an command like "cd .." and try to read the result from childprocess through the pipe, it reads nothing. I think the problem is I didn't redirect childprocess's stdin/out successfully.
I succeeded in doing similar things by using an anonymous pipe or named pipes in Linux. I am new to windows programming, and this problem has stuck me for a long time.
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.
In Windows it's possible to open devices and volumes via CreateFile(). I've used this successfully before to ReadFile() from devices, but now I want to switch to memory-mapping. In the following code, I receive INVALID_HANDLE_VALUE for the value of b, and c is set to 87, ERROR_INVALID_PARAMETER.
HANDLE a = ::CreateFileA("\\\\.\\h:", GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_NO_BUFFERING, NULL);
HANDLE b = ::CreateFileMappingA(a, NULL, PAGE_READONLY, 0, 0, NULL);
DWORD c = ::GetLastError();
How can I get this to work?
You can't. CreateFileMapping can only create a mapping to a file. Take a look at the difference in the documentation between the hFile parameter for ReadFile and for CreateFileMapping. For ReadFile it lists all the different types of handles it accepts (which includes devices), for CreateFileMapping it only lists files.