Das Objekt wird bereits an einer anderen Stelle verwendet.

  • C#

Es gibt 28 Antworten in diesem Thema. Der letzte Beitrag () ist von Gonger96.

    Das Objekt wird bereits an einer anderen Stelle verwendet.

    Ich habe das Problem, das ich nicht auf eine Bitmap zugreifen kann, da sie von irgendwoher anders verwendet wird. Das Problem ist, das dass gar nicht sein kann! Der verantwortliche Codeteil ist dieser:

    C#-Quellcode

    1. var hdc = graphics.GetHdc();
    2. var intPtr = GdiNative.CreateCompatibleDC(hdc);
    3. var hbitmap = _buffer.GetHbitmap();
    4. GdiNative.SelectObject(intPtr, hbitmap);
    5. GdiNative.StretchBlt(hdc, 0, 0, width, height, intPtr, 0, 0, GraphicsDevice.DisplayMode.Width, GraphicsDevice.DisplayMode.Height, GdiNative.GdiRasterOperations.SRCCOPY);
    6. GdiNative.DeleteObject(hbitmap);
    7. GdiNative.DeleteObject(intPtr);
    8. graphics.ReleaseHdc(hdc);


    Allerdings wurde die Bitmap vorher mit .DrawImage auf den _buffer gezeichnet, das heißt die eigentliche Bitmap dürfte doch hier gar keine Bedeutung mehr spielen? Wie kann ich diesen Fehler beheben?
    Ich habe das löschen des DC's eingefügt, hat aber wie vermutet das Problem nicht gelöst.


    Ich versteh halt nicht, wieso noch ein Bezug zur alten Bitmap besteht, da diese via DrawImage quasi kopiert wurde, und rein theoretisch gar nicht mehr gebraucht wird.
    Für gewöhnlich macht man sowas auch etwas anders. Das wird ja Doublebuffering, also hohl dir deine HBITMAP per CreateCompatibleBitmap() und instanzier einfach ein Graphics-Objekt aus dem komplatiblen DC. Damit kannste ganz normal zeichnen, dann disposen und dann BitBlt() bzw. StretchBlt aufrufen. Am Ende natürlich noch die ganzen Resourcen freigeben.
    /
    Kopiert wird die nicht. Du bekommst nur die HBITMAP die in der Bitmapinstanz benutzt wird. Das ist ja nurn Wrapper dafür
    Das verstehe ich nicht ganz, um einen Kompatiblen DC zu bekommen benötige ich den Hdc aus einen Graphics Objekt, dieses ensteht aus den handle einer Form. Nun sagst du das ich aus den kompatiblen eine neue Graphics erstellen soll - aber wieso? Die Graphics Klasse brauche ich zu der zeit gar nicht mehr.. Wenn du das anders meintest, bitte nochmal erläutern ;)
    Doublebuffering läuft ja mit doppeltem Puffer, also 2 DC's. Für gewöhnlich fängst du im Paintevent an: PAINTSTRUCT instanzieren, BeginPaint() aufrufen da gibts den eigentlichen DC des Fensters. Dann den zweiten per CreateCompatibleDC() hohlen. Natürlich muss der auch irgendwodrauf rendern also braucht der ne leere HBITMAP, die du dir per CreateCompatibleBitmap() holhst und mit SelectObject in den DC packst. Dann instanzierst du dir ein Graphicsobjekt aus dem kompatiblen DC und malst was du willst. So malste ja auf den zweiten Puffer (die HBMP). Dann kopierst du den DC der Bitmap auf den DC des Fensters per BitBlt() o. StretchBlt(). Danach disposed du die Graphics, löscht die HBMP (DeleteObject), löscht den DC (DeleteDC) und rufst EndPaint() auf, damit wird der DC des Fensters wieder freigegeben.

    Wichtig ist die Resourcen richtig zu löschen. Ich hab vorgestern vergessen die HBITMAP zu löschen - bisschen die Fenstergröße geändert dann war der gesame Arbeitsspeicher voll. Mal ne andere Frage: Was hast du überhaupt vor ?
    Ich nehme mal an, das ist für deine Engine und du machst das etwa so wie ich, dass du erst alles auf ne Bitmap zeichnest und diese willst du jetzt auf die Form kopieren. Richtig? Also Doublebuffering ist da ja nicht mehr nötig, du hast den Doublebuffer ja bereits in Form der Bitmap.
    bei mir siehts so aus:

    C#-Quellcode

    1. var g = surface.CreateGraphics();
    2. IntPtr pTarget = g.GetHdc();
    3. IntPtr pSource = CreateCompatibleDC(pTarget);
    4. IntPtr hBmp = bmp.GetHbitmap();
    5. IntPtr pOrig = SelectObject(pSource, hBmp);
    6. BitBlt(pTarget, 0, 0, bmp.Width, bmp.Height, pSource, 0, 0, TernaryRasterOperations.Srccopy);
    7. DeleteObject(hBmp);
    8. DeleteDC(pSource);
    9. g.ReleaseHdc(pTarget);
    10. g.Dispose();
    Eigentlich also kein Unterschied.
    Du arbeitest vermutlich (hoffentlich?) mit Threading. Leider ist GDI+ da ganz anfällig, du musst wirklich sorgfältig mit SyncLock und anderen Spielereien alles absolut synchron halten. Kannst du das behaupten?
    @Artentus: Naja.. das ist schon längst in der Engine mir ist nur letztens dieser Fehler aufgefallen. Ich habe noch nie mit SyncLock gearbeitet, und wüsste auch nicht was ich synchronisieren muss?

    @Gonger96:

    Ich habe eine Bitmap auf die werden verschiedene Images gezeichnet, irgendwann kommt es zur "Presentation" und der die Buffer Bitmap soll auf die Form übertragen werden. Ich hatte damals gehört, dass der direkte Zugriff auf gdi32.dll schneller wär als DrawImage.
    Nein warum sollte es auch - der Zugriff auf die Bitmap in der Textur ist eigentlich nicht möglich und internalen Dingen vorbehalten ;)


    Der Code steht im GdiRenderer, und wird ausgeführt nachdem Renderer.Close() (EndDraw) aufgerufen wurde. Der Inhalt des Buffers soll auf das Surface kopiert werden. Allerdings scheint es, obwohl mit DrawImage der Inhalt des Bitmaps kopiert wurde und es eigentlich nicht mehr verwendet werden müsste, er beim kopieren auf die Bitmap zugreift...


    Ich konnte das Problem lösen .. allerdings weiß ich nicht genau warum ausgerechnet das funktioniert, da ich quasi immer noch auf die Bitmap zugreife... Ich werde mir SyncLocks trotzdem mal anschauen, hab mich gerade dazu schon ein bisschen belesen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ThuCommix“ ()

    Hm, also ich erstelle die Bitmap nach jeden EndRender-Aufruf zusammen mit dem Graphics (warum nimmst du eigentlich BufferedGraphics, es funktioniert ohne genausogut?) neu.

    SyncLock bzw. allgemein Threadsynchronisierung brauchst du vor allem, wenn du von mehreren Threads auf nicht-threadsichere Ressourcen, wie z.B. der komplette GDI-Kram (Brushes, Bitmaps, usw.), zugreifen willst. Ich hab aber zu ner anderen Methode gegriffen, da SyncLock durchaus Performance zieht.

    ThuCommix schrieb:

    Du meinst ohne Double Buffer?
    Die Bitmap ist der Buffer. Indem du erst alles dadrauf zeichnest und dann ganz am Ende die Bitmap auf das Fenster kopierst, hast du ja den selben Effekt, afaik funktioniert DoubleBuffer doch genau so. Wenn du die Bitmap auch noch Doublebufferest, dann hast du eigentlich drei Buffer, und ich weiß immer noch nicht, in welchen Fällen sowas überhaupt sinnvoll sein sollte. Normalerweise reichen auf jeden Fall zwei Buffer (daher ja auch das "Double" in DoubleBuffer), und die Bitmap ist schon der zweite Buffer.

    ThuCommix schrieb:

    Es geht ja nicht um die Buffer Bitmap, sondern um die Bitmap in der Textur
    ? Reden wir irgendwie aneinander vorbei? :D
    Nicht nur afaik, genau das ist Doublebuffering. Ich würd bei sowas so oder so Doublebuffering verwenden, nur wenn du GDI mit reinschiebst, musst du auch natives Doublebuffering machen. Sonst kopierst du den DC und renderst dann erneut drauf, das flackert nur.
    Reden wir irgendwie aneinander vorbei?


    Anscheinend irgendwie schon :D


    Mir ist bewusst das ich Double Buffer benutze, und das ist auch so geplant - Ich benutze ja auch nur zwei, oder was hast du jetzt gemeint?
    Wieso erstellst du neu? Reicht doch Clear() und die graphics vom Buffer kannst du ja noch verwenden..



    Bei mir flackert auch nichts..

    ThuCommix schrieb:

    Ich benutze ja auch nur zwei
    Nö, du benutzt drei. Erst zeichnest du mit ner BufferedGraphics auf die Bitmap, das ist der erste Buffer. Dann hast du die Bitmap selbst, welche den zweiten darstellt, und der dritte Buffer ist das Fenster.
    Du kannst auch mit ner normalen Graphics auf die Bitmap zeichnen.

    ThuCommix schrieb:

    Wieso erstellst du neu?
    Weil sich das Surface ja 1. geresized haben kann und 2. weil die Graphics, die auf die Bitmap zeigt, ja sowieso Disposed werden muss.
    @Artentus
    Warum sollte da was flackern ? Nur wenn man Doublebuffered auf True stellt und dann noch wieder mit GDI (ohne +) drüberzeichnet, kann man sich das auch sparen. Bei GDI sollte man, wenns auf Performance ankommt bzw. auf die Rendergeschwindigkeit, auch mit GDI doublebuffern und nicht nur die Property auf True setzen.