2010-09-26 10 views
2

avoir cette procédure (DELPHI 2010):Problème d'utilisation TEncodedStream avec un TStringList

procedure TfrmMainApp.ChangeLogon; 
var 
    EncStr: TEncodedStream; // from M.Cantu, see below 
    LogonName : tUserName; 
    LogonPW : tPassword; 
    MessageString: string; 
begin 
    if MessageDlg('You are about to change the login to the Connection server. Do you wish to continue?', 
    mtWarning, [mbYes, mbNo], 0) = mrYes then 
    begin 
    LogonName := ''; 
    LogonPW := ''; 
    with dlgPWLogIn do 
    begin 
     Caption := 'Change Database Logon'; 
     edtPassword.CharCase := ecNormal; 
     gbPrompt.Caption := 'Enter User name:'; 
     edtPassword.PasswordChar := #0; 
    end; 
    if dlgPWLogIn.ShowModal = mrOK then 
    begin 
     LogonName := dlgPWLogIn.edtPassword.Text; 
     dlgPWLogIn.Release; 
     Application.CreateForm(TdlgPWLogIn, dlgPWLogIn); 
     with dlgPWLogIn do 
     begin 
     Caption := 'Change Logon'; 
     edtPassword.CharCase := ecNormal; 
     gbPrompt.Caption := 'Enter Password:'; 
     edtPassword.PasswordChar := cPASSWORD_CHAR; 
     end; 
     if dlgPWLogIn.ShowModal = mrOK then 
     begin 
     LogonPW := dlgPWLogIn.edtPassword.Text; 
     FLogParams.Clear; 
     FLogParams.Add(trim(LogonName)); 
     FLogParams.Add(trim(LogonPW)); 
     //* send and save above params to logon txt file 
     EncStr := TEncodedStream.Create('dblogon.txt', fmCreate); 
     try 
      FLogParams.SaveToStream (EncStr); 
      // ... 
      // ... 
      // ... anything executed here is in error! 
     finally 
      begin 
      EncStr.Free; 
      end; 
     end; 
     end 
     else 
     MessageDlg('Cancelled By User.', mtInformation, [mbOK], 0); 
    end 
    else 
     MessageDlg('Cancelled By User.', mtInformation, [mbOK], 0); 
    end 
    else 
    MessageDlg('Cancelled By User.', mtInformation, [mbOK], 0); 
end; 

PROBLÈME: Tout exécuté après FLogParams.SaveToStream (EncStr) ligne (message exemple d'information) ou après la procédure a exécuté est en erreur :: j'obtiens une erreur ACCES DE VIOLATION sur l'EXE.

J'ai testé la même classe TEncodedStream avec le texte à sauvegarder provenant d'un Tmemo et ça marche bien, donc l'invité est la TStringList utilisée pour contenir le texte temporaire (FLogParams est une TStringList précédemment créée et libérée quand le formulaire est détruit).


THnks pour l'aide.

Remarque: La classe TEncodedStream a été écrite par M.Cantu. Il est le suivant:

unit EncodStr; 

    Interface 
    uses 
     Classes; 
    type 
     TEncodedStream = class (TFileStream) 
     private 
     FKey: Char; 
     public 
     constructor Create(const FileName: string; Mode: Word); 
     function Read(var Buffer; Count: Longint): Longint; override; 
     function Write(const Buffer; Count: Longint): Longint; override; 
     property Key: Char read FKey write FKey default 'A'; 
     end; 

    implementation 

    constructor TEncodedStream.Create(
     const FileName: string; Mode: Word); 
    begin 
     inherited Create (FileName, Mode); 
     FKey := 'A'; 
    end; 

    function TEncodedStream.Write(const Buffer; 
     Count: Longint): Longint; 
    var 
     pBuf, pEnc: PChar; 
     I, EncVal: Integer; 
    begin 
     // allocate memory for the encoded buffer 
     GetMem (pEnc, Count); 
     try 
     // use the buffer as an array of characters 
     pBuf := PChar (@Buffer); 
     // for every character of the buffer 
     for I := 0 to Count - 1 do 
     begin 
      // encode the value and store it 
      EncVal := (Ord (pBuf[I]) + Ord(Key)) mod 256; 
      pEnc [I] := Chr (EncVal); 
     end; 
     // write the encoded buffer to the file 
     Result := inherited Write (pEnc^, Count); 
     finally 
     FreeMem (pEnc, Count); 
     end; 
    end; 

    function TEncodedStream.Read(var Buffer; Count: Longint): Longint; 
    var 
     pBuf, pEnc: PChar; 
     I, CountRead, EncVal: Integer; 
    begin 
     // allocate memory for the encoded buffer 
     GetMem (pEnc, Count); 
     try 
     // read the encoded buffer from the file 
     CountRead := inherited Read (pEnc^, Count); 
     // use the output buffer as a string 
     pBuf := PChar (@Buffer); 
     // for every character actually read 
     for I := 0 to CountRead - 1 do 
     begin 
      // decode the value and store it 
      EncVal := (Ord (pEnc[I]) - Ord(Key)) mod 256; 
      pBuf [I] := Chr (EncVal); 
     end; 
     finally 
     FreeMem (pEnc, Count); 
     end; 
     // return the number of characters read 
     Result := CountRead; 
    end; 
    end. 


--------- 

Exemple of using this class given by M CAntu: 

    unit EncForm; 

    interface 

    uses 
     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
     StdCtrls, ExtCtrls; 

    type 
     TFormEncode = class(TForm) 
     Memo1: TMemo; 
     Memo2: TMemo; 
     OpenDialog1: TOpenDialog; 
     SaveDialog1: TSaveDialog; 
     Panel1: TPanel; 
     BtnLoadPlain: TButton; 
     BtnSaveEncoded: TButton; 
     BtnLoadEncoded: TButton; 
     Splitter1: TSplitter; 
     procedure BtnSaveEncodedClick(Sender: TObject); 
     procedure BtnLoadEncodedClick(Sender: TObject); 
     procedure BtnLoadPlainClick(Sender: TObject); 
     private 
     { Private declarations } 
     public 
     { Public declarations } 
     end; 

    var 
     FormEncode: TFormEncode; 

    implementation 

    {$R *.DFM} 

    uses 
     EncodStr; 

    procedure TFormEncode.BtnSaveEncodedClick(Sender: TObject); 
    var 
     EncStr: TEncodedStream; 
    begin 
     if SaveDialog1.Execute then 
     begin 
     EncStr := TEncodedStream.Create(SaveDialog1.Filename, fmCreate); 
     try 
      Memo1.Lines.SaveToStream (EncStr); 
     finally 
      EncStr.Free; 
     end; 
     end; 
    end; 

    procedure TFormEncode.BtnLoadEncodedClick(Sender: TObject); 
    var 
     EncStr: TEncodedStream; 
    begin 
     if OpenDialog1.Execute then 
     begin 
     EncStr := TEncodedStream.Create(OpenDialog1.FileName, fmOpenRead); 
     try 
      Memo2.Lines.LoadFromStream (EncStr); 
     finally 
      EncStr.Free; 
     end; 
     end; 
    end; 

    procedure TFormEncode.BtnLoadPlainClick(Sender: TObject); 
    begin 
     if OpenDialog1.Execute then 
     Memo1.Lines.LoadFromFile (
      OpenDialog1.FileName); 
    end; 

    end. 

============================= 


EDITED: 

Thanks: Ansifying the TEncodedStream corrected the problem: 

unit EncodStr; 

interface 

uses 
    Classes; 

type 
    TEncodedStream = class (TFileStream) 
    private 
    FKey: ansiChar; 
    public 
    constructor Create(const FileName: string; Mode: Word); 
    function Read(var Buffer; Count: Longint): Longint; override; 
    function Write(const Buffer; Count: Longint): Longint; override; 
    property Key: ansiChar read FKey write FKey default 'A'; 
    end; 

implementation 

constructor TEncodedStream.Create(
    const FileName: string; Mode: Word); 
begin 
    inherited Create (FileName, Mode); 
    FKey := 'A'; 
end; 

function TEncodedStream.Write(const Buffer; 
    Count: Longint): Longint; 
var 
    pBuf, pEnc: PansiChar; 
    I, EncVal: Integer; 
begin 
    // allocate memory for the encoded buffer 
    GetMem (pEnc, Count); 
    try 
    // use the buffer as an array of characters 
    pBuf := PansiChar (@Buffer); 
    // for every character of the buffer 
    for I := 0 to Count - 1 do 
    begin 
     // encode the value and store it 
     EncVal := (Ord (pBuf[I]) + Ord(Key)) mod 256; 
     pEnc [I] := AnsiChar (EncVal); 
    end; 
    // write the encoded buffer to the file 
    Result := inherited Write (pEnc^, Count); 
    finally 
    FreeMem (pEnc, Count); 
    end; 
end; 

function TEncodedStream.Read(var Buffer; Count: Longint): Longint; 
var 
    pBuf, pEnc: PansiChar; 
    I, CountRead, EncVal: Integer; 
begin 
    // allocate memory for the encoded buffer 
    GetMem (pEnc, Count); 
    try 
    // read the encoded buffer from the file 
    CountRead := inherited Read (pEnc^, Count); 
    // use the output buffer as a string 
    pBuf := PansiChar (@Buffer); 
    // for every character actually read 
    for I := 0 to CountRead - 1 do 
    begin 
     // decode the value and store it 
     EncVal := (Ord (pEnc[I]) - Ord(Key)) mod 256; 
     pBuf [I] := ansiChar (EncVal); 
    end; 
    finally 
    FreeMem (pEnc, Count); 
    end; 
    // return the number of characters read 
    Result := CountRead; 
end; 
end. 
+0

Veuillez ne pas appeler 'Trim' sur un mot de passe. Vous devriez accepter chaque caractère verbatim. Si un mot de passe arrive au début ou à la fin avec un espace, alors qu'il en soit ainsi. –

+0

merci pour le fint. – volvox

Répondre

3

Je n'ai pas un PC Windows à proximité de le tester, mais une supposition, vous frappez le Char est un élément multi-octets sur Delphi 2010, alors que le code de la classe TEncodeStream suppose que Char est un élément à un seul octet. Vous devez convertir le code de la classe TEncodeStream pour utiliser explicitement un AnsiString/AnsiChar

+0

Merci .. je n'ai pas réalisé le problème !!! En répondant à la classe, cela a bien fonctionné. J'ai modifié le message original. – volvox