Pointeur invalide dans fonction DLL

Résolu
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 - 10 mars 2009 à 18:23
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 - 10 mars 2009 à 19:04
Bonjour,
toujours dans le cadre de la création d'une DLL Windows, j'ai encore un petit problème après le HWND_BROADCAST.
Je vous explique le contexte : une DLL qui permet de créer, ouvrir, gérer des logs enfin bref (pour l'instant chaque ligne du log contient un entier sur 32 bits pour commencer simple), tout ça genre "API".
J'ai mis au point 6 fonctions pour l'instant :

OpenLog, qui permet d'ouvrir un log (ne se laisse pas démonter si le fichier n'existe pas).
CloseLog, qui ferme un log.
CanAccess, qui indique si un processus peut accéder à un log ouvert selon ses paramètres.
ReadLog, qui lit l'intégralité d'un log et qui renvoie le tout dans une structure appropriée.
WriteLog, qui ajoute une ligne au log.

J'ai un problème avec ReadLog. Voici son implémentation complète (j'ai mis les commentaires en anglais c'est plus facile à lire - et plus explicite que le français) :

// Reads an entire log and stocks data in lpLog
function ReadLog(dwFile: Longword; dwID: Longword; var lpLog: LOG_STRUCT): Longword; stdcall;
const
LineSize = SizeOf(LOG_LINE);
Var
NLines: Longword;
I: Longword;
Reserved: Longword;
CurrentLine: LOG_LINE;
begin
Result := READLOG_ERROR; // Set function error return by default
if CanAccess(List[FilePos(dwFile)].lpPath, dwID) then // If access granted
begin
SetFilePointer(Result, 0, nil, FILE_BEGIN); // Places file pointer to beginning of file
NLines := GetFileSize(dwFile, nil) div LineSize; // Calculates number of lines in the log
SetLength(lpLog.lpLines, NLines); // Redims log lines array
for I := 0 to NLines - 1 do // For each line ...
begin
SetFilePointer(dwFile, I * LineSize, nil, FILE_BEGIN); // Moves file pointer
if not ReadFile(dwFile, CurrentLine, LineSize, Reserved, nil) then // Reads line and stocks it in the array
Exit // Stops function if read error
else lpLog.lpLines[I] := CurrentLine; // If file read succeeded, then stock line in lpLog structure
end;
Result := READLOG_SUCCESS; // Function has succeeded
end;
end;

Avec mon projet de test, après avoir ouvert un log avec OpenFile, je le lis en entier :

Var
Struct: LOG_STRUCT;
I: Integer;
begin
ReadLog(Log, 777, Struct); // 777 est ma clé de log (vous verrez bientôt)
// LOG_STRUCT est une structure de log
ListBox1.Clear;

for I := 0 to Length(Struct.lpLines) -1 do
ListBox1.Items.Add(IntToStr(Struct.lpLines[I].dwText));
end;

Bon tout va bien, je récupère bien mes entiers, mais un problème subsiste toujours : un EInvalidPointer (Opération de pointeur incorrect) arrive toujours à la fin de la fonction et du listage des entiers.

Je n'arrive même pas à déterminer si l'exception est causée par un code dans la DLL ou dans mon projet de test. Le code de la DLL me semble quand-même assez bien fait, et je pensais à un problème de libération de mémoire ... En effet voici la structure LOG_STRUCT :

LOG_LINE = packed record // A line of a log
//dwText: array [0..254] of Char; // Line contents
dwText: Longword;
end;

LOG_STRUCT = packed record // Log structure
lpLines: array of LOG_LINE; // Log lines
end;

Voilà je crois avoir tout dit, vous pouvez éventuellement demander du code supplémentaire j'ai tout sous la main, néanmoins je n'arrive pas à comprendre d'où vient cette exception ... vive les pointeurs ...

Merci d'avance :)

Cordialement, Bacterius !

4 réponses

f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 37
10 mars 2009 à 18:50
petite correction ici :

Var
Struct: LOG_STRUCT;
I: Integer;
begin
  ReadLog(Log, 777, Struct); // 777 est ma clé de log (vous verrez bientôt)

  ListBox1.Items.BeginUpdate;
  try
    ListBox1.Clear;
    for I := 0 to Length(Struct.lpLines) -1 do
      ListBox1.Items.Add(IntToStr(Struct.lpLines[I].dwText));
  finally
    ListBox1.Items.EndUpdate;
  end;     
end;

sinon pourquoi ne pas utiliser de Stream ? (TFileStream) exemple :

type
  TLogItem = LongWord;
  TLogLines = array of TLogItem;
  TLog = record
    Size : int64;
    Count: integer;
    Lines: TLogLines;
  end;

const
  LogItemSize = SizeOf(TLogItem);
 
function ReadLog(const FileName: string; var Log: TLog): integer;
var N, C : cardinal;
    Flx : TFileStream;
begin
  result := -1; // Error : File Not Found

  if not FileExists(FileName) then
    exit;
   
  result := 0; // Error : Stream error or file empty
 
  Flx := TFileStream.Create(FileName, fmOpenRead);
  try
    Log.Size := Flx.Size;
    Log.Count:= Log.Size div LogItemSize;
    SetLength(Log.Lines, Log.Count);
    for N := 0 to Log.Count-1 do
      Flx.Read(Log.Lines[N], LogItemSize);
    Result := 1; // Success
  finally
    Flx.Free;
  end;
end;

procedure LogToStringList(const Log: TLog; Strings: TStrings);
var N : integer;
begin
  Strings.BeginUpdate;
  try
    for N := 0 to Log.Count-1 do
      Strings.Add(IntToStr(Log.Lines[N]));
  finally
    Strings.EndUpdate;
  end;
end;

<hr size="2" width="100%" />
3
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 9
10 mars 2009 à 18:57
@f0xi : merci pour la clause try..finally et Begin/EndUpdate, je n'y avais pas pensé.
Sinon pour le TFileStream, je n'avais pas envie d'être dépendant d'une classe Delphi et je préfererais lire un fichier en appellant les API de bas niveau ReadFile et WriteFile.

Sinon merci pour l'idée de la structure TLog, je vais m'en inspirer, l'idée des "headers" avec la taille et le nombre de lignes est vraiment une bonne idée :)

Merci encore, je vais regarder et je reviens.

Cordialement, Bacterius !
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 9
10 mars 2009 à 18:59
Mais en fin de compte, d'où venait l'exception EInvalidPointer ??

Cordialement, Bacterius !
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 9
10 mars 2009 à 19:04
Ah j'ai réussi à trouver d'où venait l'erreur : en fait, le tableau dynamique lpLines de la structure LOG_STRUCT n'était pas libéré dans le bouton ReadFile. En tout cas j'ai fait un :

try FreeAndNil(Struct); except; end;

Et je reçois une violation d'accès gérée, mais plus d'opération de pointeur invalide.

Au moins ça c'est réglé, je vais réfléchir à comment mieux gérer la structure ...
Merci encore f0xi, je vais tenter de mettre en oeuvre ton idée de structure dans ma DLL :)

Cordialement, Bacterius !
0