Page 3 of 3 FirstFirst 1 2 3
Results 31 to 39 of 39

Thread: Krijg memory leak niet gevonden

  1. #31
    HAHAHAHAHAHA. Probleem gevonden.

    Hoeveel karakters bevat de tekst "Removable disconnected" ???
    En wat probeer jij met DiskType=%-23s te doen???

    Als ik daar gewoon %s van maak dan gaat het goed.
    Ik begrijp dat alleen nog niet helemaal want bij mij is het wel minder dan 23 karakters.

    Weird...

    Overigens zou ik het VolumeLabel altijd ophalen.
    Dan krijg ik de foutmelding nl ook.


    Dit voldoet dus:

    Delphi Code:
    1. lpnLength := 0; // Init
    2. lError := WNetGetConnection(PChar(aDiskSign), nil, lpnLength);
    3. if lError = ERROR_MORE_DATA then // size received in lpnLength
    4. begin
    5.  
    6.   lBufVolumeLabel := AllocMem(lpnLength); // Alloc memory for VolumeLabel buffer
    7.   try
    8.  
    9.     // ALTIJD DOEN
    10.     lError := WNetGetConnection(PChar(aDiskSign), lBufVolumeLabel, lpnLength); // Get network name
    11.     result.VolumeLabel := string(lBufVolumeLabel); // Return volume label
    12.  
    13.     if lError = ERROR_CONNECTION_UNAVAIL then // It exists but is unavailable
    14.     begin
    15.       result.DiskType := dtRemovableNotConnected; // Return DiskType
    16.       result.ImageIndex := SIID_DRIVENETDISABLED; // Set imageindex to disconnected icon
    17.     end;
    18.  
    19.   finally
    20.       FreeMem(lBufVolumeLabel, lpnLength); // Free Memory
    21.   end;
    22.  
    23. end;

    Je hoeft dus ook niet met die StrPas() constructie te werken als je cast naar string (en daarna wordt er impleciet gecast naar shortstring).

  2. #32
    Ok. nog een poging. Er blijft iets raars in zitten.
    Ik denk dat het die AllocMem is. Daar gebeurd iets heel raars mee.

    Maar ik zou die AllocMem helemaal niet gebruiken.

    Ik zou van lBufVolumeLabel een string maken en dan dit:
    Delphi Code:
    1. var
    2.   lBufVolumeLabel: String;
    3. begin
    4.   //...
    5.  
    6.       SetLength(lBufVolumeLabel, MAX_PATH);
    7.       // lBufVolumeLabel := AllocMem(lpnLength); // Alloc memory for VolumeLabel buffer DIT DUS NIET
    8.  
    9.       // ...
    10.  
    11.       lError := WNetGetConnection(PChar(aDiskSign), PChar(lBufVolumeLabel), lpnLength); // hier een pChar om lBufVolumeLabel heen

    Op die manier ruimt de compiler de lBufVolumeLabel netjes op.

    Dan werkt het hier wel goed.

    (en dan dus wel gewoon die Result.VolumeLabel := string(lBufVolumeLabel); )


    Bij mij is ie nu dit:

    Delphi Code:
    1. function GetDiskInfo (aDiskSign : String) : TDiskInfo;
    2. var
    3.   lpnLength             : Cardinal;
    4.   lError                : DWORD;
    5.   lBufVolumeLabel       : String;
    6. begin
    7.   Result.DiskSign       := ShortString(aDiskSign);                                                                      // TDiskInfo.Sign = Driveletter STRING[2]
    8.   Result.DiskType       := dtUnknown;                                                                                   // Init
    9.   Result.VolumeLabel    := '';                                                                      // Init
    10.   Result.ImageIndex     := -1;                                                                      // Init
    11.  
    12.  
    13.   case GetDriveType(PChar(IncludeTrailingPathDelimiter(aDiskSign))) of                                  // Check if drive removable, fixed, CD-ROM, RAM disk, or network drive.
    14.     DRIVE_UNKNOWN       : Result.DiskType := dtUnknown;                                             // The drive type cannot be determined
    15.     DRIVE_NO_ROOT_DIR   : Result.DiskType := dtNotExists;                                           // The root path is invalid. For example, no volume is mounted at the path.
    16.     DRIVE_REMOVABLE     : Result.DiskType := dtRemovable;                                           // The disk can be removed from the drive.
    17.     DRIVE_FIXED         : Result.DiskType := dtFixed;                                               // The disk cannot be removed from the drive
    18.     DRIVE_REMOTE        : Result.DiskType := dtRemote;                                              // The drive is a remote (network) drive
    19.     DRIVE_CDROM         : Result.DiskType := dtCDROM;                                               // The drive is a CD-ROM drive
    20.     DRIVE_RAMDISK       : Result.DiskType := dtRAMDisk;                                             // The drive is a RAM disk
    21.   end;
    22.  
    23.   // if Result.DiskType = dtNotExists then                                                                                 // if NotExists then start checking for Disconnected drive
    24.     begin
    25.       lpnLength         := 0;                                                                                           // Init
    26.  
    27.       lError            := WNetGetConnection(PChar(aDiskSign), nil, lpnLength);                             // Get Size for lBufVolumeLabel in lpnLength
    28.  
    29.       if lError = ERROR_MORE_DATA then                                                                                  // size received in lpnLength
    30.         begin
    31.           SetLength(lBufVolumeLabel, MAX_PATH);
    32.           // lBufVolumeLabel := AllocMem(lpnLength);                                                        // Alloc memory for VolumeLabel buffer
    33.           try
    34.             lError := WNetGetConnection(PChar(aDiskSign), pChar(lBufVolumeLabel), lpnLength);                       // Get network name
    35.             if lError = ERROR_CONNECTION_UNAVAIL then                                                                   // It exists but is unavailable
    36.               begin
    37.                 Result.VolumeLabel := string(lBufVolumeLabel);                                             // Return volume label
    38.                 Result.DiskType := dtRemovableNotConnected;                                                             // Return DiskType
    39.                 Result.ImageIndex := SIID_DRIVENETDISABLED;                                                             // Set imageindex to disconnected icon
    40.               end
    41.             else
    42.               Result.DiskType := dtNotExists;                                                                           // otherwise reurn dtNotExists
    43.           finally
    44.             // FreeMem(lBufVolumeLabel, lpnLength);                                                                        // Free Memory
    45.           end;
    46.         end;
    47.     end;
    48. end;

  3. #33
    Win32.Trojan.Heur.Herby
    Join Date
    Dec 2003
    Location
    Nuenen of all places
    Posts
    289
    Kreeg jij geen melding over typecasten?

    Code:
      TDiskInfo                 = record
        ....
        VolumeLabel             : shortstring;
      end;
    
    
    // Result.VolumeLabel := string(lBufVolumeLabel);
    Result.VolumeLabel := ShortString(lBufVolumeLabel);
    Het werkt inderdaad nu bij de console en de VCL versie.
    Alleen snap ik het probleem met AllocMem niet, ik alloceer geheugen en ruim het netjes op, waarom dan toch een Access Denied in de VCL versie.

    Hoe dan ook, weer ontzettend bedankt voor je hulp

  4. #34
    Quote Originally Posted by Herby View Post
    Alleen snap ik het probleem met AllocMem niet, ik alloceer geheugen en ruim het netjes op, waarom dan toch een Access Denied in de VCL versie.
    Het is ook niet alleen de AllocMem en FreeMem die het probleem zijn.
    Want als ik er weer een lBufVolumeLabel2 tussen zet met AllowMem en FreeMem maar deze niet gebruik in WNetGetConnection, dan gaat het goed.
    Alleen als ik hem in WNetGetConnection gebruik dan gaat het mis.

    Raar. Maar met SetLength werkt het in ieder geval goed.

  5. #35
    Win32.Trojan.Heur.Herby
    Join Date
    Dec 2003
    Location
    Nuenen of all places
    Posts
    289
    ja dat klopt want in mijn applicatie klapt het er nu niet meer uit, kan ik weer verder

    Ontzettend bedankt.

  6. #36
    Quote Originally Posted by rvk View Post
    Waarom geeft mijn testcode uit post #2 dan ook een memory leak.
    Daar heb ik de AllocMem en Windows calls er helemaal uit gesloopt en alleen met een string gewerkt.
    Het probleem is volgens mij toch echt een string binnen een record.

    Je gebruikt daar FillChar, en overschrijft daarmee de string header, inclusief de refcount. Waarschijnlijk wordt de string opgeruimd als de refcount van 1 naar 0 gaat, maar dat mechanisme haal je onderuit door de refcount kunstmatig op 0 te zetten.
    1+1=b

  7. #37
    De VolumeLabel die in het record staat is inmiddels een shortstring waar geen refcount op zit.

    Ik zat nog te denken aan de AllocMem (die wel een fill met zero doet) maar met GetMem gaat het ook mis.

  8. #38
    Member
    Join Date
    Mar 2012
    Location
    Nederland
    Posts
    64
    Ik zou voor de buffer gewoon een TArray<Char> gebruiken. Zet die met SetLength op de juiste lengte en gebruik daarna SetString om de info in je record te zetten. Verder moet de FillChar weggehaald worden zoals GolezTrol al heeft gezegd, dat zorgt namelijk voor je memoryleak (waarschijnlijk vanaf het begin af aan). Delphi zorgt namelijk zelf voor het opruimen van de string door een refcount bij te houden, jij overschrijft die met allemaal nullen waardoor Delphi dus denkt dat de string leeg is en nooit meer het geheugen vrijgeeft. De FillChar is ook helemaal niet nodig, want in het begin van je DiskInfo functie initialiseer je alle velden van het record al.

    Delphi Code:
    1. unit DriveUtils;
    2.  
    3. interface
    4.  
    5. uses
    6.   System.SysUtils,
    7.   WinAPI.Windows,
    8.   Winapi.ShellAPI;
    9.  
    10. type
    11.   TDiskSign                 = string[2];
    12.   TDiskType                 = (dtUnknown, dtNotExists, dtRemovable, dtFixed, dtRemote, dtCDROM, dtRAMDisk, dtRemovableNotConnected);
    13.  
    14.   TDiskInfo                 = record
    15.     DiskSign                : string;
    16.     DiskType                : TDiskType;
    17.     VolumeLabel             : string;
    18.     ImageIndex              : integer;
    19.   end;
    20.  
    21. function DiskTypeToStr (aDiskType: TDiskType) : string;
    22. function GetDiskInfo (aDiskSign : String) : TDiskInfo;
    23.  
    24.  
    25. implementation
    26.  
    27.  
    28. function DiskTypeToStr (aDiskType: TDiskType) : string;
    29. begin
    30.   case aDiskType of
    31.     dtUnknown               : result := 'Unknown';
    32.     dtNotExists             : result := 'Does''t exists';
    33.     dtRemovable             : result := 'Removable';
    34.     dtFixed                 : result := 'Fixed';
    35.     dtRemote                : result := 'Remote';
    36.     dtCDROM                 : result := 'CDrom';
    37.     dtRAMDisk               : result := 'RAMdisk';
    38.     dtRemovableNotConnected : result := 'Removable disconnected';
    39.   end;
    40. end;
    41.  
    42. function GetDiskInfo (aDiskSign : String) : TDiskInfo;
    43. var
    44.   lpnLength             : Cardinal;
    45.   lError                : DWORD;
    46.   lBufVolumeLabel       : TArray<Char>;
    47. begin
    48.   Result.DiskSign       := aDiskSign;                                                                                   // TDiskInfo.Sign = Driveletter STRING[2]
    49.   Result.DiskType       := dtUnknown;                                                                                   // Init
    50.   Result.VolumeLabel    := '';                                                                                                                          // Init
    51.   Result.ImageIndex     := -1;                                                                                                                          // Init
    52.  
    53.  
    54.   case GetDriveType(PChar(IncludeTrailingPathDelimiter(aDiskSign))) of                                                                                  // Check if drive removable, fixed, CD-ROM, RAM disk, or network drive.
    55.     DRIVE_UNKNOWN       : Result.DiskType := dtUnknown;                                                                                               // The drive type cannot be determined
    56.     DRIVE_NO_ROOT_DIR   : Result.DiskType := dtNotExists;                                                                                             // The root path is invalid. For example, no volume is mounted at the path.
    57.     DRIVE_REMOVABLE     : Result.DiskType := dtRemovable;                                                                                             // The disk can be removed from the drive.
    58.     DRIVE_FIXED         : Result.DiskType := dtFixed;                                                                                                 // The disk cannot be removed from the drive
    59.     DRIVE_REMOTE        : Result.DiskType := dtRemote;                                                                                                // The drive is a remote (network) drive
    60.     DRIVE_CDROM         : Result.DiskType := dtCDROM;                                                                                                 // The drive is a CD-ROM drive
    61.     DRIVE_RAMDISK       : Result.DiskType := dtRAMDisk;                                                                                               // The drive is a RAM disk
    62.   end;
    63.  
    64.   if Result.DiskType = dtNotExists then                                                                                 // if NotExists then start checking for Disconnected drive
    65.     begin
    66.       lpnLength         := 0;                                                                                           // Init
    67.  
    68.       lError            := WNetGetConnection(PChar(aDiskSign), nil, lpnLength);                                                                     // Get Size for lBufVolumeLabel in lpnLength
    69.  
    70.       if lError = ERROR_MORE_DATA then                                                                                  // size received in lpnLength
    71.         begin
    72.           SetLength(lBufVolumeLabel, lpnLength);
    73.           lError := WNetGetConnection(PChar(aDiskSign), PChar(lBufVolumeLabel), lpnLength);                                                             // Get network name
    74.  
    75.           if lError = ERROR_CONNECTION_UNAVAIL then                                                                     // It exists but is unavailable
    76.             begin
    77.               SetString(Result.VolumeLabel, PChar(lBufVolumeLabel), lpnLength - 1);                                     // Return volume label, length includes terminating #0 char, we don't need that
    78.               Result.DiskType := dtRemovableNotConnected;                                                               // Return DiskType
    79.               Result.ImageIndex := SIID_DRIVENETDISABLED;                                                               // Set imageindex to disconnected icon
    80.             end
    81.           else
    82.             Result.DiskType := dtNotExists;                                                                             // otherwise reurn dtNotExists
    83.         end;
    84.     end;
    85.  
    86. end;
    87.  
    88.  
    89. end.

  9. #39
    Win32.Trojan.Heur.Herby
    Join Date
    Dec 2003
    Location
    Nuenen of all places
    Posts
    289
    Quote Originally Posted by The_Fox View Post
    Ik zou voor de buffer gewoon een TArray<Char> gebruiken. Zet die met SetLength op de juiste lengte en gebruik daarna SetString om de info in je record te zetten. Verder moet de FillChar weggehaald worden zoals GolezTrol al heeft gezegd, dat zorgt namelijk voor je memoryleak (waarschijnlijk vanaf het begin af aan). Delphi zorgt namelijk zelf voor het opruimen van de string door een refcount bij te houden, jij overschrijft die met allemaal nullen waardoor Delphi dus denkt dat de string leeg is en nooit meer het geheugen vrijgeeft. De FillChar is ook helemaal niet nodig, want in het begin van je DiskInfo functie initialiseer je alle velden van het record al.
    Nou je het inderdaad zegt, die FillChar had ik op een gegeven moment toegevoegd omdat ik wel een Volumelabel terug kreeg maar bij de volgende drive daar bras van overhield.

Page 3 of 3 FirstFirst 1 2 3

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •