views:

113

answers:

1

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.
+3  A: 

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

Petesh
Thanks .. i did not realised the issue!!! Ansifying the class made it works fine. I have edited the original message.
volvox