[GDI+] Zugriffsverletzung beim Versuch Resourcen freizugeben
-
Hallo liebe C++ Community,
ich bin C++ Anfänger, habe allerdings in AutoIt (Scriptsprache) schon mal mit GDI+ gearbeitet. In meinem Sourcecode habe ich Images und Fonts geladen und möchte diese beim Beenden des Programms wieder freigeben. Damit ich die Resourcen nur 1 mal laden muss und sie dann in verschiedenen Funktionen benutzen kann, habe ich einen globalen Pointer darauf gesetzt. Wenn ich meinen Quellcode kompiliere und danach die Anwendung teste, funktioniert alles super, bis ich das Fenster schließe, denn genau dann erscheint die Fehlermeldung "Unbehandelte Ausnahme bei 0x..... in MeinProjekt.exe: 0x......: Zugriffsverletzung beim Lesen an Position 0x.....".
Danach wird auf folgende Funktion verwiesen (GdiPlusBase.h):
void (operator delete)(void* in_pVoid) { DllExports::GdipFree(in_pVoid); }
Nun zu meinem Quellcode. Ich habe den groben Ablauf mal herausgefiltert (
Anfänger):
Image *einBild; //Pointer void eineAndereFunktion() { // hier zeichne ich das Bild etc... } int Main() { GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); Image dasBild(L"Bild.bmp"); einBild=&dasBild; // Hier werden noch andere Funktionen aufgerufen, in denen ich das Bild benutze... eineAndereFunktion(); // Nun versuche ich die Resourcen freizugeben delete &dasBild, einBild; GdiplusShutdown(gdiplusToken); }
Nur woran liegt der Fehler? Wo wird hier ein Zugriff verletzt?
mfG
Developer30
-
Hi probier mal das hier.
Erzeugen:
Image test(L"C:\test.jpg");
Löschen:
DeleteObject(&test);
Du musst aber auch wieder die Graphics Instanz frei geben.
Erzeugen:Graphics grafik(...);
Löschen:
grafik.ReleaseHDC(hdc);
so hab ich es zumindest in meinen alten Programmen gemacht.
Gruß
Ombre
-
Warum deletest du dasBild, es wurde doch nicht mit new erzeugt!?
-
dot schrieb:
Warum deletest du dasBild, es wurde doch nicht mit new erzeugt!?
ja ich muss die Resource ja irgendwie freigeben. Ob/Dass
delete
nur für Objekte mitnew
ist, wusste ich nicht.@Ombre: hm ja ich arbeite mit einem Buffer, der sieht ungefähr so aus:
hdc = GetDC(hWnd); hdcBuffer = CreateCompatibleDC(hdc); bmpBuffer = CreateCompatibleBitmap(hdc, iWidth, iHeight); SelectObject(hdcBuffer, bmpBuffer);
und den gebe ich so wieder frei:
DeleteDC(hdcBuffer); DeleteObject(bmpBuffer);
keine Ahnung wieso, aber
DeleteObject
ändert nichts an der Fehlermeldung. Ich habe auch noch ein SolidBrush, eine FontFamily und eine Font drin, die ich auf die gleiche Weise wie die Images behandle.
-
so, ich habe meinen Projektquellcode mal auf das wesentliche reduziert, Fehler kommt immernoch.
#pragma comment(lib, "gdiplus.lib") #include <windows.h> #include <GdiPlus.h> using namespace Gdiplus; LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); char szClassName[ ] = "WindowClass"; int iWidth=200; int iHeight=200; // GDI+ HDC hdc, hdcBuffer; HBITMAP bmpBuffer; Image *einBild; void OnPaint(HDC hdc) // Draw-Funktion { Graphics graphics(hdcBuffer); graphics.Clear(Color(0,0,0)); graphics.DrawImage(einBild,10, 0); BitBlt(hdc, 0, 0, iWidth, iHeight, hdcBuffer, 0, 0, SRCCOPY); graphics.ReleaseHDC(hdcBuffer); } LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow) { HWND hWnd; MSG msg; WNDCLASS wndClass; GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = WndProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = hInstance; wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = TEXT("title"); RegisterClass(&wndClass); hWnd = CreateWindow( TEXT("title"), // window class name TEXT("title"), // window caption WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position iWidth, // initial x size iHeight, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters // Initialize GDI+. GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); hdc = GetDC(hWnd); hdcBuffer = CreateCompatibleDC(hdc); bmpBuffer = CreateCompatibleBitmap(hdc, iWidth, iHeight); SelectObject(hdcBuffer, bmpBuffer); // Lade das Bild Image dasBild(L"..\\logo.bmp"); einBild=&dasBild; ShowWindow(hWnd, iCmdShow); UpdateWindow(hWnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // Resourcen freigeben DeleteObject(&dasBild); DeleteDC(hdcBuffer); DeleteObject(bmpBuffer); GdiplusShutdown(gdiplusToken); return msg.wParam; } // WinMain LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; switch(message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); OnPaint(hdc); EndPaint(hWnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hWnd, message, wParam, lParam); } } // WndProc
-
Du hast dort eine lokale Variable
Image dasBild(...);
- wenn die Klasse vernünftig gestaltet ist, hat die einen Destruktor, der sich darum kümmert, die von ihr angeforderten Speicherbereiche wieder freizugeben. Also ist es auch nicht notwendig, diese Variable per delete oder DeleteObject() wieder freizugeben.
-
gibt es in GDI+ dafür einen Destruktor?(ja gibt es)
was noch komisch ist, ist dass keine Fehlermeldung kommt, wenn ich folgendes vonWinMain
nachOnPaint
verschiebe:Image dasBild(L"..\\logo.bmp"); einBild=&dasBild;
wenn ich das mache, muss ich natürlich
DeleteObject
in Zeile 82 rauskommentieren...Edit:
Hier der Destruktorinline Image::~Image() { DllExports::GdipDisposeImage(nativeImage); }
aber irgendwas stimmt nicht, weil sobald
GdiplusShutdown
aufgerufen wird, kommt der Fehler
-
Hmmm wenn der Fehler mit GdiplusShutdown zusammen hängt, kann es fast nur daran liegen, das nicht alle erzeugten Objekte wieder gelöscht werden.
Siehe die MSDN:
... , and you must delete all of your GDI+ objects (or have them go out of scope) before you call GdiplusShutdown.
Also hat ein Objekt noch Gültigkeit und wurde nicht gelöscht.
Hoffe das konnte helfen.
Ombre
-
ok ich habe den Fehler gefunden.
so habe ich nun das Bild erstellt:Image* einBild = new Image(L"..\\logo.bmp");
und dann kann man es auch mit
delete
wieder freigeben:delete einBild;
danke an alle, die sich mitbeteiligt haben
lg
Developer30