AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

IStream und IPicture freigeben

Ein Thema von stz · begonnen am 3. Aug 2006 · letzter Beitrag vom 9. Aug 2006
Antwort Antwort
Benutzerbild von stz
stz

Registriert seit: 8. Sep 2005
Ort: Neuendeich, Lübeck
277 Beiträge
 
Turbo Delphi für Win32
 
#1

IStream und IPicture freigeben

  Alt 3. Aug 2006, 18:52
Moin Moin,
ich habe mir mit Hilfe vom diesem Thread etwas zusammengebastelt, um JPEGs in einer nonVCL-Anwendung zu laden und anzuzeigen. Das gaze funktioniert auch wunderbar, allerdings habe ich das Gefühl, mir ein gewaltiges Speicherleck gebastelt zu haben, da ich mit GlobalAlloc Speicher anfordere, diesen dann mit CreateStreamOnHGlobal einem Stream zur Verwaltung übergebe mit der Optionen, dass dieser Speicher auch wieder freigegeben wird, wenn der Stream freigegeben wird. Aus diesem Stream erzeuge ich dann ein Picture und nun ist mir nicht klar, ob und wie ich beides wieder freigeben muss. pPicture vom Typ IPicture ist bei mir nur eine lokale Variable, daher finde ich, dass ich am Ende der Procedure irgendwas damit machen muss, bevor ich das Handle nicht mehr habe

Könnt ihr euch das mal ansehen und kommentieren?

Gruß
Malte

Delphi-Quellcode:
function LoadPicture(const AFile: string; var pPicture: IPicture):Boolean;
const
  IID_IPicture : TGUID = '{7BF80980-BF32-101A-8BBB-00AA00300CAB}';
var
  hFile, hMem: THandle;
  dwFileSize, dwBytesRead: DWord;
  pData: Pointer;
  bRead: Boolean;
  hRes: HResult;
  pStream: IStream;
begin
  Result := False;
  bRead := False;
  dwBytesRead := 0;

  //Datei öffnen
  hFile := CreateFile(PChar(AFile), GENERIC_READ, 0, NIL, OPEN_EXISTING, 0, 0);
  if hFile <> INVALID_HANDLE_VALUE then
  begin
    try
      //Dateigröße ermitteln
      dwFileSize := GetFileSize(hFile, nil);
      if dwFileSize <> INVALID_FILE_SIZE then
      begin
        //GlobalMemory reservieren und gleichzeitig mit "Nullen" füllen
        hMem := GlobalAlloc(GMEM_MOVEABLE{ or GMEM_NODISCARD} or GMEM_ZEROINIT, dwFileSize);
        if hMem <> 0 then
        begin
          //Adresse des ersten Bytes des Speicher-Objects abfragen
          pData := GlobalLock(hMem);
          if pData <> nil then
          begin
            try
              //Daten in das Speicher-Object lesen
              bRead := ReadFile(hFile, pData^, dwFileSize, dwBytesRead, nil);
            finally
              //Ich bin mit schreiben fertig, Sperre weg --> Daten bleiben
              GlobalUnlock(hMem);
            end;
          end;

          if (bRead = True) and (dwFileSize = dwBytesRead) then
          begin
            //Aus GobalMemory IStream erzeugen --> freigeben??
            //(** wird der Stream freigegeben wird auch automatisch
            //GlobalMemory freigegeben)
            pStream := nil;
            hRes := CreateStreamOnHGlobal(hMem, True {**}, pStream);
            if (hRes = S_OK) and (pStream <> nil) then
            begin
              //IPicture aus der Bilddatei in IStream erzeugen --> freigeben??
              hRes := OleLoadPicture(pStream, dwFileSize, False, IID_IPicture, pPicture);
              if (hRes = S_OK) and (pPicture <> nil) then
                Result := True;
            end;
          end;
        end;
      end;
    finally
      //Datei wieder zumachen
      CloseHandle(hFile);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  BildDateiname = 'C:\darc.jpg';
var
  DC: HDC;
  hmHeight, hmWidth, nHeight, nWidth: Integer;
  rc: TRect;
  pPicture: IPicture;
begin
  if LoadPicture(BildDateiname, pPicture) then
  begin
    DC := GetDC(Handle);
      if(pPicture.get_Width(hmWidth) = S_OK) and
        (pPicture.get_Height(hmHeight) = S_OK) and
        (Windows.GetClientRect(Handle,rc)) then
      begin
        nWidth := MulDiv(hmWidth,GetDeviceCaps(DC,LOGPIXELSX),2540);
        nHeight := MulDiv(hmHeight,GetDeviceCaps(DC,LOGPIXELSY),2540);
        pPicture.Render(DC, 0, 0, nWidth, nHeight, 0, hmHeight,
             hmWidth, -hmHeight, rc);
      end;
    ReleaseDC(Handle,DC);
    //pPicture und zugrundeliegendes IStream wieder freigeben:
    //???
  end;
end;
PS: Wie man sieht, habe ich das ganze zum Testen auf eine Form gezeichnet, aber ich will es natürlich im Endeffekt in einer richtigen nonVCL-Anwendung haben...
Malte Schmitz
Der Unterschied zwischen Theorie und Praxis ist in der Praxis größer als in der Theorie.

Entwickler des HTML-Editors MEdit (DP)
  Mit Zitat antworten Zitat
Benutzerbild von stz
stz

Registriert seit: 8. Sep 2005
Ort: Neuendeich, Lübeck
277 Beiträge
 
Turbo Delphi für Win32
 
#2

Re: IStream und IPicture freigeben

  Alt 5. Aug 2006, 16:15
Hat denn keiner einen kleinen Tip oder Denkanstoß für mich

Gruß
Malte
Malte Schmitz
Der Unterschied zwischen Theorie und Praxis ist in der Praxis größer als in der Theorie.

Entwickler des HTML-Editors MEdit (DP)
  Mit Zitat antworten Zitat
Benutzerbild von stz
stz

Registriert seit: 8. Sep 2005
Ort: Neuendeich, Lübeck
277 Beiträge
 
Turbo Delphi für Win32
 
#3

Re: IStream und IPicture freigeben

  Alt 9. Aug 2006, 13:25
Hallo,
die Erkenntnis hat mich getroffen wie der Blitz
Also für alle, die das hier mal lesen und denen eine Lösung helfen würde:
Sowohl die Variable vom Typ IStream als auch IPicture sind Interfaces und Interfaces verwalten sich bekanntlich selbst (s. Interface-Tutorial von xaromz). Da die beiden Variablen nur lokale Variablen sind, werden diese am Ende der Funktion bzw. der Prozedur zerstört und der Referenzzähler von pStream und pPicture steht auf 0. Deswegen zerstören sich die Interfaces selbst und es gibt kein Speicherleck. Um dies im Source ein wenig deutlicher zu machen, kann und söllte man vor dem Ende der Funktion / Prozedur
Delphi-Quellcode:
pStream := nil
//bzw.
pPicture := nil;
einfügen.
Ich habe das im folgenden in meinem am Anfang geposteten Code nochmal eingefügt (man beachte die blauen Stellen). Außerdem habe ich den Code jetzt so umgebaut, dass der mit GlobalAlloc reservierte Speicher auf jeden Fall von GlobalFree freigegeben wird. (rote Markierung) Das halte ich für die bessere Lösung, da bei der ersten Version im Fehlerfall ein Problem entstehen kann: Speicher wird zwar reserviert, aber Stream nicht erzeugt, also auch nicht wieder freigegeben (wobei der Stream dann ja ursprünglich den Speicher mit hätte freigeben sollen), also wird auch Speicher nicht freigegeben
Code:
uses
  ActiveX;

function LoadPicture(const AFile: string; var pPicture: IPicture):Boolean;
const
  IID_IPicture : TGUID = '{7BF80980-BF32-101A-8BBB-00AA00300CAB}';
var
  hFile, hMem: THandle;
  dwFileSize, dwBytesRead: DWord;
  pData: Pointer;
  bRead: Boolean;
  hRes: HResult;
  pStream: IStream;
begin
  Result := False;
  bRead := False;
  dwBytesRead := 0;

  //Datei öffnen
  hFile := CreateFile(PChar(AFile), GENERIC_READ, 0, NIL, OPEN_EXISTING, 0, 0);
  if hFile <> INVALID_HANDLE_VALUE then
  begin
    try
      //Dateigröße ermitteln
      dwFileSize := GetFileSize(hFile, nil);
      if dwFileSize <> INVALID_FILE_SIZE then
      begin
        //GlobalMemory reservieren und gleichzeitig mit "Nullen" füllen
        hMem := GlobalAlloc(GMEM_MOVEABLE{ or GMEM_NODISCARD} or GMEM_ZEROINIT, dwFileSize);
        if hMem <> 0 then
        begin
          [color=#ff0000]try[/color]
            //Adresse des ersten Bytes des Speicher-Objects abfragen
            pData := GlobalLock(hMem);
            if pData <> nil then
            begin
              try
                //Daten in das Speicher-Object lesen
                bRead := ReadFile(hFile, pData^, dwFileSize, dwBytesRead, nil);
              finally
                //Ich bin mit schreiben fertig, Sperre weg --> Daten bleiben
                GlobalUnlock(hMem);
              end;
            end;

            if (bRead = True) and (dwFileSize = dwBytesRead) then
            begin
              //Aus GobalMemory IStream erzeugen
              pStream := nil;
              hRes := CreateStreamOnHGlobal(hMem, [color=#ff0000]False[/color], pStream);
              if (hRes = S_OK) and (pStream <> nil) then
              begin
                //IPicture aus der Bilddatei in IStream erzeugen
                hRes := OleLoadPicture(pStream, dwFileSize, False, IID_IPicture, pPicture);
                if (hRes = S_OK) and (pPicture <> nil) then
                  Result := True;
                [color=#0000ff]pStream := nil;[/color]
              end;
            end;
          [color=#ff0000]finally
            //Speicher-Objekt freigeben
            GlobalFree(hMem);
          end;[/color]
        end;
      end;
    finally
      //Datei wieder zumachen
      CloseHandle(hFile);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  BildDateiname = 'C:\darc.jpg';
var
  DC: HDC;
  hmHeight, hmWidth, nHeight, nWidth: Integer;
  rc: TRect;
  pPicture: IPicture;
begin
  if LoadPictureFromFile(BildDateiname, pPicture) then
  begin
    DC := GetDC(Handle);
      if(pPicture.get_Width(hmWidth) = S_OK) and
        (pPicture.get_Height(hmHeight) = S_OK) and
        (Windows.GetClientRect(Handle,rc)) then
      begin
        nWidth := MulDiv(hmWidth,GetDeviceCaps(DC,LOGPIXELSX),2540);
        nHeight := MulDiv(hmHeight,GetDeviceCaps(DC,LOGPIXELSY),2540);
        pPicture.Render(DC, 0, 0, nWidth, nHeight, 0, hmHeight,
             hmWidth, -hmHeight, rc);
      end;
    ReleaseDC(Handle,DC);
    [color=#0000ff]//pPicture wieder freigeben:
    pPicture := nil;[/color]
  end;
end;
Edit: Ich hoffe ich habe alle &gt; und &lt; wieder in < und > verwandelt...
Malte Schmitz
Der Unterschied zwischen Theorie und Praxis ist in der Praxis größer als in der Theorie.

Entwickler des HTML-Editors MEdit (DP)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:30 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz