Pipe ReadFile blockiert
-
PathRetriever.h:
#pragma once #include <Windows.h> #include <Shlwapi.h> #pragma comment(lib,"Shlwapi.lib") #include <string> class PathRetriever { public: PathRetriever(void); bool RetrievePath(std::wstring& Target); ~PathRetriever(void); };
MyPipe.h:
#pragma once #include <Windows.h> #include <string> class MyPipe { private: HANDLE hRead; HANDLE hWrite; bool bCreateSuccessful; void CreatePipeInternal(); public: MyPipe(void); bool ReturnCreateSucessfull(); HANDLE ReturnReadHandle(); HANDLE ReturnWriteHandle(); void ReadLoop(std::wstring& ResultString); ~MyPipe(void); };
MyProcess.h:
[#pragma once #include <Windows.h> #include <string> #include "MyPipe.h" class MyProcess { private: bool bSuceeded; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; void ZeroStructures(); void ConstructInternal(wchar_t* Path,wchar_t* Arguments,HANDLE hOutput); bool bCreateSuccessful; public: MyProcess(std::wstring Path); MyProcess(std::wstring Path,std::wstring Arguments); MyProcess(std::wstring Path,std::wstring Arguments,MyPipe OutputPipe); bool ReturnCreateSucessfull(); void WaitForExit(); ~MyProcess(void); };]
MyPipe.h:
#pragma once #include <Windows.h> #include <string> class MyPipe { private: HANDLE hRead; HANDLE hWrite; bool bCreateSuccessful; void CreatePipeInternal(); public: MyPipe(void); bool ReturnCreateSucessfull(); HANDLE ReturnReadHandle(); HANDLE ReturnWriteHandle(); void ReadLoop(std::wstring& ResultString); ~MyPipe(void); };
MyPipe.cpp:
#include "MyPipe.h" MyPipe::MyPipe(void) { CreatePipeInternal(); } void MyPipe::CreatePipeInternal() { bCreateSuccessful=false; SECURITY_ATTRIBUTES saAttr={0}; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; if(CreatePipe(&this->hRead,&this->hWrite,&saAttr,0)) { bCreateSuccessful=true; } ; } HANDLE MyPipe::ReturnReadHandle() { return hRead; } HANDLE MyPipe::ReturnWriteHandle() { return hWrite; } bool MyPipe::ReturnCreateSucessfull() { return bCreateSuccessful; } void MyPipe::ReadLoop(std::wstring& ResultString) { DWORD dwRead=0; bool bResult=true; wchar_t Buf[2]={0}; do { ZeroMemory(&Buf,sizeof(wchar_t)*2); dwRead=0; if(ReadFile(this->ReturnReadHandle(),Buf,sizeof(wchar_t)*2,&dwRead,0)) { bResult=true; } else { DWORD dwLast=GetLastError(); } ResultString+=std::wstring(Buf); } while(bResult&&dwRead==sizeof(wchar_t)*2); } MyPipe::~MyPipe(void) { }
MyProcess.cpp:
#include "MyProcess.h" void MyProcess::ZeroStructures(void) { ZeroMemory(&this->StartupInfo,sizeof(STARTUPINFO)); ZeroMemory(&this->ProcessInformation,sizeof(ProcessInformation)); } void MyProcess::ConstructInternal(wchar_t* Path,wchar_t* Arguments,HANDLE hOutput){ ZeroStructures(); bCreateSuccessful=false; if(hOutput) { this->StartupInfo.hStdOutput=hOutput; this->StartupInfo.dwFlags|=STARTF_USESTDHANDLES; } if(CreateProcess(Path,Arguments,0,0,TRUE,NORMAL_PRIORITY_CLASS,0,0,&this->StartupInfo,&this->ProcessInformation)) { bCreateSuccessful=true; } } MyProcess::MyProcess(std::wstring Path) { ConstructInternal(const_cast<wchar_t*>(Path.c_str()),0,0); } MyProcess::MyProcess(std::wstring Path,std::wstring Arguments) { ConstructInternal(const_cast<wchar_t*>(Path.c_str()),const_cast<wchar_t*>(Arguments.c_str()),0); } MyProcess::MyProcess(std::wstring Path,std::wstring Arguments,MyPipe OutputPipe) { ConstructInternal(const_cast<wchar_t*>(Path.c_str()),const_cast<wchar_t*>(Arguments.c_str()),OutputPipe.ReturnWriteHandle()); } bool MyProcess::ReturnCreateSucessfull() { return bCreateSuccessful; } void MyProcess::WaitForExit() { WaitForSingleObject(this->ProcessInformation.hProcess,INFINITE); } MyProcess::~MyProcess(void) { CloseHandle(this->ProcessInformation.hThread); CloseHandle(this->ProcessInformation.hProcess); }
PathRetriever.cpp:
#include "PathRetriever.h" PathRetriever::PathRetriever(void) { } bool PathRetriever::RetrievePath(std::wstring& Target) { bool bReturn=false; WCHAR Path[MAX_PATH+1]={0}; if(GetSystemDirectory(Path,MAX_PATH+1)) { if(PathAppend(Path,L"net.exe")) { Target=std::wstring(Path); bReturn=true; } } return bReturn; } PathRetriever::~PathRetriever(void) { }
Die Funktion:
void RunNetAndDisplayResult() { MyPipe Pipe; if(Pipe.ReturnCreateSucessfull()) { SetHandleInformation(Pipe.ReturnWriteHandle(),HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT); std::wstring Path=L""; PathRetriever Retriever; Retriever.RetrievePath(Path); MyProcess Process(Path,L"users",Pipe); if(Process.ReturnCreateSucessfull()) { Process.WaitForExit(); std::wstring Result=L""; Pipe.ReadLoop(Result); MessageBox(0,const_cast<wchar_t*>(Result.c_str()),L"Ergebnis",MB_ICONINFORMATION); } } }
-
ist jetzt geraten aber wird die Process.WaitForExit() denn überhaupt beendet?
-
@Wade1234 Ja, Process.WaitForExit() wird beendet. Ich habe enen Breakpoint bei "std::wstring Result=L"";" gesetzt. Der Breakpoint wird erreicht.
-
@philipp95 probier mal SetHandleInformation(Pipe.ReturnWriteHandle(),HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT); in SetHandleInformation(Pipe.ReturnWriteHandle(),HANDLE_FLAG_INHERIT,0); zu ändern. ansonsten gibt es im msdn ein sehr schönes beispiel für die verwendung von pipes.
-
@Wade1234 Ich habe die Zeile in SetHandleInformation(Pipe.ReturnWriteHandle(),HANDLE_FLAG_INHERIT,0); geändert. Dennoch blockiert ReadFile.
-
und ConstructInternal(const_cast<wchar_t*>(Path.c_str()),const_cast<wchar_t*>(Arguments.c_str()),OutputPipe.ReturnWriteHandle()); funktioniert? also eigentlich kannst du char nicht so einfach nach wchar casten.
-
@Wade1234 std::wstring Path,std::wstring Arguments
-
Nur mal eine Vermutung: Du kannst vor ReadFile mit PeekNamedPipe schauen, ob überhaupt etwas zu holen ist (auch ohne zu kopieren). Und anschließend eben solange ReadFile aufrufen, bis die verfügbaren Bytes (lpTotalBytesAvail) abgeholt sind.
Irgendwas war da nämlich...
-
@philipp95 sagte in Pipe ReadFile blockiert:
@Wade1234 std::wstring Path,std::wstring Arguments
ja aber arguments.c_str()? wieso liest du eigentlich immer 2* sizeof(wchar_t)? wird überhaupt etwas aus der pipe gelesen?
@yahendrik sagte in Pipe ReadFile blockiert:
Nur mal eine Vermutung: Du kannst vor ReadFile mit PeekNamedPipe schauen, ob überhaupt etwas zu holen ist (auch ohne zu kopieren). Und anschließend eben solange ReadFile aufrufen, bis die verfügbaren Bytes (lpTotalBytesAvail) abgeholt sind.
Irgendwas war da nämlich...das ist aber eine anonymous pipe, bei der readfile eigentlich mit eof bzw. dem entsprechenden äquivalent returnen sollte, wenn keine daten mehr vorhanden sind.
jedenfalls ist das mal ein schönes beispiel, warum ich lieber mit C bzw. funktionsorientierung programmiere.
-
Pipe? Warum Pipe? Das ist eine normale Datei...
Halte Dich an dieses offizielle Beispiel und es sollte gehen:
https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
-
@philipp95 sagte in Pipe ReadFile blockiert:
Hallo, ich habe ein C++-Programm, was die Standardausgabe von net users auslesen soll.
So was hab ich auch mal gemacht:
https://www.c-plusplus.net/forum/topic/248213/system-befehl-ausgabe-umleiten/10
-
Oder einfach popen/_popen/_wpopen verwenden. Geht noch einfacher und ist sogar fast plattformunabhängig. Ob das für dich sinnvoll ist, sei dahingestellt, es ist aber zweifelsohne kürzer.
#include <cstdio> //... static int closePipe(FILE *p) { #if _WIN32 return _pclose(p); #else return pclose(p); #endif }; //eine Klasse, deren Objekt eine Pipe enthält und diese automatisch mit closePipe schließt. using pipeptr = std::unique_ptr<FILE, decltype(&closePipe)>; //führt command aus und gibt dessen errorcode + rückgabewert zurück std::pair<int, std::string> exec(const std::string &command) { #ifdef _WIN32 //2>&1 sorgt dafür, dass stderr nach stdout fließt pipeptr pipe(_popen((command + " 2>&1").c_str(), L"r"), &closePipe); #else pipeptr pipe(popen((command + " 2>&1").c_str(), &closePipe); #endif if(!pipe) ...//fehler, den du aus errno auslesen kannst. std::string output; char buf[512]; while(fgets(buf, sizeof(buf), pipe.get())) output += buf; auto ret = closePipe(pipe.release()); return { ret, output }; }