0xC0000005: Access Violation nach CreateProcess - wieso?



  • Moin!

    Ich will aus meinem Programm heraus ein anderes Programm aufrufen.
    Das mache ich mit CreateProcess:

    char strCmd[] = "";
    		sprintf(strCmd, _T("%s"), strInhalt);
    		PROCESS_INFORMATION pi = {0};
    		STARTUPINFO si = {sizeof(si)};
     		si.wShowWindow = SW_SHOW;
    		CString strPfad = GetPfad(strInhalt);
    
    		BOOL fReturn = CreateProcess(NULL, strCmd, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, strPfad, &si, &pi);
    		if (WAIT_TIMEOUT == WaitForSingleObject(pi.hProcess, INFINITE))
    		{
    			TerminateProcess(pi.hProcess, 0);
    		}
    
    		CloseHandle(pi.hProcess);
    		CloseHandle(pi.hThread);
    

    Das Programm startet auch, aber

    1. Hängt mein Programm, bis das andere beendet wurde.
      Das liegt wohl am INFINITE, aber was muss da hin, damit es nicht hängt?
    2. Bekomme ich die Access Violation, sobald ich die Funktion verlasse.
      Wenn ich stattdessen mit WinExec arbeite, habe ich zwar das falsche Arbeitsverzeichnis für die Anwendung, aber dafür keinen Absturz. 🙄

    Hier die Meldung:

    ---------------------------
    Microsoft Visual C++
    ---------------------------
    Unbehandelte Ausnahme in MeinProg.exe (KERNEL32.DLL): 0xC0000005: Access Violation.
    ---------------------------
    OK
    ---------------------------

    Wie kann ich da nun suchen? Oder was muss ich fangen? 😕



  • @1: Ja, das liegt daran, daß du INFINTE wartest, bis der erzeugte Prozess beendet wurde. Dort kannst du stattdessen die maximale Laufzeit (in Millisekunden) angeben, die du dem anderen Programm zubilligst, bevor du es abschießen willst.

    @2: ist es wirklich nötig, das frisch aufgerufene Programm per TerminateProcess abzuschießen? (wie die MSDN sagt: "Use it only in extreme circumstances.").

    (btw, welche Anweisung löst denn die Ausnahme aus?)



  • Okay, dann nehme ich das Abschießen mal raus. Es ist nicht nur nicht notwendig sondern dieses Mal sogar unerwünscht.

    CStoll schrieb:

    (btw, welche Anweisung löst denn die Ausnahme aus?)

    Tja, so richtig kann ich es nicht verstehen, aber es ist keine "Anweisung" sondern die } der Funktion. 😕

    Wenn ich einen Breakpoint auf das zweite CloseHandle setze und F10 drücke, passiert nix.
    Nochmal F10 und dann knallts.

    Der Rest der Funktion ist eigentlich auch harmlos und wie gesagt: Mit WinExec statt CreateProcess ist alles okay.

    void CAnbindung::StarteHno()
    {
    	CWaitCursor csr;
    	CString strInhalt = GetHnoCmd();
    	if (strInhalt.IsEmpty())
    	{
    		return;
    	}
    
    	if (strInhalt.Right(4) == _T(".trf"))
    	{	// Es ist das alte HNO
    		// Pfad und Laufwerk rausfinden
    		CString strPfad = GetPfad(strInhalt);
    		CString strPfad2 = strPfad.Right(strPfad.GetLength() -3);
    		strPfad = strPfad.Left(2);
    		::WinExec(strInhalt + _T(" ") + strPfad + _T(" ") + strPfad2, SW_SHOW);
    	}
    	else
    	{
    		char strCmd[] = "";
    		sprintf(strCmd, _T("%s"), strInhalt);
    		PROCESS_INFORMATION pi = {0};
    		STARTUPINFO si = {sizeof(si)};
     		si.wShowWindow = SW_SHOW;
    		CString strPfad = GetPfad(strInhalt);
    
    		BOOL fReturn = CreateProcess(NULL, strCmd, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, strPfad, &si, &pi);
    //		if (WAIT_TIMEOUT == WaitForSingleObject(pi.hProcess, INFINITE))
    //		{
    //			TerminateProcess(pi.hProcess, 0);
    //		}
    
    		CloseHandle(pi.hProcess);
    		CloseHandle(pi.hThread);
    	}
    }
    

  • Mod

    Dieser Code ist die Ursache:

    char strCmd[] = ""; 
    sprintf(strCmd, _T("%s"), strInhalt);
    

    Du kopierst in enen String der 1 Zeichen lang ist mehr hinein!



  • estartu schrieb:

    char strCmd[] = "";
    		sprintf(strCmd, _T("%s"), strInhalt);
    

    typischer anfängerfehler, strCmd[] ist nur ein byte gross 😉



  • Mist, wieso hat es überhaupt funktioniert?
    Ich hatte das noch im Verdacht, sah im Debugger aber gut aus.

    Okay, wie geht es richtig? GetBuffer will nämlich auch nicht.

    Ist übrigens nicht wirklich ein Anfängerfehler, nur eine weitere Episode eines jahrelange Kampfes mit C-Zeichenketten. 🙄



  • Eigentlich sollte GetBuffer() der richtige Ansatz sein, wie hast du es denn verwendet?



  • etwa so...

    BOOL fReturn = CreateProcess(NULL, strInhalt.GetBuffer(_MAX_PATH), ...);
    

    🙂



  • Versucht habe ich:

    char strCmd[] = strInhalt.GetBuffer(strInhalt.GetLength());
    

    das gab aber

    error C2440: 'initializing' : 'char *' kann nicht in 'char []' konvertiert werden
    Es gibt keine Konvertierungen von Arraytypen, obwohl es Konvertierungen von Verweisen oder Zeigern in Arrays gibt

    Aber das von vista funktioniert. 🙂

    Dankeschön! 🙂

    PS: Wenn ich meine Lösung direkt in den Funktionsaufruf schreibe, funktioniert die auch.
    Wieso das blos wieder? 🙄



  • ReleaseBuffer nicht vergessen!

    @estartu: bei solchen Fehlern kann es interessant sein mit F11 zu steppen statt mit F10. So steppst du nämlich auch in die aufgerufenen Destruktor hinein und kannst so möglicherweise herausfinden, in welcher Klasse es knallt.



  • Die Größe eines Arrays muß zur Compilezeit feststehen (wenn du ein String-Literal übergibst, kann der Compiler daraus die nötige Größe berechnen), mit einem Zeiger ( char*strCmd=...; ) wäre dir das nicht passiert.



  • estartu schrieb:

    PS: Wenn ich meine Lösung direkt in den Funktionsaufruf schreibe, funktioniert die auch.
    Wieso das blos wieder? 🙄

    Naja, weil diese Funktion eben einen char* erwartet. Was du gemacht hast ist eh Quatsch, wieso hast du strCmd überhaupt als char[] deklariert und nciht als char*?



  • Ich hab das so, weil es an anderer Stelle so mal funktioniert hat. 🙄
    Wie man merkt, stehe ich mit dem Code auf Kriegsfuß und nehme da meine schon fertige Lösung, sofern vorhanden. (Das kann durchaus auch hier aus dem Forum sein...)



  • estartu schrieb:

    PS: Wenn ich meine Lösung direkt in den Funktionsaufruf schreibe, funktioniert die auch.
    Wieso das blos wieder? 🙄

    weil es einen unterschied zwischen pointer und array gibt.
    du kannst den inhalt eines arrays nicht ändern oder es initialisieren, indem du ihm einen pointer zuweist.
    wenn du bei einer fuktion, die einen char* erwartet, einen array-bezeichner einsetzt, dann wird automatisch die adresse des ersten element des arrays übergeben (und nicht das array selbst).

    huch? ich bin ja viel zu spät 😞



  • dEUs schrieb:

    ReleaseBuffer nicht vergessen!

    das braucht man nur, wenn man den inhalt des CStrings über den pointer verändern will, den GetBuffer() lieferte.
    in estartus fall ist es nicht nötig.


  • Mod

    Das ist eigentlich nicht das Problem. Hier wird ja der Stack überschrieben. Es müsste also sofort auffallen, das die Varoablenund der Callstack futssch sind.

    Es müsste noch mehr auffallen, da in der Debugversion sofort die Frame-Guard Checker anspringen und einen ASSERT feuern!


Log in to reply