LPDIRECTDRAW->Lock(...) Fehler



  • Hi
    also ich erzeuge zunächst das DirectDraw Objekt und das Surface wie es eigentlich überall gemacht wird (die FAILEDergebnisse überprüfe ich natürlich):

    if (FAILED(DirectDrawCreateEx(NULL, (void **)&lpdd7, IID_IDirectDraw7, NULL)))
    {
    	return(0);
    }
    
    if (FAILED(lpdd7->SetCooperativeLevel(main_window_handle, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)))
    	return 0;
    
    if (FAILED(lpdd7->SetDisplayMode(1024,768,32,0,0)))
    	return 0;
    
    ZeroMemory(&ddsurfdesc, sizeof(ddsurfdesc));
    
    ddsurfdesc.dwSize = sizeof(ddsurfdesc);
    ddsurfdesc.dwFlags = DDSD_CAPS;
    ddsurfdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
    
    if (FAILED(lpdd7->CreateSurface(&ddsurfdesc, &lpddsprimary,NULL)))
    return 0;
    

    32 Bit deshalb, weil meine Grafikkarte anscheinend kein 24 Bit unterstützt und mir 16 und 8 Bit zu wenig ist. (Bei 24 Bit hatte ich immer eine Meldung, dass auf den Speicher nicht zugegriffen werden kann, mit 32 Bit passiert dies nicht mehr)
    Jetzt will ich auf das Surface malen bzw. ein Pixel plotten. Dazu muss ich natürlich erstmal das Surface locken:

    memset(&ddsurfdesc, 0, sizeof(ddsurfdesc));
    ddsurfdesc.dwSize = sizeof(ddsurfdesc);
    
    if (FAILED(lpddsprimary->Lock(NULL, &ddsurfdesc, DDLOCK_WAIT | 
                DDLOCK_SURFACEMEMORYPTR, NULL))) 
        return 0;
    
    lpddsprimary->Unlock(NULL);
    

    Das FAILED Makro liefert mir aber einen Fehler. Und wenn ich zwischen Lock und Unlock auf den Speicher zugreifen will (über ddsurfdesc.lpSurface), bekomme ich die Meldung, dass nicht in den Speicher geschrieben werden kann.
    Ich weiß echt nicht wo der Fehler steckt. Habe schon Tage gebraucht, um den Fehler bei den 24 Bit zu finden und jetzt habe ich wieder alles so gemacht, wie es in den Beispielcodes aus einem Buch drinsteht und es klappt wieder irgendwas nicht.
    Naja ich hoffe mal ihr seht irgendwo einen Fehler. Werde natürlich auch in der Zwischenzeit weiterprobieren...

    PS: Natürlich Release ich auch alle Objekte am Schluss wieder, also daran kann es auch nicht liegen.



  • Musste man nicht explizit angeben, dass man schreiben möchte?
    Also DDLOCK_WRITEONLY.



  • mhh laut Buch nicht und hat in diesem Fall auch keine Veränderung hervorgerufen.
    Komisch ist halt, dass ohne Lock keine Fehler auftauchen. Erst wenn ich Locke und Unlocke bekomme ich durch das Failed Makro einen Fehler (das Makro um den Lock). Und wenn ich das Makro weglasse und zwischen Lock und Unlock schreiben will, dann bekomme ich die Meldung, dass in den Speicher nicht geschrieben werden kann.
    Und am Displaymode sollte es auch nicht liegen denn 32 Bit unterstützt die Graka auf jeden Fall.



  • Ok ich hab neue Erkenntnisse gewonnen... Nachdem ich den Code aus dem Buch kopiert habe, das schreiben in den Speicher. Das Failed Makro liefert auch keinen Fehler, solange ich das Fenster geöffnet lasse. Sobald ich das Fenster minimiere, wird ein Fehler gemeldet sprich das FAILED Makro gibt true zurück.
    Wie lässt sich das erklären?
    Und sobald ich das Fenster wieder Maximiere, wird nichts mehr auf das Surface gezeichnet.





  • Hast du es auch schon mal mit Restore() versucht, nach dem das flipen fehlgeschlagen hat?

    EDIT: ahh, da war jemand schneller 🙂



  • mhhh ok wenn ich das richtig verstehe müsste ich in meiner Gameschleife überprüfen ob der Surfacememory verloren gegangen ist und wenn ja, dann muss ich Restore() aufrufen.
    Und der Surfacememory geht dann verloren, sobald ich das Fenster minimiere, richtig?
    Und 2. Problem:
    Wie ich jetzt rausgefunden habe, bekomme ich nur dann eine Meldung, dass nicht in den Speicher geschrieben werden kann ("Die Anweisung ... verweist auf Speicher in ... . Der Vorgang written konnte nicht durchgeführt werden."), wenn ich den Lock nicht mit dem FAILED Makro überprüfe. Sprich wenn ich das FAILED Makro um den Lock setze, läuft alles wunderbar. Lasse ich es weg, läuft das Programm, aber beim Beenden kommt die Meldung von Windows. Allerdings verstehe ich nicht, warum ich unbedingt das FAILED Makro setzen muss:

    //funktioniert:
    if (FAILED(lpddsprimary->Lock(...)))
    return 0;
    
    //funktioniert nicht (Fehlermeldung von Windows):
    lpddsprimary->Lock(...);
    

    EDIT: Jetzt hab ich es glaube ich: Sobald ich das Fenster schließe, geht der Speicher verloren. Aber die Schleife wird noch mind. einmal durchlaufen. Und dann geht der Zugriff nicht mehr. Nachdem ich jetzt eine zusätzliche Variable eingefügt habe, die testet, ob das Fenster geschlossen werden soll, klappt es.
    Zumindest das zweite Problem...
    Jetzt muss ich noch das mit dem Minimieren hinbekommen. Kann mir da vielleicht jemand einen Tipp geben, wo ich mit dem Restore arbeiten muss, damit nach dem Maximieren wieder gezeichnet wird?



  • Wie ich jetzt rausgefunden habe, bekomme ich nur dann eine Meldung, dass nicht in den Speicher geschrieben werden kann, wenn ich den Lock nicht mit dem FAILED Makro überprüfe

    na klar - beachte das schluesselwort "if":
    dein surface wird nur beschrieben, wenn es gelockt werden konnte.
    in einen nicht mehr existenten speicherbereich zu schreiben ist prinzipiell keine gute idee.



  • Ok soweit ist klar... (Hätte ich auch selbst drauf kommen können ich Trottel)
    Nur was kann ich machen um das Problem mit dem Minimieren zu beheben? Hab das jetzt mal mit dem IsLost und Restore probiert aber es hat nicht geklappt. Wo müsste ich das ganze überprüfen und dann restoren? Nach dem Lock? Oder muss ich eine Windowsmessage abfangen, die beim Minimieren und Maximieren gesendet wird?



  • du reagierst auf den fehlercode der methoden von IDirectDraw und IDirectDrawSurface.



  • Ich hab das ganze jetzt so gelöst:

    HRESULT result;
    
    result=lpddsprimary->Lock(NULL, &ddsurfdesc, DDLOCK_SURFACEMEMORYPTR | 
                                                     DDLOCK_WAIT, 
                                                     NULL);
    if (result==DD_OK)
    {
    ULONG * video_buffer = (ULONG *)ddsurfdesc.lpSurface;
    video_buffer[0] = BUILD32RGB(0,255,255,255);
    } else
    lpddsprimary->Restore();
    
    if (FAILED(lpddsprimary->Unlock(NULL)))
    return 0;
    

    Gibts noch eine schönere Lösung, um irgendwie die Zeichenaktionen aus der Abfrage zu bekommen und trotzdem die Abfrage zu schaffen? Hab schon verschiedene if-Kombinationen probiert aber das ist bis jetzt das einzige was funktioniert. Bei den anderen schließt er meistens mein Fenster sobald ich es wieder maximiere.

    EDIT:
    Wie ist es mit dieser Variante? Funktioniert auch und ist meiner Meinung nach besser. Wie seht ihr das?

    result=lpddsprimary->Lock(NULL, &ddsurfdesc, DDLOCK_SURFACEMEMORYPTR | 
                                                     DDLOCK_WAIT, 
                                                     NULL);
    if (result!=DD_OK)
    {
        lpddsprimary->Restore();
        return 0;
    }
    
    ULONG * video_buffer = (ULONG *)ddsurfdesc.lpSurface;
    video_buffer[0] = BUILD32RGB(0,255,255,255);
    
    if (FAILED(lpddsprimary->Unlock(NULL)))
    return 0;
    


  • Ich mache es normalerweise ca. so:

    void Foo::Bar()
    {
        HRESULT hr = m_lpdds->Lock(...);
        if(hr == DDERR_SURFACELOST)
        {
            TryRestore();
            hr = m_lpdds->Lock(...);
        }
    
        if(FAILED(hr))
            ThrowDDException(hr);
    
        // ... (use lock)
    
        VERIFY(SUCCEEDED(m_lpdds->Unlock()));
    }
    
    void Foo::TryRestore()
    {
        if(m_lpdds->IsLost() != DDERR_SURFACELOST)
        {
            // try restore
            if(SUCCEEDED(m_lpdds->Restore()))
                OnSurfaceRestored();
        }
    }
    
    void Foo::OnSurfaceRestored()
    {
        // restore surface contents
    }
    

Anmelden zum Antworten