SetConsoleCtrlHandler funktioniert auf Windows 7 nicht mehr



  • Auf XP konnte man wunderbar das Schließen der Konsole abfangen und main selbst beenden. Bei Windows 7 wird jedoch nach dem Behandeln des Events der Prozess einfach beendet.
    Um die Hauptschleife zu beenden, verwende ich in meinem Beispiel eine globale bool -Variable, die ich optional noch mit CRITICAL_SECTION schütze. Aus der MSDN-Seite kann man nicht entnehmen, wie und wann genau die Funktion aufgerufen wird, aber normalerweise müsste das in einem anderen Thread passieren. Die Handler-Funktion wird auf jeden Fall aufgerufen und running muss dabei auf false gesetzt werden.

    #include <iostream>
    #include <Windows.h>
    using namespace std;
    
    CRITICAL_SECTION cs;
    bool running = true;
    
    #if 1
    #define LOCK(cs) EnterCriticalSection(cs)
    #define UNLOCK(cs) LeaveCriticalSection(cs)
    #else
    #define LOCK(cs) void(0)
    #define UNLOCK(cs) void(0)
    #endif
    
    bool is_running()
    {
    	bool b;
    	LOCK(&cs);
    	b = running;
    	UNLOCK(&cs);
    	return b;
    }
    
    void close()
    {
    	LOCK(&cs);
    	running = false;
    	UNLOCK(&cs);
    }
    
    BOOL WINAPI CtrlHandler(DWORD dwCtrlType)
    {
        switch (dwCtrlType)
        {
    	case CTRL_C_EVENT:
    	case CTRL_CLOSE_EVENT:
    		close();
    		return TRUE;
    
    	case CTRL_BREAK_EVENT:
    	case CTRL_LOGOFF_EVENT:
    	case CTRL_SHUTDOWN_EVENT:
    		close();
    		return FALSE;
    
    	default:
    		return FALSE;
        }
    }
    
    int main()
    {
    	InitializeCriticalSection(&cs);
        BOOL rc = SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
    	cout << "SetConsoleCtrlHandler: [" << rc << "]" << endl;
    
    	while (is_running())
    	{
    	}
    
    	//dieser Punkt wird nie erreicht (mit Haltepunkt getestet)
    
    	cout << "Closing.." << endl;
    
    	DeleteCriticalSection(&cs);
    }
    

    Kennt jemand eine Lösung?



  • Probier mal, ob das Programm mit Admin-Rechten korrekt funktioniert.

    Übrigens:

    #define LOCK(cs) void(0)
    #define UNLOCK(cs) void(0)
    

    Du kannst auch einfach schreiben:

    #define LOCK(cs)
    #define UNLOCK(cs)
    


  • oooo schrieb:

    Probier mal, ob das Programm mit Admin-Rechten korrekt funktioniert.

    Keine Veränderung.



  • Die Synchronisation in deinem Code funktioniert nicht:

    #if 0
    #define LOCK(cs) EnterCriticalSection(cs)
    #define UNLOCK(cs) LeaveCriticalSection(cs)
    #else
    #define LOCK(cs) void(0)
    #define UNLOCK(cs) void(0)
    #endif
    

    #if 0 ist immer false, also läuft der Code in den else-Zweig. Folglich wars das mit der Synchronisation. Eventuell liegt auch dort der Fehler.



  • oooo schrieb:

    Die Synchronisation in deinem Code funktioniert nicht [...] Eventuell liegt auch dort der Fehler.

    In beiden Fällen funktioniert es nicht.
    Ich hatte die Makros eingebaut, um auszuschließen, dass die Critical Section etwas mit dem Fehler zu tun hat. Inzwischen schließe ich es aus, also sollte es #if 1 heißen.



  • Ich habe leider keine Ideen mehr. Kannst du es nicht anders lösen?



  • Hallo zusammen,

    Versuch mal mit SetConsoleMode mit ENABLE_WINDOW_INPUT.

    Gruß



  • Sigie schrieb:

    Versuch mal mit SetConsoleMode mit ENABLE_WINDOW_INPUT.

    Hast du dafür ein Beispiel? So funktioniert es auf jeden Fall nicht (die Funktionen geben TRUE zurück):

    BOOL rc = -1;
    	HANDLE consoleHandle = GetStdHandle(STD_INPUT_HANDLE);
    	DWORD mode;
    	rc = GetConsoleMode(consoleHandle, &mode);
    	cout << "GetConsoleMode: [" << rc << "]" << endl;
    	rc = SetConsoleMode(consoleHandle, mode | ENABLE_WINDOW_INPUT);
    	cout << "SetConsoleMode: [" << rc << "]" << endl;
    


  • Ich habe das gleiche Problem und ich denke, dass das wahrscheinlich wieder irgend so eine dumme Sicherheitsvorkehrung ist...
    Naja dafür kann man die Console wieder in den Vollbildmodus wechseln 😃



  • Es ist möglich, das Problem durch einen weiteren Thread halbwegs zu lösen. Die Thread-Funktion erreicht das Ende und so kann man sauber aufräumen. Übrig bleiben nur globale Objekte, die man generell vermeiden sollte und das thread -Objekt, das kein Problem darstellen sollte, weil die Threads ohnehin von Windows beendet werden.

    EDIT 3: Meine aktuelle Version einer Umgehung (TProgram erfordert eine start() -Methode):

    template <class TProgram>
    	struct ConsoleThread : public boost::noncopyable
    	{
    		void join()
    		{
    			m_thread.join();
    		}
    
    		static ConsoleThread &get()
    		{
    			static ConsoleThread instance;
    			return instance;
    		}
    
    	private:
    
    		boost::thread m_thread;
    
    		ConsoleThread()
    			: m_thread(boost::bind(&ConsoleThread::threaded, this))
    		{
    #ifdef PLAINLIB_WINDOWS
    			const BOOL rc = SetConsoleCtrlHandler(&ConsoleThread::CtrlHandler, TRUE);
    			ASSERT(rc);
    #endif
    		}
    
    		void threaded()
    		{
    			TProgram program;
    			program.start();
    		}
    
    		void interrupt()
    		{
    			m_thread.interrupt();
    			join();
    		}
    
    #ifdef PLAINLIB_WINDOWS
    		static BOOL WINAPI CtrlHandler(DWORD dwCtrlType)
    		{
    			switch (dwCtrlType)
    			{
    			case CTRL_C_EVENT:
    			case CTRL_CLOSE_EVENT:
    				get().interrupt();
    				return TRUE;
    
    			case CTRL_BREAK_EVENT:
    			case CTRL_LOGOFF_EVENT:
    			case CTRL_SHUTDOWN_EVENT:
    				get().interrupt();
    				return FALSE;
    
    			default:
    				return FALSE;
    			}
    		}
    #endif
    	};
    

Anmelden zum Antworten