Pointeur invalide dans fonction DLL [Résolu]

Bacterius 3869 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention - 10 mars 2009 à 18:23 - Dernière réponse : Bacterius 3869 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention
- 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 !
Afficher la suite 

Votre réponse

4 réponses

Meilleure réponse
f0xi 4304 Messages postés samedi 16 octobre 2004Date d'inscription 9 mars 2018 Dernière intervention - 10 mars 2009 à 18:50
3
Merci
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%" />

Merci f0xi 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 72 internautes ce mois-ci

Commenter la réponse de f0xi
Bacterius 3869 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention - 10 mars 2009 à 18:57
0
Merci
@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 !
Commenter la réponse de Bacterius
Bacterius 3869 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention - 10 mars 2009 à 18:59
0
Merci
Mais en fin de compte, d'où venait l'exception EInvalidPointer ??

Cordialement, Bacterius !
Commenter la réponse de Bacterius
Bacterius 3869 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention - 10 mars 2009 à 19:04
0
Merci
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 !
Commenter la réponse de Bacterius

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.