Ausgabe einer Konsolenanwendung in GUI



  • Würd mich auch ma brennend interessieren, suche sowas schon ewig, aber nirgendwo im Netz was gefunden... irgendeiner hier kann doch mit Sicherheit helfen oder hat das schon genau so gemacht?!



  • Hallo Karl-Heinz

    Versuch mal folgendes:

    while(fgets(buff, 512, in) != NULL)
        {
            m_out.SetSel(MAXLONG,MAXLONG);
            m_out.ReplaceSel(CString(buff));
            m_out.Invalidate ();
            m_out.UpdateWindow ();
        }
    


  • Hi, weicher, funktioniert auch nicht, weder UpdateWindow() noch UpdateData() noch sonst irgendwas. Bin ehrlich gesagt ein wenig ratlos...



  • Hallo Karl-Heinz

    das könntest Du noch versuchen... Hat aber seine Tücken 😉

    MSG msg;  // edit: brauchts natürlich auch noch
        while(fgets(buff, 512, in) != NULL)
        {
            m_out.SetSel(MAXLONG,MAXLONG);
            m_out.ReplaceSel(CString(buff));
            m_out.Invalidate ();
            m_out.UpdateWindow ();
    
            while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
            {
              if (!AfxGetThread()->PumpMessage())
                break;
            }
        }
    


  • Leider auch nicht, erst wenn die Konsolenanwendung beendet ist, ich hab auch während die Konsolenanwendung läuft, keinen Zugriff auf meine GUI 😞



  • Hallo Karl-Heinz

    ich hab auch während die Konsolenanwendung läuft

    Dass Du eine Konsolenanwendung hast, habe ich überlesen.

    Mach doch eine Dialogbasierte Anwendung, dann wird es gehen.



  • 😃 ich glaube du verstehst mein problem nicht. ich will ja aus einer Konsolenanwendung bewusst die Ausgabe auslesen 😃



  • dann leg doch das lesen in einen thread und poste von da über eine usermessage die daten in dein mainthread also da wo dein edit läuft, dann sollte meiner meinung nach auch die darstellung laufen, denk dran im read-thread das du ne pause mit ein baust sonst pollt der auf 100% der CPU leistung unmd wird nur durch windows eigenem threadwechsel raus gerissen



  • also zunächst hab ich die popen-Funktion rausgeschmissen und gehe nun über CreateProcess. Hab mir mal angeschaut wie man mit pipes umgeht und mir daraus den gleichen Effekt gebastelt wie mit popen. Die Frage ist nun an welcher Stelle muss ich welche Nachricht wohin schicken, damit die GUI nicht mit "keine Rückmeldung" da steht?

    Pipe.h:

    #ifndef PIPEH
    #define PIPEH
    
    #include <windows.h>
    
    class CPipe
    {
        public:
            enum pipeEnde {READ, WRITE};
    
            CPipe();
            ~CPipe();
    
            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
            CPipe(const CPipe &);
            CPipe& operator=(const CPipe &);
    };
    
    #endif
    

    Pipe.cpp

    #include "StdAfx.h"
    #include "Pipe.h"
    
    //Konstruktor
    CPipe::CPipe()
    {
        CreatePipe(&readEnd, &writeEnd, NULL, 0);
    }
    
    //Destruktor
    CPipe::~CPipe()
    {
        ClosePipeHandle(READ);
        ClosePipeHandle(WRITE);
    }
    
    //public
    void CPipe::ClosePipeHandle(pipeEnde end)
    {
        switch(end)
        {
            case READ:
                    if(readEnd)
                    {
                        CloseHandle(readEnd);
                        readEnd = 0;
                    }
                    break;
            case WRITE:
                    if(writeEnd)
                    {
                        CloseHandle(writeEnd);
                        writeEnd = 0;
                    }
                    break;
        }
    }
    
    HANDLE CPipe::GetPipeHandle(pipeEnde end)
    {
        switch(end)
        {
            case READ:  return readEnd;
            case WRITE: return writeEnd;
        }
    
        return NULL;
    }
    
    void CPipe::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 CPipe::MakeInheritable(HANDLE *h, bool inheritable)
    {
        if(!h)
            return;
    
        HANDLE proc = GetCurrentProcess();
    
        DuplicateHandle(proc, *h, proc, h, 0, inheritable, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
    }
    

    Dlg.h

    // createprocessguiDlg.h: Headerdatei
    //
    
    #pragma once
    #include "afxwin.h"
    #include <vector>
    #include <string>
    #include "Pipe.h"
    #include <cstringt.h>
    
    // CcreateprocessguiDlg-Dialogfeld
    class CcreateprocessguiDlg : public CDialogEx
    {
    	// Konstruktion
    public:
    	CcreateprocessguiDlg(CWnd* pParent = NULL);	// Standardkonstruktor
    
    	// Dialogfelddaten
    	enum { IDD = IDD_CREATEPROCESSGUI_DIALOG };
    
    protected:
    	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV-Unterstützung
    
    	// Implementierung
    protected:
    	HICON m_hIcon;
    
    	// Generierte Funktionen für die Meldungstabellen
    	virtual BOOL OnInitDialog();
    	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    	afx_msg void OnPaint();
    	afx_msg HCURSOR OnQueryDragIcon();
    	DECLARE_MESSAGE_MAP()
    public:
    	CEdit m_out;
    	afx_msg void OnBnClickedOk();
    	int StartTSMuxer();
    	CString csExe;
    	const std::vector<std::string> & getResultVector() const;
    private: 
    	std::vector<std::string> result;
    	void readToVector(HANDLE rHandle); 
    	int startTSMuxerProcess(HANDLE wrHandle);
    };
    

    Dlg.cpp

    void CcreateprocessguiDlg::OnBnClickedOk()
    {
    	result.clear();
    
        CPipe readPipe;
        readPipe.MakeInheritable(CPipe::WRITE);
    
    	if(startTSMuxerProcess(readPipe.GetPipeHandle(CPipe::WRITE)) == 0)
    	{
    		// Fehler
    	}
        readPipe.ClosePipeHandle(CPipe::WRITE);
        readToVector(readPipe.GetPipeHandle(CPipe::READ));
    }
    
    int CcreateprocessguiDlg::startTSMuxerProcess(HANDLE wrHandle)
    {
    	STARTUPINFO si;
    	PROCESS_INFORMATION pi;
    	CString std_cmd;
    
    	ZeroMemory(&si,sizeof(STARTUPINFO));
    	ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));
    
    	si.cb = sizeof(STARTUPINFO);
    	si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    	si.hStdOutput = wrHandle;
    	si.hStdError  = wrHandle;
    	si.wShowWindow = SW_HIDE;
    
    	std_cmd = _T("\"C:\\Users\\admin\\Documents\\Visual Studio 2010\\Projects\\out\\Debug\\out.exe\"");
    
    	if (!CreateProcess(NULL, (LPWSTR&)std_cmd, NULL, NULL, true, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
    	{
    		return 0;
    	}
    
    	// Close any unnecessary handles.
    	CloseHandle(pi.hThread);
    	CloseHandle(pi.hProcess);
    
    	return 1; 
    }
    
    void CcreateprocessguiDlg::readToVector(HANDLE rHandle)
    {
    	char inBuf[256];
    	memset(inBuf, 0, sizeof(inBuf));
    	DWORD nBytesRead;
    	std::string tmp;
    	BOOL ret;
    	MSG msg;
    	while(TRUE)
    	{
    
    		if (!ReadFile(rHandle, inBuf, sizeof(inBuf), &nBytesRead, NULL) || !nBytesRead)
    			break;
    
    		for(int i = 0; i < nBytesRead; ++i)
    		{
    
    			if(inBuf[i] == 10)
    			{
    				result.push_back(tmp);
    				tmp.clear();
    
    				theApp.PumpMessage();
    
    				m_out.SetWindowTextW((CString)inBuf);
    
    			}
    			else if(inBuf[i] == 13)
    				;
    			else
    				tmp.push_back(inBuf[i]);
    		}
    	}  
    }
    


  • Das mit dem Thread war ne gute Idee. Jetzt hab ich Zugriff auf das Fenster.

    Hab einen Thread erstellt, in dem ich die Lese-Schleife von meiner pipe abarbeite. Dazu hätte ich noch eine Frage:

    Wie genau funktioniert die Interprozesskommunikation?
    Ich starte ja über einen Button eine Konsolenanwendung und Frage deren Ausgabe ab, um sie in der GUI darzustellen. Das vorzeitige Abbrechen der Konsolenanwendung würde ich gerne über einen Button realisieren. Allerdings hängt der Thread ja in der while-Schleife bis das Programm auf normalen Wege beendet ist. Wie genau muss ich das anstellen, dass mein thread mitbekommt dass der "Abbrechen-Button" gedrückt wurde und er aus der Schleife rausspringen soll?



  • Na ja du könntest der Threadklasse eine Variable spenden die du von außen veränderst also sprich ne BOOL-Variable und solange die TRUE ist soll der Thread laufen und wenn die FALSE ist soll er sich beenden.

    Des weitern könnte der Thread auch schaun ob die Konsolenanwendung noch läuft und wenn die net mehr läuft sich beenden.

    Aber gibt sicher noch andere elegantere Lösungen, aber das nur mal auf die schnelle als Gedankenansatz.


Anmelden zum Antworten