externes Programm vorzeitig beenden



  • Hallo Leute, habe mal wieder ein Problem:

    Ich starte in meiner Anwendung eine externe exe-Datei, die etwas ausführt (was genau ist eigentlich egal). Das ganze wird durch einen Thread aufgerufen, damit ich noch was anderes machen kann. So nun gibt es aber das Problem, wenn ich die Hauptanwendung beende, läuft das externe Programm weiter. Wie kann ich das vorzeitig stoppen??

    So rufe ich das externe Programm in dem Thread auf:

    SHELLEXECUTEINFO ShExecInfo = {0};
    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    ShExecInfo.hwnd = NULL;
    ShExecInfo.lpVerb = "open";
    //Pfad und Programmname zusammensetzen
    CString alles = pfad+name;
    ShExecInfo.lpFile = alles;		
    ShExecInfo.lpParameters = d;	
    ShExecInfo.lpDirectory = pfad;
    ShExecInfo.nShow = SW_HIDE;
    ShExecInfo.hInstApp = NULL;	
    ShellExecuteEx(&ShExecInfo);
    WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
    

    Kann mir da jemand helfen??



  • exit(0)?



  • Du kannst versuchen ein WM_CLOSE an das Hauptfenster zu senden.
    Am schlimmsten Falls kannst Du TerminateProcess ausführen...



  • Das verstehe es jetzt nicht ganz. Ich will doch eigentlich dem ext. Programm sagen, daß es sich beenden soll. Also wenn ich z.B. OnClose() in der Hauptanwendung aufrufe. Da muß doch das ext. Programm irgendwie eine Nachricht bekommen??



  • Nö, nciht automatisch. Wäre ja Unfug. Aber Jochen hat dir ja schon zwei Möglichkeiten aufgezeigt, wie du es "per Hand" veranlassen kannst:
    Die nette Methode: "Magst dich beenden?" und der Kopfschuß 😮



  • evil-peter schrieb:

    Da muß doch das ext. Programm irgendwie eine Nachricht bekommen??

    Hab ich doch eigentlich auch gesagt (oder zumindest gemeint 😉 )... Du musst dem externen Programm eine WM_CLOSE Nachricht an das Hauptfenster schicken! (Es sei denn es handlet sich dabei um eine Consolen-Anwendung)...



  • So wollte ich das machen:

    void CTest_Dialog::OnClose()
    {
    
    int iGedrueckt; 
    
        iGedrueckt = MessageBox("Test wirklich abbrechen?","", MB_YESNO | MB_ICONQUESTION); 
    
    	CFile file;
        switch (iGedrueckt) 
        { 
            case IDYES: 
    
    			file.Remove(pfad + "\\XML\\" + user.u_strUserPath + "\\" + "Ausgabe.xml");
    			file.Remove(pfad + "\\XML\\" + user.u_strUserPath + "\\" + "Eingabe.xml");
    			file.Remove(pfad + "\\XML\\" + user.u_strUserPath + "\\" + "Auswertung.xml");
    			file.Remove(pfad + "\\XML\\" + user.u_strUserPath + "\\" + "Auswertung.xls");
    			m_fFont.DeleteObject();
    			t_fFont.DeleteObject();
    			t_bmpHintergrund.DeleteObject();
    			EndThread = true;
    			TerminateProcess(m_SpeechThread->ShExecInfo.hProcess, 0);//das ist der Prozess, um den es geht
                OnOK(); 
                break; 
            case IDNO: 
    			return;
                break; 
        }
    	CDialog::OnClose();
    }
    

    Nun rufe ich das OnClose in der Hauptanwendung auf und wollte halt von hier aus den Prozess beenden. Geht aber so nicht. Wie mache ich das richtig???

    Edit: Es ist eine Konsolenanwendung die im Hintergrund läuft!!!



  • Jetzt habe ich das Programm mal manuell in der Konsole gestartet und dann einfach das Konsolenfenster wieder geschlossen. Und dann beendet sich das Programm. Würde es nicht vielleicht auch gehen, daß ich das in meinem Programm auch irgendwie mache???



  • Kann mir den keiner bei dem Problem helfen? Ist doch bestimmt nicht unlösbar!

    Bitte Bitte!!!



  • starte die console mit CreateProcess dadurch erhälst du die ProcessID(pInfo) die du brauchst um den process wieder zu zerstöhren.

    //Processinformationen zum zerstöhren der Anwendung
    	PROCESS_INFORMATION pInfo; 
    	ZeroMemory(&pInfo,sizeof(pInfo));
    
    	char cExecute[MAX_PATH] = "C:\\Pfad\\zur\\Console.exe";
    	//Erstelle die Startinformationen für das Consolenfenster
    	STARTUPINFO sInfo; 
    	ZeroMemory(&sInfo,sizeof(sInfo));
    	sInfo.cb			= sizeof(sInfo);
    	sInfo.dwFlags		=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
    	sInfo.hStdInput		= NULL;		
    	sInfo.wShowWindow	= SW_HIDE;	
    
    	//Erstelle den Consloenprocess
    	CreateProcess(0,cExecute,0,0,TRUE,
              NORMAL_PRIORITY_CLASS,0,0,&sInfo,&pInfo);
    
    HANDLE hProcess = OpenProcess(  PROCESS_TERMINATE, FALSE, [b]pInfo.dwProcessId[/b]);
    
        if( NULL != hProcess )
        {
    		TerminateProcess( hProcess, 0 );
    	}
    	CloseHandle( hProcess );
    


  • Ich hoffe da kann ich dann aber auch alle Angaben machen, wie bei ShellExecuteEx!
    Danke erstmal.

    Gruß



  • Ich dachte mir das schon, daß es da Probleme geben wird. Ich hatte ja extra ShellExecuteEx damals verwendet, weil meine Konsolenanwendung auch Parameter zum starten braucht.
    Wie kann ich die den bei CreateProcess einbauen?
    Und außerdem benutze ich ja auch CStrings. Die müssen ja dann auch noch irgendwie in char konvertiert werden.
    Und wie soll das gehen?
    Ich kenne nur die konvertierung in char* und da braucht man ja auch die Länge des Strings?



  • Jetzt habe ich das erstmal zum laufen gebracht. Es gibt aber noch Probleme.
    Einmal wird das Konsolenprogramm mit verschiedenen Kommandozeilen aufgerufen. Nun verlangt CreateProcess aber einen konstanten String zum Aufruf des Programms bzw. Prozesses.
    Wie kann ich das nun lösen?



  • für CString in char

    CString sString = "Ich werd nen char";
    char *cString = sString.GetBuffer(sString.GetLength());
    MessageBox(cString );
    

    für die parameterübergabe an eine console kannst du den/die parameter mit in den Parameter 2 (LPCWSTR lpszCmdLine) der CreateProcess Function packen.

    CString sExecute = "C:\\Path\\Console.exe";
    CString sArgumente = "/Argument /Argument";//Wie die eizelnen argumente an die console übergeben werden bitte bei deiner console kucken
    
    char cExecute[MAXPATH];
    sprintf(cExecute,"%s %s",sExecute,sArgumente);
    
    ...
    CreateProcess(0,cExecute,0,0,TRUE,
          NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW,0,0,&sInfo,&pInfo);//
    ...
    

    um andere parameter an deine console zu übergeben kuck dir mal bitte die STARTUPINFO struckur & die übergabeparameter der CreateProcess Funktion genauer an

    mfg
    LowFly



  • Wunderbar. das mit der Umwandlung hatte ich so noch nicht gekannt. Das mit dem Parameter klappte ja auch schon(siehe letzten Beitrag).
    Jetzt aber doch noch ein Problem. Im Normalbetrieb soll der Prozess nicht vorzeitig beendet werden. Es wird aber nach dem Beenden eine Variable gesetzt die die Enter-Taste freigibt, damit wieder ein Prozess beim drücken ablaufen kann. Wie kriege ich heraus, wann der Prozess sich selber beendet hat?



  • wenn mich nicht alles täuscht aber ich weis es nicht genau kannst die über die STARTUPINFO
    festlegen ob der zu erstellende process überwacht werden soll/kann/darf. das gibst du dem mit auf den weg.
    dann muste dir nen thead mit WaitForSingleObject baun der dir das Handle (PROCESS_INFORMATION) auf den Process überwacht.
    wenn das handle auf den thread nicht mehr existiert weist du das der process beendet ist.
    kuck dir mal dieses beispiel

    mfg
    LowFly



  • OK habe ich jetzt. CreateProcess gibt ja einen Wert zurück. So nun müßte alles Klar sei.
    Danke noch mal für die vielen Antworten!!!

    Beste Grüße!!



  • LowFly schrieb:

    wenn mich nicht alles täuscht aber ich weis es nicht genau kannst die über die STARTUPINFO
    festlegen ob der zu erstellende process überwacht werden soll/kann/darf. das gibst du dem mit auf den weg.
    dann muste dir nen thead mit WaitForSingleObject baun der dir das Handle (PROCESS_INFORMATION) auf den Process überwacht.
    wenn das handle auf den thread nicht mehr existiert weist du das der process beendet ist.
    kuck dir mal dieses beispiel

    mfg
    LowFly

    So nun habe ich das WaitForSingleObject in einen Thread ausgelagert und das klappt so ganz gut. Auch mit den ganzen Nachrichten usw. Aber jetzt kommt ein Debug Assertion Failed an der Stelle, wenn ich das ganze jetzt vorzeitig beende! Also beim return 0 vom Thread. Wie bekomme ich das den nun weg???



  • kann es vieleicht sein das da noch ein thread läuft wenn du das prog beendest.
    wenn du nen thread erstellst bendest du ihn mit AfxEndThread
    Ich vermute mal du erstellst einen thread in der art wie unten folgt

    static DWORD m_dwThreadExitCode;//*.h o. *cpp auserhalg jeder funktion

    UINT CDialog::thrFunction(LPVOID pParam)//Eigendliche thread funktion
    {
    CDialog* pDialog = (CDialog*) pParam;
    ::GetExitCodeThread(pDialog, &m_dwThreadExitCode);
    .....

    }

    AfxEndThread(m_dwThreadExitCode,TRUE);//In die Funktion mit der du deinen dialog bendest



  • Das ist meine Thread-Run. Hier habe ich das WaitForSingleObject von dem Prozess (also von CreateProcess) "ausgelagert":

    int CWarten::Run()
    {
    
    	WaitForSingleObject(m_pOwner->pInfo.hProcess,INFINITE);
        CloseHandle(m_pOwner->pInfo.hThread);
        CloseHandle(m_pOwner->pInfo.hProcess);
    
    	m_pOwner->PostMessage(WM_ENDE_SPEECH,0,0);
    
    	return 0;
    }
    

    Den Thread selber starte ich so:

    void CTest_Dialog::WartenThread(void)
    {
    	BOOL a = GetExitCodeThread(m_WartenThread,test1);
    	if(a==FALSE)
    	{
    	m_WartenThread = (CWarten*)AfxBeginThread(RUNTIME_CLASS(CWarten), NULL, 0, CREATE_SUSPENDED); 
    	m_WartenThread->SetOwner(this);
    	m_WartenThread->ResumeThread();
    	}
    	else{
    	}
    
    }
    

    So und nun beende ich ja den Thread nicht richtig sauber, wenn ich einfach das Programm beende. Ich weiß jetzt nicht so richtig, wie ich das erklären soll! Sbald ich das Programm ganz normal ablaufen lasse, ist ja auch alles in Ordnung. Weil halt der Process der vom Thread gesteuert wird sich ja richtig beendet. Aber wenn ich den Process beende, weiß ja auch der Thread nicht mehr vozu er da ist und deshalb muß der Thread halt vorzeitig beendet werden. Ja, aber wie????



  • Ich werde noch verrückt!! Wieso geht den das nicht richtig!??! Ich könnte ja nun sagen: Bei der Release-Version funktioniert es Ja. Das ist aber irgendwie nicht so richtig befriedigend. Soll ich etwa noch mal den kompletten Code posten???


Anmelden zum Antworten