MDI und Callback Funktion



  • HALLO.

    ich hatte vor einer weile (23.01.2006) dieses problem mit MDI und verschiedenen CALLBACK FUNKTIONEN gepostet.

    leider bin ich seit dem nicht mehr dazu gekommen, das zu ende zu bringen. darum wollte ich jetzt noch einmal nachfragen, ob mir noch jemand helfen kann?? 🙄

    ich habe immer noch das problem, dass ich nicht weis, wie ich das gespeicherte HANDLE für meine verschiedenen CALLBACK FUNKTIONEN wieder verwenden kann. ich habe es jetzt am beispiel der F1 taste so gemacht, aber wenn ich F1 betätige, dann stürzt das program ab.

    case WM_KEYDOWN:			
    {
       pMDData = (PMDDATA) GetWindowLong (hWnd, 0);
       if (pMDData->hTab == (HWND)lParam && PAD[wParam] == TRUE)
          MessageBox (pMDData->hTab, "F1 down", "Eingabebox", MB_OK);
       return 0;				
    }
    

    DANKE. 🙂
    STICK.



  • An welcher Stelle genau stürzt er denn ab?



  • das programm macht nicht mehr weiter, wenn ich auf F1 drücke.

    STICK. 🙂



  • PAD[wParam]
    

    das dürfte in einen Speicherbereich zeigen, der nicht zu Deinem Prozess gehört.

    Blackbird



  • Du drückst dich nicht gerade präzise aus. Wie genau sieht der Fehler aus? Zugriffsverletzung? Wenn ja, wo tritt diese auf (in welcher Zeile)?



  • ja. hast ja recht, damit kann man als aussenstehender ohne quellcode vor augen nicht viel anfangen. darum hier jetzt mehr informationen:

    fehlermeldung:

    unbehandelte ausnahme in api6.exe: 0*C000000005 access violation

    an folgender stelle:

    if (pMDData->hTab == (HWND)lParam && PAD[wParam] == TRUE)

    dazu muss ich aber sagen, dass ich zuvor, also bevor ich die callbackfunktion angenfangen habe zu verändern für viele childwindows, folgenden code hatte und da gab es keine access violation meldung bei F1 betätigung. soll heissen, dass es da keine problem mit dem speicherzugriff geben müsste.

    case WM_KEYDOWN:			
    {
       PAD[wParam] == TRUE;
       return 0;				
    }
    

    okay. lasst mich bitte wissen, wenn ihr noch mehr infos zu meinem code braucht.
    DANKE!

    STICK 🙂



  • Hast du mal pMDData->hTab == (HWND)lParam oder PAD[wParam] == TRUE weggelassen`- dann sollte ja zumindest in einem Fall die Fehlermeldung ja weg sein.

    PAD[wParam] == TRUE;
    

    Was soll das tun 😕



  • Hast du mal pMDData->hTab == (HWND)lParam oder PAD[wParam] == TRUE weggelassen`

    JA. das habe ich gerade gemacht. die fehlermeldung verschwindet dann auch. aber das problem ist dann, dass natürlich bei einer betätigung der F1 taste kein zoomen mehr ermöglicht wird. denn in einer while schleife, die u.a. auch meine OpenGL scene zeichnet, befindet sich auch folgender code:

    if (PAD[VK_F1])		
       zoom +=0.2f;			
    if (PAD[VK_F2])		
       zoom -=0.2f;
    

    was soll ich denn nun machen?

    STICK.



  • Ich hatte eigentlich nicht gemeint, dass du das ganz weglässt, sondern wollte nur den Fehler einschränken, also ob es an

    pMDData->hTab == (HWND)lParam
    

    oder an

    PAD[wParam] == TRUE
    

    liegt....

    Aber ich denke, dass am ehesten PAD[wParam] den Fehler verursacht, also dass wParam vielleicht manchmal ein ungültiger Index ist 😕 Du kannst ja mal über den Debugger schauen, ob es bei jedem WM_KEYDOWN dort abstürzt und was für Werte die einzelnen Variablen dort haben...



  • HALLO.

    ich habe nun deinen ratschlag befolgt und herausgefunden, wo der fehler liegt. deine vermutung, dass es dabei an PAD[wParam] == TRUE liegt, hat sich nicht bestätigt. wenn ich nur diesen befehl in der if-bedingung lasse, stürzt das programm nicht mehr ab, führt aber auch nicht die gewünschte ZOOM funktion aus.

    bleibt nur pMDData->hTab == (HWND)lParam in der if-bedingung, dann stürzt das programm ab und gibt wieder die FEHLERMELDUNG "unbehandelte ausnahme etc.".
    über den wert von "pMDData->hTab" wird gesagt:

    CXX0017: FEHLER: Symbol "" nicht gefunden.

    ich kann damit aber leider nicht so viel anfangen. 😞

    STICK.



  • pMDData = (PMDDATA) GetWindowLong (hWnd, 0);
    

    Bekommst du hier was gültiges zurück?!



  • wenn ich mir den wert von "pMDData" anschaue, nachdem ich F1 gedrückt habe, wird folgendes ausgegeben:

    Name:      Wert:
    pMDData    0x000000000
    -hTab      CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden
    

    STICK.



  • Soetwas hatte ich schon fast erwartet - offenbar ist hWnd (ich nehme mal an, dass das einen vernünftigen Wert hat) nicht das Fensterhandle, zu dem du Werte zuvor gespeichert hast...

    Das Problem sitzt also wohl an einer anderen Stelle bzw. du liest eben zu einem falschen Fensterhandle den Wert aus 🙄



  • das fensterhandle hWnd hat folgenden wert:

    hWnd     0x000b07f8
    -unused  CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden
    

    das heisst meines erachtens, dass hWnd keinen vernünftigen wert hat und damit auch nicht das richtige fensterhandle ist ?? 😕

    STICK.

    p.s.1: wo kann ich dazu informationen im netz finden? da muss doch irgendwo was darüber geschrieben sein.
    p.s.2: ich poste hier noch einmal meinen code, vielleicht kann man daran sehen, wo etwas nicht stimmt.

    global:

    typedef struct tagMDDATA
    {
    	HWND   hTab;
    } MDDATA, *PMDDATA;
    

    in der CALLBACK FUNKTION:

    PMDDATA pMDData;
    
    case WM_CREATE:
    {
     SET_OPENGL(hWnd);
     pMDData = (PMDDATA) HeapAlloc (GetProcessHeap (),
     HEAP_ZERO_MEMORY, sizeof (MDDATA));
     SetWindowLong (hWnd, 0, (long) pMDData);	
     pMDData->hTab = hWnd;
    }
    break;
    
    case WM_KEYDOWN:			
    {
     pMDData = (PMDDATA) GetWindowLong (hWnd,0); 
     if (pMDData->hTab == (HWND)lParam && PAD[wParam] == TRUE)
     MessageBox (pMDData->hTab, "F1 down", "Eingabebox", MB_OK);
     return 0;				
    }
    
    case WM_CLOSE:
     pMDData = (PMDDATA) GetWindowLong (hWnd, 0);
     HeapFree (GetProcessHeap (), 0, pMDData);
    break;
    
    case WM_SIZE:
     pMDData = (PMDDATA) GetWindowLong (hWnd, 0);
    break;
    


  • Wie hast du deine Fensterklasse registriert?

    nIndex
    [in] Specifies the zero-based offset to the value to be set. Valid values are in the range zero through the number of bytes of extra window memory, minus the size of an integer.

    Bin mir gerade zwar nicht ganz sicher, aber ich denke, es wäre das beste bei Set-/GetWindowLong GWL_USERDATA anstelle von 0 zu verwenden...



  • meine fensterklasse habe ich in etwa so registriert:

    // DAS IST DAS FENSTER DER HAUPTANWENDUNG
        wc.cbSize = sizeof(WNDCLASSEX);
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = (WNDPROC)DialogMainWnd;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = NULL;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)(COLOR_3DSHADOW+1);
        wc.lpszMenuName = MAKEINTRESOURCE(IDM_MYMENU);
        wc.lpszClassName = MainFrame;
        wc.hIconSm = NULL;
        RegisterClassEx(&wc);
    
        // DAS IST DAS OPENGL-CHILD-FENSTER
        wc.cbSize = sizeof(WNDCLASSEX);
        wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
        wc.lpfnWndProc = (WNDPROC)DialogMDIOpenGL;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = NULL;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)(COLOR_3DSHADOW+1);
        wc.lpszMenuName = NULL;
        wc.lpszClassName = g_szChildClassName;
        wc.hIconSm = NULL;
        RegisterClassEx(&wc);
    

    In der CALLBACK-FUNKTION des HAUPTFENSTERS steht dann irgendwo:

    // SO WERDEN DIE OPENGL-CHILD-FENSTER ERZEUGT
    case WM_COMMAND:
     switch(LOWORD(wParam))
      {
       case IDM_OPENGL:
        {
        HWND hChild;
        MDICREATESTRUCT cs;
    
        ZeroMemory(&cs, sizeof(CREATESTRUCT));
        hChild = CreateWindowEx(WS_EX_MDICHILD,g_szChildClassName,buf,
        WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW,
        0,0,400,400,g_hMDIClient,NULL,GetModuleHandle(NULL),&cs);
    
        if(!hChild)
        MessageBox(NULL,"Child creation failed.","Error",MB_ICONEXCLAMATION |   
        MB_OK);
        }
     }
    


  • //-------------------------------------------------------------------------
    // Callback-Routine vom Windows Childfenster
    //-------------------------------------------------------------------------
    LRESULT CALLBACK WndProcMD (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	static HWND   hwndClient, hwndFrame;
    	HDC           hdc;
    	PAINTSTRUCT   ps;
    	RECT          rect;
    	PMDDATA       pMDData = NULL;
    
    	switch (message)
    	{
    	//####################################################################
    	case WM_CREATE:
    		char szText[64];
    		wsprintf (szText, "0x%08x", hwnd);
    		MessageBox (hwnd, szText, "Handle:", MB_OK); // nur Testausgabe
    
    		// Platz für individuelle Daten
    		pMDData = (PMDDATA) HeapAlloc (GetProcessHeap (),
    		                               HEAP_ZERO_MEMORY, sizeof (MDDATA));
    
    		// Handle des Rahmen- und des Client-Fensters festhalten:
    		hwndClient = GetParent (hwnd);
    		hwndFrame  = GetParent (hwndClient);
    		break;
    	//####################################################################
    	case WM_MDIACTIVATE:      // Menü einsetzen 
    		if (lParam == (LPARAM) hwnd)
    			SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) wData.hMenuMD,
    			(LPARAM) wData.hMenuMDWindow);
    		else
    			SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) wData.hMenuMain,
    			(LPARAM) wData.hMenuMainWindow);
    
    		DrawMenuBar (hwndFrame);
    		return 0;
    
    	//####################################################################
    	case WM_PAINT:
    		hdc = BeginPaint (hwnd, &ps);
    		EndPaint (hwnd, &ps);
    		break;
    	//####################################################################
    	case WM_CLOSE:
    		if (IDOK != MessageBox (hwnd, TEXT ("Fenster schließen?"),
    			TEXT ("MD Recorder"), MB_ICONQUESTION | MB_OKCANCEL))
    			return 0;
    		break;   // -> weiter mit DefMDIChildProc
    	//####################################################################
    	case WM_DESTROY:
    		pMDData = (PMDDATA) GetWindowLong (hwnd, 0);
    		HeapFree (GetProcessHeap (), 0, pMDData);
    		return 0;
    	}
    	// Weitergabe an DefMDIChildProc (ersetzt DefWindowProc)
    	return DefMDIChildProc (hwnd, message, wParam, lParam);
    }
    

    Hier ist ein gekuerztes Beispiel, bei case WM_MDIACTIVATE: sieht man die Verwendung vom Childfenster-Handle.

    hwndClient und hwndFrame sind static!

    Blackbird



  • HALLO BLACKBIRD.

    danke für die antwort. ich werde mir das in ruhe anschauen, um es verstehen zu können.

    GRÜSSE.
    STICK.



  • hallo BLACKBIRD.

    ich bin gerade dabei, deinen beispielcode zu verstehen. dabei ist mir die frage gekommen, woher du die informationen betreffs Childfenster-Handle hast? gibts da ein gutes buch dazu oder hast du's im netz gefunden?

    ich habe das problem ja wie du weist schon ziemlich lange und würde darum wirklich gerne mal gute literatur dazu lesen, wie ich es beheben kann. mit deinem beispielcode kann ich leider auch nicht so viel anfangen 😞
    du schreibst, dass in WM_MDIACTIVATE das Childfenster-Handle verwendet wird. ich sehe aber nicht, dass "pMDData" irgendwo steht? 😕

    DANKE.
    STICK.



  • Hallo @stick_thai,

    ... dabei ist mir die frage gekommen, woher du die informationen betreffs Childfenster-Handle hast? gibts da ein gutes buch dazu oder hast du's im netz gefunden?

    Um ehrlich zu sein - ich habs vollstaendig aus der MSDN, also der Hilfe zum VC++6.0 "abgeschrieben" und angepasst.

    ... du schreibst, dass in WM_MDIACTIVATE das Childfenster-Handle verwendet wird. ich sehe aber nicht, dass "pMDData" irgendwo steht?

    Du verwendest offenbar einen anderen Ansatz, den ich nicht kenne (oder verstehe). Der Code vom Parent und den Childs muss schon zueinander passen.
    Mein Projekt ist aber ziemlich gross, psten laesst sich das nicht.

    Meine Methode, solche Probleme zu loesen, die WAEHREND eines Projektes auftreten, ist: Parallel zum laufenden Projekt mache ich noch kleine "Hilfs-"projekte auf, in denen ich bestimmte Details naeher untersuche.
    Hier waere z.B. ein Mini-Windowsprojekt mit einem Parent und mehreren (zur Laufzeit erstellbaren) Childs angebracht, in denen nur die F1-Taste ausgewertet wird. Entweder durch "Strippen" des vorhandenen Projekts oder besser noch: von Grund auf ein Neues.

    Mehr faellt mir dazu auch nicht ein.

    Blackbird


Anmelden zum Antworten