Konsolenprgramm steuern (stdin)



  • Hallo,
    ich habe ein altes DOS- Programm, das unter WinXP in der Konsole (cmd) läuft. Jetzt möchte ich dieses Programm von meinem VC++ Programm aus starten und das DOS- Programm bedienen, also Texte schreiben oder F- Tasten simulieren.

    Ich lege eine Pipe an (CreatePipe), starte den Prozess mit CreateProcess und schreibe mit WriteFile in die Pipe.

    Was muss ich tun, damit das DOS- Programm, das nichts von der Pipe weiss, diese Eingaben auch annimmt/ anzeigt?

    Mit dem folgenden Programm kann ich den Prozess starten und in die Pipe schreiben, allerdings kommt nichts an. 😞

    void CShellViewDlg::OnCreate() 
    {
    
    	SECURITY_ATTRIBUTES sa;
    	ZeroMemory(&sa,sizeof(SECURITY_ATTRIBUTES));
    	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    	sa.bInheritHandle = TRUE;
    	sa.lpSecurityDescriptor = NULL;  //TODO
    
    	//sichern des Handles
    	hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
    
    	HANDLE hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
    	//Pipe anlegen
    	if(!CreatePipe(&hChildStdinRd, &hChildStdinWr, &sa,0)){
    		MessageBox("Fehler beim Pipe- Erzeugen");
    	}
    
    	if(!SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd)){
    		MessageBox("Fehler bei Verbindung zu Stdin");
    	}
    
    	//Duplizieren des Schreib Handels, damit es nicht vererbt wird
    	if(!DuplicateHandle(GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0,FALSE, DUPLICATE_SAME_ACCESS)){
    		MessageBox("Fehler beim Duplizieren");
    	}
    	CloseHandle(hChildStdinWr);
    
    /********************************************************************
    **********  Prozess starten  **********************************
    ********************************************************************/
    	STARTUPINFO    si;
    	ZeroMemory(&si,sizeof(STARTUPINFO));
    
    	 // stdin, stdout und stderr des Kindes in STARTUPINFO eintragen
    	si.cb         = sizeof(STARTUPINFO);
    	si.dwFlags    = STARTF_USESTDHANDLES;
    	si.hStdInput  = hChildStdinRd;
    	si.hStdOutput = hChildStdoutWr;
    	si.hStdError  = hChildStdoutWr;
    
        PROCESS_INFORMATION  pi;
    	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
    
        GetStartupInfo(&si); 
    
        BOOL ret = CreateProcess(NULL,"C:\\WINNT\\System32\\cmd.exe",// Name der Appl
    	  &sa,      // Default process security attributes
    	  NULL,      // Default thread security attributes
    	  TRUE,      // inherit handles from the parent
    	  0,      // Normal priority
    	  NULL,      // Use the same environment as the parent
    	  NULL,      // Launch in the current directory
    	  &si,      // Startup Information
    	  &pi);      // Process information stored upon return
    
    	if(ret){
    		int dwProcessId = pi.dwProcessId;
    		char final_string[200];
    		sprintf(final_string, "ProzessId: %i", dwProcessId);
    		MessageBox(final_string);
    		//Beendet den Prozess
    //		HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE,dwProcessId );
    //		TerminateProcess (hProcess,0);
    //		CloseHandle(hProcess);
    	}
    	else
    	{
    		MessageBox("Fehler beim Erzeugen des Prozesses");
    	}
    
    }
    
    //in die Pipe schreiben
    void CShellViewDlg::Write(HANDLE childStdinWrDup)
    {
    	LPCTSTR line = "Test von Stdin";
    	DWORD dwWritten;
    	if(!WriteFile(childStdinWrDup, line, _tcslen(line)*sizeof(TCHAR),&dwWritten,NULL)){
    		MessageBox("Fehler beim Schreiben");
    	}
    	else{
    		char final_string[200];
    		sprintf(final_string, "Länge des geschriebenen Textes: %i", dwWritten);
    		MessageBox(final_string);
    	}
    }
    
    //
    void CShellViewDlg::OnWrite() 
    {
    	Write(hChildStdinWrDup);
    }
    

    gruss
    ziba



  • Hi, erstmal Willkommen im Forum.

    Kannst du deinen Code bitte in [ cpp ] [ /cpp ] - Tags (ohne Leerzeichen) schreiben? Dann wird der Code übersichtlicher angezeigt. 😉





  • Danke erstmal für die Antwort.

    Hab mir den Artikel bei MSDN durchgelesen und das Programm mal getestet.
    Kann sein, dass ich's nur grad nicht blicke 😞 , aber
    bei diesem Beispielprogramm schickt der Kindprozess ja die Daten zurück, die der Vaterprozess gesendet hat.
    Bei meinem Programm müsste der Kindprozess die Daten, die der Vater sendet im eigenen Fenster anzeigen. Mein Problem ist, dass ich vom DOS- Programm nur ein exe- File habe, also den Code nicht verändern kann. Ich bräuchte also genau die Schnittstelle, die die Tastatur nutzt.

    gruss
    ziba



  • Noch eine Frage:

    Mit

    si.dwFlags = STARTF_USESTDHANDLES;
          si.hStdOutput = hChildStdOut;
          si.hStdInput  = hChildStdIn;
          si.hStdError  = hChildStdErr;
    

    lege ich die STARTUPINFO des Kindprozesses fest. si.dwFlags = STARTF_USESTDHANDLES; legt fest, dass die nachfolgenden 3 Parameter für Stdout, Stdin und Stderr des Kindes verwendet werden.
    Soweit so gut, aber ich möchte, dass der Kindprozess nur den Stdin vom Vaterprozess bekommt und der Stdout bleibt, wie er ist. Also wie komme ich an den Stdout des Kindprozesses, oder wie muss si.hStdOutput = ??? aussehen, damit der Kindprozess seinen Stdout behält. Parameter weglassen oder gleich NULL setzen hilft nicht.



  • Hab das Programm zum Laufen bekommen und leicht abgeändert, sodass ich es auch für ein eigenes Konsolenprogramm nutzen kann.
    Mit nem normalen Konsolenprogramm funktioniert das auch ganz gut, aber wenn ich mein altes DOS- Programm starte bekomme ich nur folgende Fehlermeldung:

    Titel: 16-Bit-MS-DOS-Teilsystem

    D:\...\...\yyy.exe
    Die NTVDM-CPU hat einen ungültigen Befehl entdeckt.
    CS:0836 IP:01f2 OP:63 65 73 73 2e Klicken Sie auf "Schließen" ...

    Kann sich jemand vorstellen, warum das jetzt kommt.
    Es muss doch einen Weg geben, das Programm zu steuern.
    Mit dem TOOL von autoitscript.com gehts ja auch.


Anmelden zum Antworten