Problem using TEncodedStream with a Tstringlist
HAving this procedure (DELPHI 2010):
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;
PROBLEM: Anything executed after FLogParams.SaveToStream (EncStr) line (exemple info message) or after the procedure has executed is in error :: i get an ACCESS VIOLATION error on the EXE.
I have tested the same TEncodedStream clas开发者_运维知识库s with text to be saved coming from a Tmemo and it works fine, so i guest the fault is in the TStringList used to hold the temporary text (FLogParams is a TStringList previously created and released when the form is destroyed).
THnks for help.
Note: The TEncodedStream class was written by M.Cantu. It is the following:
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.
I don't have a windows pc nearby to test it, but at a guess, you're hitting the Char is a multi-byte item on Delphi 2010, while the code from the TEncodeStream class is assuming that Char is a single byte item. You should convert the code from the TEncodeStream class to explicitly use a AnsiString/AnsiChar
精彩评论