PixelFormat=pf24bit versucht Arbeitsspeicherüberlastung



  • Th69 schrieb:

    Der Canvas wird ja noch nichteinmal benutzt -)

    Jo.

    Im Thread w.v stand bei ihm zwischen Zeile 15 und 17 noch

    bmp->Canvas->CopyRect(bmp->Canvas->ClipRect,canvas,source);
    

    Hat er sicher übersehen.. 😉
    edit: Link ergänzt



  • Wegen ReleaseDC,canvas wird doch am Ende gelöscht, für was braucht man da noch ReleaseDC? Hab umgebaut aber das Problem liegt nicht daran. Es liegt auf jeden Fall bei den 24bit.
    Und wegen

    bmp->Canvas->CopyRect(bmp->Canvas->ClipRect,canvas,source);
    

    hab "Komentare" gelöscht und hab ausversehen mitgelöscht als ich hier gepostet hab.
    Also so sieht der Code in dem Compiler aus:

    DWORD WINAPI ScanFunc( LPVOID lpParam )
    {
     while(whilethread==true)
     {
      if(scanthread==true)
      {
      //sk.SendKeys("{BEEP 100 500}");
       Graphics::TBitmap *bmp = new Graphics::TBitmap();
      TCanvas *canvas = new TCanvas();
       dc = GetWindowDC(GetDesktopWindow());
       canvas->Handle = dc;
       bmp->PixelFormat=pf24bit;
    
       TRect source;
       GetWindowRect(GetDesktopWindow(),(LPRECT)&source);
       bmp->Width = source.Right ;
       bmp->Height = source.Bottom;// * 30 / 100;
       //source.Top = source.Bottom * 70 / 100;
       bmp->Canvas->CopyRect(bmp->Canvas->ClipRect,canvas,source);
    	 //ForLoL->Image1->Picture->Bitmap=bmp;
    	 //ForLoL->Image1->Picture->Assign(bmp);
    
       for(scany=0; scany < bmp->Height; scany++)
       {
    	//ypix = (TRGBTriple *)bmp->ScanLine[scany];
    	ypix = reinterpret_cast<TRGBTriple *>(bmp->ScanLine[scany]);
    	for(scanx=0; scanx < bmp->Width; scanx++)
    	{
    	 if(ypix[scanx].rgbtBlue == 49 && ypix[scanx].rgbtGreen==247 &&
    		ypix[scanx].rgbtRed ==255)
    	 {
    	 //sk.SendKeys("{BEEP 350 500}");
    	  sk.SendKeys("w");
    	  MessageBox(0,"Gefunden","test1",MB_OK);
    	 }
    	}
       }
    
      bmp->FreeImage();
      delete bmp;
      delete canvas;
      ReleaseDC(0,dc);
    
      //sk.SendKeys("{BEEP 150 500}");
      }
      Sleep(10);
     }
    }
    


  • igromanru schrieb:

    Wegen ReleaseDC,canvas wird doch am Ende gelöscht, für was braucht man da noch ReleaseDC?

    Jeder Aufruf von GetWindowDC erfordert am Ende das ReleaseDC:

    WinAPI-Help schrieb:

    After painting is complete, the ReleaseDC function must be called to release the device context. Not releasing the window device context has serious effects on painting requested by applications.

    Daran wirds aber nicht liegen.

    Wenn du glaubst, dass das eingestellte Pixelformat Schuld an deinem Problem ist, stelle es auf die aktuelle Auflösung deines Desktop ein (s. Systemsteuerung/Anzeige/Einstellungen).
    Vermutlich sind es 32 Bit...



  • Oh, ich musste gerade feststellen, dass mit 32 auch geht, wobei vorher gings nicht, weiß nicht genau ob vorher irgendwas anders war, aber jetzt geht es mit PixelFormat=pf32bit.
    Das Problem mit dem Arbeitsspeicher ist aber geblieben. Arbeitsspeicher bloß nicht überlastet wenn ich PixelFormat ganz weg lasse, aber dann funtioniert es nicht so wie ich es will.



  • Der MessageBox-Aufruf könnte eine weitere Ursache sein.
    Setze testweise mal ein

    Application->ProcessMessages();
    

    direkt unter die Codezeile.

    Sollte das nicht abhelfen, sieh dir den Thread an, ob der sauber beendet wird oder lass deine
    ScanFunc erstmal ausserhalb des Thread laufen.

    Hier hatte ich mal einen Code gepostet, wo ein ScreenShot ohne Canvas auskommt:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-273891-and-highlight-is-.html

    Soll heissen, dass du deinen Code etwas optimieren kannst...

    grüsse
    kpeter



  • kpeter schrieb:

    Sollte das nicht abhelfen, sieh dir den Thread an, ob der sauber beendet wird oder lass deine
    ScanFunc erstmal ausserhalb des Thread laufen.

    Hab auf ein Button drauf gemacht. Also der Speicher wurde nach einen durchlauf sauber befreit. Aber wie kann es an dem thread liegen? Zu schnell?

    Alle andere deine Lösungen haben nicht geholfen.



  • igromanru schrieb:

    Aber wie kann es an dem thread liegen?

    Um das zu beantworten, müsstest du uns mal den betreffenden Code zeigen...



  • Also alles zu dem Thread:
    Globale Deklaration:

    DWORD WINAPI ScanFunc( LPVOID lpParam );
    bool scanthread = false;
    bool whilethread = true;
    

    Erstellen vom Thread:

    __fastcall TForLoL::TForLoL(TComponent* Owner)
    	: TForm(Owner)
    {
      CreateThread(NULL,0,ScanFunc,0,0,0);
    }
    

    Thread wird beendet bei OnClose:

    void __fastcall TForLoL::FormClose(TObject *Sender, TCloseAction &Action)
    {
     scanthread=false;
     whilethread=false;
    }
    

    Der Thread selbst:

    DWORD WINAPI ScanFunc( LPVOID lpParam )
    {
     while(whilethread==true)
     {
      if(scanthread==true)
      {
       Graphics::TBitmap *bmp = new Graphics::TBitmap();
       TCanvas *canvas = new TCanvas();
       dc = GetWindowDC(GetDesktopWindow());
       canvas->Handle = dc;
       bmp->PixelFormat=pf32bit;
    
       TRect source;
       GetWindowRect(GetDesktopWindow(),(LPRECT)&source);
       bmp->Width = source.Right;  ;
       bmp->Height = source.Bottom;
       bmp->Canvas->CopyRect(bmp->Canvas->ClipRect,canvas,source);
    
       for(scany=0; scany < bmp->Height; scany++)
       {
    	ypix = reinterpret_cast<TRGBTriple *>(bmp->ScanLine[scany]);
    	for(scanx=0; scanx < bmp->Width; scanx++)
    	{
    	if(ypix[scanx].rgbtBlue == 49 && ypix[scanx].rgbtGreen==247 &&
    		ypix[scanx].rgbtRed ==255)
    	 {
    	  sk.SendKeys("w");
    	  //MessageBox(0,"Gefunden","test1",MB_OK);
    
    	 }
    	}
       }
    
      bmp->FreeImage();
      ReleaseDC(0,canvas->Handle);
      ReleaseDC(0,dc);
      delete bmp;
      delete canvas;
      }
      Sleep(100);
     }
    }
    


  • Du muss dir ein Handle für den Thread anlegen:

    static HANDLE hThread = NULL;
    

    Starten des Thread:

    hThread = CreateThread(NULL, 0, ScanFunc, 0, 0, NULL );
    

    Thread beenden:

    if ( hThread )
          TerminateThread( hThread, 0 );
    

    Das ist das mindeste.
    Das Setzen deiner boolschen Werte allein startet nur die Schleifen innerhalb ScanFunc nicht neu...



  • kpeter schrieb:

    Du muss dir ein Handle für den Thread anlegen:

    static HANDLE hThread = NULL;
    

    Starten des Thread:

    hThread = CreateThread(NULL, 0, ScanFunc, 0, 0, NULL );
    

    Thread beenden:

    if ( hThread )
          TerminateThread( hThread, 0 );
    

    Das ist das Mindeste.
    Das Setzen deiner boolschen Werte allein startet nur die Schleifen innerhalb ScanFunc nicht neu...

    Danke, aber es hilt nicht.
    Also 1. Ich will den Thread nicht nochmal starten, es wird ja auch erst am OnClose ausgeschaltet.
    2. Ich glaube nicht, dass der Thread an dem Problem schuld ist. Wie ich den Thread ausmache, kann nicht beeinflussen was passiert während der Thread läuft. Abgesehen davon verschwindet das Problem mit dem Arbeitsspeicher Füllung sobald ich PixelFormat=pf32bit entferne. Also muss es damit was zusammenhängen.

    Ich werde das Problem nochmal erklären:
    Also es ist so, ich starte das Programm, drücke auf ein Button der scanthread auf true setzt. Danach passiert halt jedes mal beim durchlaufen der while Schleife, das was in der If Funtion steht. Dabei steigt der verbauch des Arbeitsspeichers ununterbrochen. Wenn ich aus der code bmp->PixelFormat=pf32bit entferne, dann läuft das Programm mit normalen Speicherverbrauch. Aber dann passiert nicht das was ich von der ScanLine Funtion erwarte.



  • Weiter oben schrieb ich schon mal, dass du Application->ProcessMessages setzen sollst,
    wenn deine if-Bedingung erfüllt ist.
    Was sk.SendKeys("w"); bewirkt, hast du bisher nicht geschrieben. Du musst
    deiner Anwendung Zeit geben, alle Messages erst einmal zu verarbeiten...



  • kpeter schrieb:

    Weiter oben schrieb ich schon mal, dass du Application->ProcessMessages setzen sollst,
    wenn deine if-Bedingung erfüllt ist.
    Was sk.SendKeys("w"); bewirkt, hast du bisher nicht geschrieben. Du musst
    deiner Anwendung Zeit geben, alle Messages erst einmal zu verarbeiten...

    Ich glaube du hast mich nicht verstanden. Sobald die scanthread=true ist fängt an der Verbrauch der Arbeitsspeicher ständig zu steigern. Dabei wird weder die MessageBox noch die sk.SendKeys ausgeführt. Weil if garnicht zustimmt.

    sk.SendKeys ist nur eine Funtion die keybd_event ausführt.

    Und noch was, alles was ich noch nicht erwähnt hab ist das was keinen Einfluss auf das Problem hat. Ich habe alles gestest bzw ohne diese Funtionen gestartet.



  • Hmm.
    In Zeile 21 schreibst du in die Struktur TRGBTriple rein. Eher für 24 Bit-BMPs.
    Versuchs mal mit RGBQUAD, 4-BYTE-Struktur. Ansatz:

    RGBQUAD *ptr;
    
    for (int y = 0; y < bmp->Height; y++) {
       ptr = (RGBQUAD*)bmp->ScanLine[y];
       for (int x = 0; x < bmp->Width; x++) {
          if (ptr[x].rgbRed 	== 255 &&
          .
          .
    


  • An dem Ergebnis hat sich leider nichts geändert. Passiert genau das selbe wie mit dem TRPGTriple.



  • Nun, wenn ich mir diesen und auch den vorhergehenden Thread betrachte, muss ich feststellen, dass du im Prinzip immer denselben Code postest.

    Insbesondere hast du folgende Hinweise nicht beachtet:
    Erstellen der Bitmap NICHT in der ScanFunc, sondern schon vor Aufruf des Thread. Schliesslich bleibt die Grösse konstant.
    Das ReleaseDC ist fehlerhaft. Hättest du meinen Hinweis (Link) beachtet, müsstest du diese Funktion einschl. GetWindowDC nicht mal verwenden.
    Auch das Erstellen eines TCanvas wäre unnötig, da in der API-Funktion BitBlt direkt das Handle des DC des Bitmap
    übergeben wird.
    Deine Scanfunktion ist nicht korrekt; sie müsste einen return-Wert zurückgeben.
    Keine Ahnung, wie gross dein Monitor ist, aber da du ja permanent scannst, sollte diese Funktion auch so kurz wie möglich gehalten
    werden.
    Mit welchem Tool stellst du deine Arbeitsspeicherüberlastung fest?



  • kpeter schrieb:

    Insbesondere hast du folgende Hinweise nicht beachtet:
    Erstellen der Bitmap NICHT in der ScanFunc, sondern schon vor Aufruf des Thread. Schliesslich bleibt die Grösse konstant.

    Hab ich schon versucht, da das Ergebnis sich nicht geändert hat hab ich es so gelassen.

    kpeter schrieb:

    Das ReleaseDC ist fehlerhaft. Hättest du meinen Hinweis (Link) beachtet, müsstest du diese Funktion einschl. GetWindowDC nicht mal verwenden.
    Auch das Erstellen eines TCanvas wäre unnötig, da in der API-Funktion BitBlt direkt das Handle des DC des Bitmap
    übergeben wird.

    Wieso ist ReleaseDC fehlerhaft? Ansonsten hab ich mit BitBlt schon mal versucht und wie in dem Beispiel nachgebaut:

    DWORD WINAPI ScanFunc( LPVOID lpParam )
    {
     while(whilethread==true)
     {
      if(scanthread==true)
      {
       Graphics::TBitmap *bmp = new Graphics::TBitmap();
       dc = GetWindowDC(GetDesktopWindow());
       hBitmap = CreateCompatibleBitmap(dc, iSizeW, iSizeH);
       HDC hdcTemp = CreateCompatibleDC(dc);
       bmp->PixelFormat=pf24bit;
       bmp->Width = iSizeW;
       bmp->Height = iSizeH;
       BitBlt(bmp->Canvas->Handle, 0, 0, bmp->Width, bmp->Height, dc, 0, 0, SRCCOPY);
    
       for(scany=0; scany < bmp->Height; scany++)
       {
    	ypix = reinterpret_cast<TRGBTriple *>(bmp->ScanLine[scany]);
    	for(scanx=0; scanx < bmp->Width; scanx++)
    	{
    	  if(ypix[scanx].rgbtBlue == 49 && ypix[scanx].rgbtGreen==247 &&
    		ypix[scanx].rgbtRed ==255)
    	 {
    	  MessageBox(0,"Gefunden","test1",MB_OK);
    	 }
    	}
       }
      bmp->FreeImage();
      ReleaseDC(0,dc);
      delete bmp;
      }
      Sleep(100);
     }
     return 0;
    }
    

    Was ist danran falsch? 😕

    kpeter schrieb:

    Mit welchem Tool stellst du deine Arbeitsspeicherüberlastung fest?

    Task-Manager->Processe. Da steht welches Process wie viel Speicher verbraucht. Ich weiß nicht genau ob es unter XP schon gabs(glaub schon) aber ich habe Windiws 7.
    Und genau dort fängt an die Zahl zu wachsen sobald ich den scanthread auf true setze.



  • Was ist das denn hier plötzlich in deinen Zeilen 9 und 10 ???

    igromanru schrieb:

    hBitmap = CreateCompatibleBitmap(dc, iSizeW, iSizeH);
       HDC hdcTemp = CreateCompatibleDC(dc);
    

    Wird doch nie verwendet???

    Die Funktion ReleaseDC ist hier beschrieben. Auch welche Parameter erwartet werden.



  • Die Zwei Zeilen hab ich ausversehen mit übergenommen.
    Und was dir an dem ReleaseDC nicht gefällt verstehe ich auch nicht.
    Ich habe jetzt mal so gemacht, aber besser wurde davon jetzt auch nicht:

    DWORD WINAPI ScanFunc( LPVOID lpParam )
    {
     while(whilethread==true)
     {
      if(scanthread==true)
      {
       Graphics::TBitmap *bmp = new Graphics::TBitmap();
       DeskH =  GetDesktopWindow();
       dc = GetWindowDC(GetDesktopWindow());
       bmp->PixelFormat=pf24bit;
    
       bmp->Width = iSizeW;
       bmp->Height = iSizeH;
       BitBlt(bmp->Canvas->Handle, 0, 0, bmp->Width, bmp->Height, dc, 0, 0, SRCCOPY);
    
       for(scany=0; scany < bmp->Height; scany++)
       {
    	ypix = reinterpret_cast<TRGBTriple *>(bmp->ScanLine[scany]);
    	for(scanx=0; scanx < bmp->Width; scanx++)
    	{
    	  if(ypix[scanx].rgbtBlue == 49 && ypix[scanx].rgbtGreen==247 &&
    		ypix[scanx].rgbtRed ==255)
    	 {
    	  MessageBox(0,"Gefunden","test1",MB_OK);
    	 }
    	}
       }
    
      bmp->FreeImage();
      ReleaseDC(DeskH,dc);
      delete bmp;
      }
      Sleep(100);
     }
     return 0;
    }
    


  • Hallo,

    Das FreeImage hier brauchst du nicht. Weietrhin würde ich das Erzeugen und zerstören des Bitmaps aus der while-Schleife nehmen.



  • Braunstein schrieb:

    Hallo,

    Das FreeImage hier brauchst du nicht. Weietrhin würde ich das Erzeugen und zerstören des Bitmaps aus der while-Schleife nehmen.

    Hab ich mal versucht. Hab dabei folgendes bemerkt:
    Wenn

    bmp = new Graphics::TBitmap();
    

    oder

    bmp->PixelFormat=pf24/*32*/bit;
    

    nur 1mal festgelegt wird, gibt es zwar keine Arbeitsspeicherüberstung aber dafür funktioniert es nicht.
    Hab versucht und hab wie du sagtest,

    Graphics::TBitmap *bmp = new Graphics::TBitmap()
    

    und

    delete bmp;
    

    außerhalb der Schleife gemacht und nach dem es nicht geklappt hat, hab ich wieder zurück umgebaut und hab

    bmp->PixelFormat=pf24/*32*/bit;
    

    nur 1mal ausführen gelassen:

    if(test011==true)
       {
       bmp->PixelFormat=pf24bit;
       test011 = false;
       }
    

    Ja, und wie gesagt, Funtion geht nicht, dafür ist aber alles OK mit dem Speicher.


Anmelden zum Antworten