createprocess() Konsolenprogramm starten und Dateinamen übergeben c++



  • Hallo,

    ich arbeite mit C++ VS2010 und möchte ein altes Fortran Program für die Konsole starten. Sobald das Programm gestartet ist muss man per Hand einen Dateinamen eingeben, als Parameter läßt sich dieser Name nicht übergeben.

    Meine Konkrete Frage lautet: Wie benutze ich eine Pipe um diesen Dateinamen zu übergeben?

    Folgende Seiten zum Thema habe ich mir angesehen, aber ich verstehe es leider nicht.

    http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx
    http://www.goffconcepts.com/techarticles/development/cpp/createprocess.html
    http://www.dreamincode.net/forums/topic/227707-microsoft-standard-inputoutput-redirection/

    Die Beispiele behandeln immer einen Child Prozess, welcher mit dem Hauptprozess Informationen austauscht, aber auf den Code von meinen Child Prozess habe ich keinerlei zugriff. Mir ist auch schleierhaft wie ich die Funktion Writefile() benutzen kann um nur einen Namen zu übergeben, diese erwartet ja eine Datei bzw. einen Pointer auf einen Speicherbereich, wenn ich das richtig verstehe.

    Ich kann bereits das Konsolenprogramm mit createprocess() starten, aber die korrekte Benutzung der Pipe funktioniert nicht. Mein code besteht derzeit nur aus copy-paste von den Beispielen, daher denke ich, dass es derzeit keinen Sinn macht ihn hier zu posten.

    Über einen guten Ratschlag würde ich mich sehr freuen!

    Gruß Attila009



  • Eine Pipe würde Dir nur nutzen, wenn das Programm von der Standardeingabe liest. Das kannst Du leicht ausprobieren. Leg eine Datei dat.txt (oder so) an, die den Dateinamen beinhaltet:

    dat.txt:
    dateiname

    und starte Dein Programm aus der Konsole mit

    progname < dat.txt

    Wenn das funktioniert und Du mehr nicht benötigst, kannst Du Dir auch die Pipe sparen, und das Programm so via CreateProcess starten, sofern die Datei mit dem Dateinamen bereitsteht.



  • Grandios, es funktioniert wie Du geschrieben hast! Dann komme ich mit meinem derzeitigen createprocess() klar, denke ich.

    Vielen Dank!



  • Zu früh gefreut, so wie ich es bis jetzt versucht habe funktioniert es leider nicht mit createprocess().

    dateiname.txt ist eine Datei mit der Bezeichnung ("Haus2") die übergeben werden soll.

    "lpdt.exe < dateiname.txt" auf der Console hat funktioniert.

    Hier die Möglichkeiten welche ich ausprobiert habe. Die Befehle musste ich leider aus dem Gedächtnis schreiben, weil ich meinen Code momentan nicht zur Hand habe, es könnte also sein, dass ich einen Syntaxfehler o.ä. gemacht habe. Der Compiler hat auf jedenfall nie gemeckert.

    CreateProcessW(const_cast<LPCWSTR>(L"lpdt.exe"),L"< dateiname.txt", 0, 0, false,CREATE_DEFAULT_ERROR_MODE, 0, 0, &siStartupInfo, &piProcessInfo);
    CreateProcessW(const_cast<LPCWSTR>(L""),L"lpdt.exe < dateiname.txt", 0, 0, false,CREATE_DEFAULT_ERROR_MODE, 0, 0, &siStartupInfo, &piProcessInfo);
    CreateProcessW(const_cast<LPCWSTR>(L"lpdt.exe < dateiname.txt"),L"", 0, 0, false,CREATE_DEFAULT_ERROR_MODE, 0, 0, &siStartupInfo, &piProcessInfo);   
    
    CreateProcessW(const_cast<LPCWSTR>(L"lpdt.exe"),L"< Haus2", 0, 0, false,CREATE_DEFAULT_ERROR_MODE, 0, 0, &siStartupInfo, &piProcessInfo);
    CreateProcessW(const_cast<LPCWSTR>(L""),L"lpdt.exe < Haus2", 0, 0, false,CREATE_DEFAULT_ERROR_MODE, 0, 0, &siStartupInfo, &piProcessInfo);
    CreateProcessW(const_cast<LPCWSTR>(L"lpdt.exe < Haus2"),L"", 0, 0, false,CREATE_DEFAULT_ERROR_MODE, 0, 0, &siStartupInfo, &piProcessInfo);
    

    Hat jemand ne Idee woran es liegen könnte?

    Gruß
    Attila009



  • Für I/O Redirection musst du in der STARTUPINFO hStdInput, hStdOutput, hStdError entsprechend setzen oder alternativ den Prozess die passenden Handles erben lassen. Abgesehen davon darfst du an CreateProcessW() als lpCommandLine kein Stringliteral übergeben und wofür eigentlich der const_cast? Überhaupt solltest du dir mal genau anschauen, wie das mit dem lpApplicationName bzw. lpCommandLine Parameter funktioniert...



  • Okay, dann brauchst Du wohl doch eine Pipe.
    Ich hab da vor langer Zeit mal mit rumexperimentiert, vielleicht kannst Du das hier einsetzen:
    pipe.h

    #ifndef PIPEH
    #define PIPEH
    
    #include <windows.h>
    
    class pipe
    {
    	public:
    		enum pipeEnde {READ, WRITE};
    
    		pipe();
    		~pipe();
    
    		HANDLE GetPipeHandle(pipeEnde end);
    
    		void MakeInheritable(pipeEnde end);
    		void ClosePipeHandle(pipeEnde end);
    
    	private:
    
    		HANDLE readEnd, writeEnd;	
    
    		void MakeInheritable(HANDLE *h, bool inheritable);
    
    		//dont copy || assign
    		pipe(const pipe &);
    		pipe& operator=(const pipe &);
    };
    #endif
    

    pipe.cpp

    #include "pipe.h"
    
    //Konstruktor
    pipe::pipe()
    {
    	CreatePipe(&readEnd, &writeEnd, NULL, 0);
    }
    
    //Destruktor
    pipe::~pipe()
    {
    	ClosePipeHandle(READ);
    	ClosePipeHandle(WRITE);
    }
    
    //public
    void pipe::ClosePipeHandle(pipeEnde end)
    {
    	switch(end)
    	{
    		case READ:
    				if(readEnd)
    				{
    					CloseHandle(readEnd);
    					readEnd = 0;
    				}
    				break;
    		case WRITE:
    				if(writeEnd)
    				{
    					CloseHandle(writeEnd);
    					writeEnd = 0;
    				}
    				break;
    	}
    }
    
    HANDLE pipe::GetPipeHandle(pipeEnde end)
    {
    	switch(end)
    	{
    		case READ:  return readEnd;
    		case WRITE: return writeEnd;
    	}
    
    	return NULL;
    }
    
    void pipe::MakeInheritable(pipeEnde end)
    {
    	switch(end)
    	{
    		case READ:
    				MakeInheritable(&readEnd, true); 
    				MakeInheritable(&writeEnd, false);
    				break;
    		case WRITE:
    				MakeInheritable(&readEnd, false); 
    				MakeInheritable(&writeEnd, true);
    				break;
    	}
    }
    
    //private
    void pipe::MakeInheritable(HANDLE *h, bool inheritable)
    {
    	if(!h)
    		return;
    
    	HANDLE proc = GetCurrentProcess();
    
    	DuplicateHandle(proc, *h, proc, h, 0, inheritable, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
    }
    

    myConsole.h

    #ifndef MYCONSOLEH
    #define MYCONSOLEH
    
    #include <string>
    #include "pipe.h"
    
    class myConsole
    {
    	public:
    		myConsole();
    		~myConsole();
    		void doCommand(std::string command);
    
    	private:
    
    		pipe writePipe;
    };
    #endif
    

    myConsole.cpp

    #include <iostream>
    #include "myConsole.h"
    
    //public
    
    void myConsole::doCommand(std::string command)
    {	
    	DWORD ignore;
    
    	command.append("\n");
    	bool wf = WriteFile(writePipe.GetPipeHandle(pipe::WRITE), command.c_str(), command.size(), &ignore, 0);
    }
    
    myConsole::~myConsole()
    {
    	doCommand("exit\n");
    }
    
    myConsole::myConsole()
    {
       PROCESS_INFORMATION pi;
       STARTUPINFO si;
    
    	writePipe.MakeInheritable(pipe::READ);
    
       // Set up the start up info struct.
       ZeroMemory(&si,sizeof(STARTUPINFO));
       si.cb = sizeof(STARTUPINFO);
       si.dwFlags = STARTF_USESTDHANDLES;
       si.hStdInput = writePipe.GetPipeHandle(pipe::READ);
       si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
       si.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
    
       CreateProcess(0, "cmd.exe", NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
    	writePipe.ClosePipeHandle(pipe::READ);
    
       CloseHandle(pi.hThread);
       CloseHandle(pi.hProcess);
    }
    

    ein Testprogramm, das ausgeführt und mit einem Parameter versorgt werden soll:
    prog.cpp

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
       string test;
       cin >> test;
    
       cout << "\nEingabe: " << test << '\n';
    
       cin >> test;
    }
    

    die Datei, die den Parameter enthält
    test.txt

    hallo
    

    und schließlich das Programm, das das obige Programm mit der Input-Datei test.txt aufrufen soll:

    #include "myConsole.h"
    
    int main()
    {
       myConsole mc;
       mc.doCommand("prog < test.txt");
    
       Sleep(5000);
    }
    


  • @Belli: Vielen Dank für deine Hilfe, aber für meine recht einfachen Anforderungen ist mir gerade eine simple Lösung eingefallen.

    Nach dem Start von CreateProcess() übergebe ich dem Programm seine Information (Dateiname) über "keybd_event(0x54, 0 ,0, 0);". Das funktioniert einfach und gut.


Log in to reply