DLL bleibt nicht in Nachrichtenschleife hängen



  • Ich hab mein gesamtes Programm in der DLL (ich könnte, also die DLlMain einfach zu WinMain ändern und hätte nen normales .exe Programm), diese wird von ner .exe geladen und ich dachte mir, ich kann in der dll ganz normal mit Fenstern und ner Nachrichtenschleife arbeiten.
    Aber die Funktion in der die Nachrichtenschleife steckt, wird nicht so lange offen gehalten bis sie durch PostQuitMessage(0) beendet wird, sondern die Funktion beendet direkt.
    Die GUI und alles bleibt, aber erhalten bis es durch die zerstörten Objekte zu nem Fehler kommt.

    Der Code der DllMain

    int APIENTRY DllMain (HINSTANCE hinst, DWORD fdwReason, PVOID pvReserved)
    {
        switch (fdwReason)
        {
            //Die DLL wird in den Adressraum des prozesses eingeblendet
            case DLL_PROCESS_ATTACH:
            {
                Frame* window = new Frame;
                App* app      = new App;
    
                //Initialisierung
                Singleton::getInstance().setHinst (hinst);
                Singleton::getInstance().setFramePtr (window);
                Singleton::getInstance().setAppPtr (app);
    
                //Fenster initialisieren
                window->init ();
                //App starten
                app->setup ();
                //Nachrichtenschleife starten
                window->run (); // HIER MÜSSTE DAS PROGRAMM STEHEN BLEIBEN TUT ES ABER NICHT
                //App beenden
                app->remove ();
    
                delete window;
                delete App;
    
                break;
            }
        }
        return TRUE;
    }
    

    Die Funktion run

    bool Frame::run ()
    {	MSG msg;
    	//Nachrichtenschleife starten
    	while (GetMessage (&msg, NULL, 0, 0)) 
    	{ 
    		TranslateMessage (&msg); 
    		DispatchMessage (&msg); 
    	}
        return true;
    }
    

    Und die WndProc für die Nachrichten

    LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    	{
    		switch (msg)
    		{
    			case WM_CREATE:
    				// create
    				return 0;
    
    			case WM_DESTROY:
    				PostQuitMessage (0);
    				return 0;
    
    		}
    
    		return DefWindowProc (hwnd, msg, wparam, lparam);
    	}
    

    Die .exe die die DLL lädt

    include <windows.h>
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain (IN HINSTANCE hinst, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
    {
    	static TCHAR szAppName[] = TEXT ("KeyLogger"); 
    	MSG          msg; 
    	HWND hwnd;
    	WNDCLASSEX   wndclassex = {0}; 
    
    	wndclassex.cbSize        = sizeof(WNDCLASSEX); 
    	wndclassex.style         = CS_HREDRAW | CS_VREDRAW; 
    	wndclassex.lpfnWndProc   = WndProc; 
    	wndclassex.cbClsExtra    = 0; 
    	wndclassex.cbWndExtra    = 0; 
    	wndclassex.hInstance     = hinst; 
    	wndclassex.hIcon         = LoadIcon (NULL, IDI_APPLICATION); 
    	wndclassex.hCursor       = LoadCursor (NULL, IDC_ARROW); 
    	wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); 
    	wndclassex.lpszMenuName  = NULL; 
    	wndclassex.lpszClassName = szAppName; 
    	wndclassex.hIconSm       = wndclassex.hIcon; 
    
    	if (!RegisterClassEx (&wndclassex)) 
    	{ 
    		MessageBox (NULL, TEXT ("RegisterClassEx fehlgeschlagen!"), szAppName, MB_ICONERROR); 
    		return 0; 
    	}
    
    	hwnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW, // erweiterter Fensterstil 
    		szAppName, // Name der Fensterklasse 
    		szAppName, // Fenstertitel 
    		WS_OVERLAPPEDWINDOW, // Fensterstil 
    		350, // X-Position des Fensters .... CW_USEDEFAULT für Default                      
    		300, // Y-Position des Fensters        
    		180, // Fensterbreite                  
    		120, // Fensterhöhe                 
    		NULL, // übergeordnetes Fenster 
    		NULL, // Menü            
    		hinst, // Programm-Kopiezähler (Programm-ID)             
    		NULL); // zusätzliche Parameter 
    
    	ShowWindow (hwnd, SW_SHOW); 
    	UpdateWindow (hwnd); 
    
    	HMODULE myLib = LoadLibrary ("app.dll");
    
    	if (myLib == NULL)
    		MessageBox (0, "error: mylib == NULL", "error", MB_OK);
    
    	while (GetMessage (&msg, NULL, 0, 0)) 
    	{ 
    		TranslateMessage (&msg); 
    		DispatchMessage (&msg); 
    	} 
    
    	FreeLibrary (myLib);
    	return 0;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    {
    	switch (msg)
    	{
    		case WM_DESTROY:
    			PostQuitMessage (0);
    			return 0;
    	}
    	return DefWindowProc (hwnd, msg, wparam, lparam); 
    }
    

    Und jetzt die große Preisfrage: Was muss ich tun, damit die DLL in der Schleife hängen bleibt?



  • Kann's sein, dass du das falsche hInstance verwendest?



  • Ne in der Winmain benutze ich ja das aus der WinMain parameterliste und in der DllMain das aus der DllMain parameterliste



  • Vielleicht solltest du überall die hInstance vom exe verwenden.



  • Sowas programmiert man doch nicht direkt in die DllMain rein. 🙄



  • @Ringding hast recht, habe mir vorhin mal den Petzold organisiert und da stehts bei den DLLs auch dabei, man braucht in der DLL das HINSTANCE des Hauptprozesses, da die Nachrichten weiterhin über den laufen.

    Kann ich mit ner Winapi Funktion das HINSTANCE meines Programmes ermitteln?
    Wäre schöner, als ne Funktion zu exportieren und im Hauptprogramm aufzurufen.



  • HINSTANCE von EXE => GetModuleHandle(NULL);



  • Danke, er kann das Handle zwar auslesen, aber die Message-Loop wird weiterhin sofort beendet 😞



  • Ich werd jetzt einfach in DLL_PROCESS_ATTACH nen Thread starten, dann hab ich ne eigene MessageLoop und die Probleme dürften erledigt sein. Damit die Fenster, aber meinem Thread gehören bzw. dessen MessageLoop muss ich ja beim erstellen das HINSTANCE Handle angeben, aber wie bekomm ich das von meinem Thread?
    Geht das mit GetModuleHandle (NULL)? Oder gibts dafür ne andere Variante?



  • hast du schonmal versucht das Fenster und die Message Loop ausserhalb der DllMain zu tun? also in einer seperaten Funktion



  • man19 schrieb:

    hast du schonmal versucht das Fenster und die Message Loop ausserhalb der DllMain zu tun? also in einer seperaten Funktion

    Das Fenster und die Funktion sind ja seperat und ob DllMain jetzt noch ne funktion start() aufruft die genau den gleichen Code hat ändert ja nix daran, dass GetMessage in Frame::run() nicht funktioniert (PeekMessage geht, dann hab ich aber immer die Sanduhr)



  • Also mit nem Thread funktioniert es, allerdings bekommt mein Programm ständig WM_PAINT Nachrichten was dazu führt, dass ständig die Sanduhr un der normale Mauszeiger wechselt und erst, wenn ich das Fenster schließe sehe ich die MSG-Boxen die aus WM_PAINT kommen.

    Könnt ihr euch das mal ansehen, woran es liegen könnt (bin aber immerhin auf dem richtigen weg, da es jetzt in der MSG Loop bleibt)?

    #include <windows.h>
    #include <process.h>
    
    LRESULT CALLBACK WProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    {
    	switch (msg)
    	{
    	case WM_CREATE:
    		MessageBox (0,"WM_Create", "msg", MB_OK);
    		return 0;
    	case WM_PAINT:
    		MessageBox (0,"WM_Paint", "msg", MB_OK);
    		return 0;
    	case WM_DESTROY:
    		MessageBox (0,"WM_Destroy", "msg", MB_OK);
    		PostQuitMessage (0);
    		return 0;
    	}
    	return DefWindowProc (hwnd, msg, wparam, lparam); 
    }
    
    void Thread (PVOID pvoid)
    {
    	static TCHAR szAppName[] = TEXT ("DLL"); 
    	MSG          msg; 
    	HWND hWnd;
    	WNDCLASSEX   wndclassex = {0}; 
    
    	wndclassex.cbSize        = sizeof(WNDCLASSEX); 
    	wndclassex.style         = CS_HREDRAW | CS_VREDRAW; 
    	wndclassex.lpfnWndProc   = WProc; 
    	wndclassex.cbClsExtra    = 0; 
    	wndclassex.cbWndExtra    = 0; 
    	wndclassex.hInstance     = (HINSTANCE)pvoid; 
    	wndclassex.hIcon         = LoadIcon (NULL, IDI_APPLICATION); 
    	wndclassex.hCursor       = LoadCursor (NULL, IDC_ARROW); 
    	wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); 
    	wndclassex.lpszMenuName  = NULL; 
    	wndclassex.lpszClassName = szAppName; 
    	wndclassex.hIconSm       = wndclassex.hIcon; 
    
    	if (!RegisterClassEx (&wndclassex)) 
    	{ 
    		MessageBox (NULL, TEXT ("DLL RegisterClassEx fehlgeschlagen!"), szAppName, MB_ICONERROR); 
    		return;
    	}
    
    	hWnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW, // erweiterter Fensterstil 
    		szAppName, // Name der Fensterklasse 
    		szAppName, // Fenstertitel 
    		WS_OVERLAPPEDWINDOW, // Fensterstil 
    		350, // X-Position des Fensters .... CW_USEDEFAULT für Default                      
    		300, // Y-Position des Fensters        
    		180, // Fensterbreite                  
    		120, // Fensterhöhe                 
    		NULL, // übergeordnetes Fenster 
    		NULL, // Menü            
    		(HINSTANCE)pvoid, // Programm-Kopiezähler (Programm-ID)             
    		NULL); // zusätzliche Parameter 
    	if (!hWnd)
    	{
    		MessageBox (0, "CreateWindow in DLL fehlgeschlagen", "info", MB_OK);
    		return;
    	}
    	ShowWindow (hWnd, SW_SHOW); 
    	UpdateWindow (hWnd); 
    
    	while (GetMessage (&msg, NULL, 0, 0)) 
    	{ 
    		TranslateMessage (&msg); 
    		DispatchMessage (&msg); 
    	} 
    }
    
    int APIENTRY DllMain (HINSTANCE hinst, DWORD fdwReason, PVOID pvReserved)
    {
    	switch (fdwReason)
    	{
    		case DLL_PROCESS_ATTACH:
    			_beginthread (Thread, 0,  hinst);
    			break;
    		case DLL_PROCESS_DETACH:
    			_endthread ();
    			break;
    	}
    	return TRUE;
    }
    


  • Zur Message-Loop in DllMain:

    The entry-point function should perform only simple initialization or termination tasks.

    Aber warum du mit PeekMessage Nachrichten bekommst und mit GetMessage nicht, ist auch seltsam 😕



  • Das Beispiel aus meinem letzten Posting geht ja soweit, nur bekomm ich eben ununterbrochen WM_PAINT nachrichten, welche aber erst nach beenden des Fensters angezeigt werden. Aber das WM_DESTROY bekommt er nicht mit, da es anscheinend ab dem ersten WM_PAINT hängt.

    Die exe und die dll sind beide als multithreaded Programme kompiliert, also daran kann es nicht liegen.



  • Du hast wohl BeginPaint und EndPaint vergessen, oder lass DefWindowProc das Regeln. :p



  • int APIENTRY DllMain (HINSTANCE hinst, DWORD fdwReason, PVOID pvReserved)
    {
        switch (fdwReason)
        {
            case DLL_PROCESS_ATTACH:
                _beginthread (Thread, 0,  hinst);
                break;
            case DLL_PROCESS_DETACH:
                _endthread ();
                break;
        }
        return TRUE;
    }
    

    Bad idea. You should have a dedicated initialization function in the DLL
    that creates the thread and the dialog. You should only perform simple
    initializations in DllMain, read the documentation on DllMain.



  • painter schrieb:

    Du hast wohl BeginPaint und EndPaint vergessen, oder lass DefWindowProc das Regeln. :p

    Wow das klappt ja damit wirklich 😮
    hab nicht gewusst, dass man in WM_PAINT "zwangsweise" beginpaint und endpaint benutzen muss

    Danke 🙂



  • Windowsprogger schrieb:

    int APIENTRY DllMain (HINSTANCE hinst, DWORD fdwReason, PVOID pvReserved)
    {
        switch (fdwReason)
        {
            case DLL_PROCESS_ATTACH:
                _beginthread (Thread, 0,  hinst);
                break;
            case DLL_PROCESS_DETACH:
                _endthread ();
                break;
        }
        return TRUE;
    }
    

    Bad idea. You should have a dedicated initialization function in the DLL
    that creates the thread and the dialog. You should only perform simple
    initializations in DllMain, read the documentation on DllMain.

    Where else should I create the thread when I don't want to export a function for creating the thread und dialog.
    The only thing would be an asynchronous function which creates them else it would be the same thing only that DllMain
    calls another function which takes the same amount of time to initialize them.



  • Where else should I create the thread when I don't want to export a function for creating the thread und dialog.

    Ok, if you don't want to export a seperate function, live with your dirty design. 👍 👍



  • Windowsprogger schrieb:

    Where else should I create the thread when I don't want to export a function for creating the thread und dialog.

    Ok, if you don't want to export a seperate function, live with your dirty design. 👍 👍

    It seems that I dont have the choide cause I've just discovered, that directly after the DLL_PROCESS_ATTACH call I get a DLL_PROCESS_DETACH call which destroys the thread and causes some trouble in my program (I get new DLL_PROCESS_ATTACH calls, but normally there should be only one).


Anmelden zum Antworten