将 TEncodedStream 与 Tstringlist 一起使用时出现问题
执行此过程(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;
问题:在 FLogParams.SaveToStream (EncStr) 行(示例信息消息)之后或在该过程执行之后执行的任何内容都是错误的 :: 我在 EXE 上收到访问冲突错误。
我已经测试了相同的 TEncodedStream 类,其中包含来自 Tmemo 的要保存的文本,并且工作正常,所以我认为错误在于用于保存临时文本的 TStringList (FLogParams 是先前创建的 TStringList,并在表单被销毁时释放) )。
谢谢帮助。
注意:TEncodedStream 类由 M.Cantu 编写。其内容如下:
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.
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 class 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我附近没有 Windows 电脑来测试它,但猜测,您在 Delphi 2010 上遇到的 Char 是多字节项,而 TEncodeStream 类中的代码假设 Char 是单字节项。您应该将 TEncodeStream 类中的代码转换为显式使用 AnsiString/AnsiChar
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