1/24/2003

Resolved issues for APRO [Windows]

This file details all the resolved issues in APRO. The fixes are generated from our changes log. This page is being made available as a service to our customers, those who want to have the absolute latest code for their development. The issues listed may be present in older versions of APRO, having been unnoticed until the present time.

If you decide to make use of this information a couple of things must be made clear.


1. You do so at your own risk. TurboPower cannot provide any help to apply these fixes or to recompile packages, applications or DLLs after you have done so. It is assumed that if you are capable of applying these patches you are capable of recompiling APRO.

2. TurboPower's patch system requires an unaltered version of the product in order that it can patch properly. If you make any of these changes in this file (or any others for that matter), you will no longer have an unaltered version and the patch to the next minor version of APRO may fail. Our recommendation is to make a backup of your unadulterated APRO directory (and subdirectories). If you don't, you will have to reinstall APRO for the next version patch.

3. All fixes in this file will appear in the next release.

4. This file will be updated at irregular intervals. No announcement will be made when the file is updated. If you need all the fixes, it behooves you to periodically check and download it.

5. These fixes will not be provided in any other form. WYSIWYG.

Total number of resolved issues: 43

Issue

Fixed?

Fix date Description

1350

yes

11/5/2002 TInAddr conflicts with other components

1880

yes

1/7/2003 Multiple instances

3217

yes

11/4/2002 Once connected to an invalid ftp site, can't connect again.

3373

yes

11/1/2002 YModem locks files

3515

yes

9/19/2002 Need update the status when setting DTR and RTS.

3548

yes

11/4/2002 Cannot enter hex values in state conditions

3580

yes

10/30/2002 Error handling

3623

yes

10/31/2002 TAPI Hold and transfer capabilities

3688

yes

10/31/2002 TAdModem.BPSRate property not updated

3702

yes

9/19/2002 TApdSendFax, fpPageOK not used for class1

3756

yes

11/1/2002 enh: Add ability to force YModem to 128 byte blocks

3861

yes

9/17/2002 Invalid modem attributes in XML files

3866

yes

9/18/2002 State machine - Mem leak upon deactivating

3867

yes

11/4/2002 States - StartString and EndString do not escape strings

3879

yes

10/31/2002 Fax - Class 1.0 implementation omission

3887

yes

9/20/2002 Data packet - AV on destroy

3888

yes

9/20/2002 Assign/AssignFile overloads causing problems

3927

yes

9/24/2002 TAdModem AV when destroyed

3941

yes

9/25/2002 State machine accesses port after closing

3980

yes

11/5/2002 OnProcessChar Command ecAnswerBack does not work.

3981

yes

11/5/2002 Add OnProcessChar commands for cursor on/off

3982

yes

1/7/2003 Support for Siemens S35i (PDU Mode?)

4004

yes

10/9/2002 Dialing using tone/pulse with TAdModem.

4010

yes

11/4/2002 AV even though ftp://ftp.turbopower.com/pub/apro/updates/APROFixes.htm#3887 was applied.

4016

yes

10/29/2002 FConnectFired may have broken DoDisconnect.

4050

yes

11/5/2002 Request for read only properties to indicate if scroll bars in use.

4055

yes

11/1/2002 TAdModem - incorrect exception if modemcap folder not found

4056

yes

11/1/2002 TApdModemStatusDialog - Cancel button doesn't work

4057

yes

11/1/2002 TAdModem - AV if port not opened

4062

yes

11/4/2002 Data packet - AV on destroy revisited

4064

yes

11/5/2002 RAS - Add support for programatic phonebook additions

4065

yes

11/6/2002 RAS - Add support to retrieve connection statistics

4066

yes

11/5/2002 Invalid Scroll Regions cause AV

4067

yes

11/5/2002 Provide manual adjustment of character cell sizes in terminal

4068

yes

11/5/2002 TAdTerminalEmulator.teProcessCommand can AV with no terminal

4071

yes

11/6/2002 RAS - Missing some consts

4082

yes

11/8/2002 AV On destroy when turning off mouseselect

4096

yes

11/18/2002 TAdModem - incompatible with user's OnTriggerXxx

4121

yes

11/26/2002 OnTapiFail getting called twice for one failure.

4132

yes

12/3/2002 Fonts changing works incorrectly with VT100

4159

yes

12/6/2002 AdModem - SetDevConfig not forcing initialization

4177

yes

12/13/2002 TApdFaxConverter - idShell conversion may leave reg/ini keys

4186

yes

12/13/2002 TApdSendFax - Class1 error handling

Bug fixes and enhancements

Issue

Type

Description

1350

fix

TInAddr conflicts with other components
The TInAddr type was declared in AdWUtil.pas and AdWnPort.pas, which could 
cause a type conflict problem. To fix, move the following declarations to 
OOMisc.pas:

{$IFNDEF PrnDrv}

type
  { moved from AdWUtil }                                                 {!!.06}
  SunB = packed record
    s_b1, s_b2, s_b3, s_b4 : AnsiChar;
  end;
  { moved from AdWUtil }                                                 {!!.06}
  SunW = packed record
    s_w1, s_w2 : Word;
  end;

  { moved from AdWnPort and AdWUtil }                                    {!!.06}
  PInAddr = ^TInAddr;
  TInAddr = packed record
    case Integer of
      0 : (S_un_b : SunB);
      1 : (S_un_w : SunW);
      2 : (S_addr : LongInt);
  end;

  { XML support }
Back

1880

enh

Multiple instances
The TApdFaxDriverInterface is a single-instance component, only one can 
interface with the printer driver at any given time.  As a workaround, the 
4.06 printer driver provides several different ways to control the print job 
via registry/ini settings.
Back

3217

fix

Once connected to an invalid ftp site, can't connect again.
Connecting to an invalid FTP server (one that does not exist or that refuses 
the connection) will cause subsequent connection attempts by the TApdFTPClient 
to fail.  To fix, make the following change to AdFtp.pas marked by {!!.06}

function TApdCustomFtpClient.Login : Boolean;
  {log on to ftp server}
...
    end else begin                                                     
      { port is already open, must be trying to re-log in }
      SendCommand(fcUSER + ' ' + FUserName);                           
    end;
    if Result then                                                       {!!.06}
      ChangeState(psLogin);
  end;                                                                 
end;
Back

3373

fix

YModem locks files
  In AwAbsPcl.pas, make the following changes marked by {!!.06}
  procedure apStopProtocol(P : PProtocolData);
  ...
      {Close the file, if it's still open}
      if aFileOpen or (TFileRec(aWorkFile).Mode <> fmClosed) then begin  {!!.06}
        CloseFile(aWorkFile);                                            {!!.06}
        aFileOpen := False;
      end;  
Back

3515

fix

Need update the status when setting DTR and RTS.
Under Win9x, status triggers could be missed.  This was due to a timing problem 
with the notification we receive from the port drivers.  To fix, make the 
following change to AwUser.pas marked by {!!!}.  This has been tested on 
Win98SE, W2K and XP boxes, further testing is required. Search for "received 
status" to find the location to change, around line 4750 in 4.05)

...
        { Get any available data }
        ExtractData;

        {Check for received status & data triggers}
        if not fEventBusy then begin
          ModemStatus := GetModemStatus;{!!!}
          while CheckStatusTriggers do
            if ClosePending then
              Exit;
          while CheckReceiveTriggers do
            if ClosePending then
              Exit;
        end;
...
Back

3548

fix

Cannot enter hex values in state conditions
The TApdState.Conditions.StartString and EndString properties do not support 
non-printable characters in the object inspector.  To fix, make the following 
change to AdPropEd.pas marked by {!!.06} and rebuild the packages.

  { property editor for TApdState strings }
  RegisterPropertyEditor(TypeInfo(string), TApdStateCondition,           {!!.06}
                         'StartString', TApdPacketStringProperty);       {!!.06}
  RegisterPropertyEditor(TypeInfo(string), TApdStateCondition,           {!!.06}
                         'EndString', TApdPacketStringProperty);         {!!.06}
Back

3580

enh

Error handling
Error handling in the printer drivers could use some tweaking. 4.06 greatly 
improved error handling and printer driver customization, enabled through 
registry entries.  Changes are quite numerous, contact tech support if you need 
the revisions.

Registry entries are described below. 
NOTE, for Windows Terminal Server/Clients, changing the root to 
HKEY_CURRENT_USER, and using the ShellHandle and ShellName entries may allow 
you to control the printer driver under this environment.

  The fax printer driver supports several registry entries to control the
  print jobs. Absence of these values will cause default behavior.
  HKEY_LOCAL_MACHINE
    ApdRegKey - defined in OOMisc.pas
      // idShell conversions
      ShellHandle : Integer, determines whether we are in an idShell conversion
                    this is the window handle that will receive our messages
      ShellName   : string, the name of the resulting APF for an idShell 
                    conversion

      // spawning app when print job starts
      AutoExec    : string, the name of an app to spawn if a
                    TApdFaxDriverInterface isn't found
      Timeout     : Integer, the time we'll wait for the app to spawn

      // debug logging
      EventLogging: Boolean, whether we log the codes/subcodes
      DumpLogging : Boolean, whether we record the raw printer data

      // general
      DefFileName : string, the default name of the resulting APF
      SuppressAV  : Bool, true to suppress any APRO-raised AVs*

      // Post-print job APF modifications
      HeadFiller  : Integer, a 1-byte value to be written to the APF's file
                    header in the Filler field, can be used to identify the
                    machine, job, etc
      HeadPadding : string, a 26-char value to be written to the APF's file
                    header in the Padding field, can be used for phone number,
                    ID, etc
Back

3623

enh

TAPI Hold and transfer capabilities
TAPI Transfer, Hold and UnHold methods added to TApdTapiDevice.  Quite 
extensive changes ranging across AdTapi.pas and AdTUtil.pas.  Modified unit 
available from http://www.aprozilla.com/betatest.htm.
Back

3688

fix

TAdModem.BPSRate property not updated
Fixed as a side-effect of a 4.04 change.
Back

3702

fix

TApdSendFax, fpPageOK not used for class1
The fpPageOK FaxProgress flag was not used for Class1 transmits.  To fix, make 
the following changes marked by {!!.06} to AwFax.pas:

  procedure fFaxTransmit(Msg, wParam : Cardinal;
                        lParam : LongInt);
    {-Perform one increment of a fax transmit}
  ...
          tf1WaitMCF :
                    ...
                      {No more pages}
                      caPutFrameT(FP);
                      fState := tf1SendDCN;
                    end;
                end;

                if cReceivedFrame in [RTPFrame, MCFFrame] then begin     {!!.06}
                  aFaxProgress := fpPageOK;                              {!!.06}
                  cForceStatus := True;                                  {!!.06}
                end;                                                     {!!.06}

                {Ask for the next frame if there are more coming}
Back

3756

enh

enh: Add ability to force YModem to 128 byte blocks
New TApdProtocol.YModem128ByteBlocks property added (public).  Set to true to 
start YModem in 128-byte blocks and prohibit 1K blocks.  Not normally required.
Back

3861

fix

Invalid modem attributes in XML files
Several of the modemcap files had invalid attributes.  Most notably, the 
Friendly names of some modems contained comments from the original INF file.  
For example, the Rockwell 33.6 modem (in mdmrock4.xml), had a FriendlyName of
  FriendlyName = "&quot;Rockwell 33.6 PnP&quot; ;//WHQL"
when it should have been 
  FriendlyName = "Rockwell 33.6 PnP"

To fix, download the new modemcap.zip from 
ftp://ftp.turbopower.com/pub/apro/updates/, or manually remove the comments 
from the XML files.
Back

3866

fix

State machine - Mem leak upon deactivating
When a state is deactivated, the internal PacketList is not cleared, leading to 
a memory leak and Index out of bounds exceptions.  To fix, make the following 
change to AdStMach.pas marked by {!!.05}:

procedure TApdStateComPortSource.StateMachineDeactivate (State : 
TApdCustomState);
var
  I : Integer;
begin
  { disable and free our Condition's data packets }
  for I := 0 to pred(PacketList.Count) do begin
    TApdDataPacket(PacketList[I]).Free;
    PacketList[I] := nil;
  end;
  PacketList.Clear;                                                      {!!.05}
end;
Back

3867

fix

States - StartString and EndString do not escape strings
Same as bug 3548.  Entering the strings at run-time can be done literally.
Back

3879

fix

Fax - Class 1.0 implementation omission
When we're using FaxClass 1.0, we are sending the wrong FCLASS= command. To 
fix, make the following changes to AwFax.pas marked by {!!.06}:

  procedure fFaxReceive(Msg, wParam : Cardinal;
  ...
        {Main state machine}
        case fState of
          rfInit :
            begin
              ...
              {Set the fax class}
              if aClassInUse = ctClass1 then begin
                fState := rf1Init1;
                caPutModem(FP, cClassCmd);                               {!!.06}
              end else begin
                fState := rf2Init1;
  ....

  function fPrepareFaxReceive(FP : PFaxRec) : Integer;
  ...
      {Set class}
      if (fFirstState <> rf2GetSenderID) then
        if aClassInUse = ctClass1 then begin
          if not caProcessModemCmd(FP, cClassCmd) then begin             {!!.06}
            Cleanup;
            Exit;
  ....
Back

3887

fix

Data packet - AV on destroy
Under certain conditions, the TApdDataPacket can cause an AV when being 
destroyed.  To fix, make the following changes to AdPacket.pas marked by 
{!!.06}:

procedure TApdDataPacketManager.DisablePackets;
var
  i : integer;
begin
  { this can get called when destroying, and called in the context of }
  { different threads, make sure the PacketList is still around }
  if Assigned(PacketList) do                                             {!!.06}
    for i := 0 to pred(PacketList.Count) do
      if Assigned(PacketList[i]) then                                    {!!.06}
        with TApdDataPacket(PacketList[i]) do
          Disable;
end;
Back

3888

fix

Assign/AssignFile overloads causing problems
Delphi 6.00 had a bug in the Assign/AssignFile methods which would cause AVs 
when PChar parameters were passed to those methods. Since the bowels of APRO 
contains many instances where we pass PChars to these methods, they were 
overloaded in 3.07.  Tests with Delphi 6.02 reveal that these bugs have been 
fixed.  The overloaded methods were not all-inclusive, which would cause 
compiler errors when using a non-overloaded version.  To fix, comment out the 
following sections in OOMisc.pas:

{.$IFDEF Delphi6}                                                        {!!.06}
{ These methods were overloaded to work around a Delphi 6 bug.  Tests with
  Delphi 6.02 reveal that the bugs have been fixed. Comment-out the declarations
  in the implementation section below also.
procedure AssignFile(var F: File; const FileName: string); overload;
procedure AssignFile(var F: TextFile; const FileName : string); overload;
procedure Assign(var F: File; const FileName: string); overload;
procedure Assign(var F: TextFile; const FileName: string); overload;}
{.$ENDIF}                                                                {!!.06}

implementation
...
{.$IFDEF Delphi6}                                                        {!!.06}
{ These methods were overloaded to work around a Delphi 6 bug.  Tests with
  Delphi 6.02 reveal that the bugs have been fixed. Comment-out the declarations
  in the interface section above also.
procedure AssignFile(var F: File; const FileName: string);
begin
  System.AssignFile(F, FileName);
end;

procedure AssignFile(var F: TextFile; const FileName : string);
begin
  System.AssignFile(F, FileName);
end;

procedure Assign(var F: File; const FileName: string);
begin
  System.Assign(F, FileName);
end;

procedure Assign(var F: TextFile; const FileName: string);
begin
  System.Assign(F, FileName);
end;}
{.$ENDIF}


Back

3927

fix

TAdModem AV when destroyed
Destroying a TAdModem when the ComPort property is not assigned will cause an 
AV. To fix, make the following change to AdMdm.pas marked by {!!.06}:

destructor TAdCustomModem.Destroy;
  { we're being destroyed }
begin
  DeallocateHWnd(FHandle);                                               {!!.02}
  ResponsePacket.Free;
  FNegotiationResponses.Free;
  FSelectedDevice.Free;
  LibModem.Free;
  if Assigned(FComPort) then                                             {!!.06}
    FComPort.DeregisterUserCallbackEx(PortOpenCloseEx);                  {!!.05}
  inherited Destroy;
end;
Back

3941

fix

State machine accesses port after closing
The state machine will access the port when deactivated to write to the 
dispatcher log.  This can cause an ie_NOpen exception under some conditions. To 
fix, make the following change to AdStMach.pas marked by {!!.06}

procedure TApdStateComPortSource.StateDeactivate (State : TApdCustomState);
begin
  if FComPort.Open then                                                  {!!.06}
    FComPort.AddStringToLog (Name + ': Deactivate');
end;
Back

3980

fix

OnProcessChar Command ecAnswerBack does not work.
Changes to extensive to list.
Back

3981

enh

Add OnProcessChar commands for cursor on/off
Dependent on other changes.
Back

3982

fix

Support for Siemens S35i (PDU Mode?)
PDU mode added for 4.06
Back

4004

fix

Dialing using tone/pulse with TAdModem.

In the AdMdm.pas unit make the following changes marked {!!.06} below:

    apw_StartDial :
      begin
        ResponsePacket.Enabled := True;
        if FModemConfig.ToneDial then                                   {!!.06}
          FComPort.Output := ConvertXML(LmModem.Settings.Prefix +
                                        LMModem.Settings.DialPrefix +
                                        LmModem.Settings.Tone +         {!!.06}
                                        FPhoneNumber +
                                        LmModem.Settings.Terminator)
        else
          FComPort.Output := ConvertXML(LmModem.Settings.Prefix +
                                        LMModem.Settings.DialPrefix +
                                        LmModem.Settings.Pulse +        {!!.06}
                                        FPhoneNumber +
                                        LmModem.Settings.Terminator);
        DoStatus(msConnectWait);
      end;
Back

4010

fix

AV even though ftp://ftp.turbopower.com/pub/apro/updates/APROFixes.htm#3887 was applied.
An AV can occur when the TApdDataPacket is destroyed.  To fix, make the 
following change to AdPacket.pas marked by {!!.06}. Note, this also affects 
design-time, depending on the creation order of the TApdComPort and 
TApdDataPacket.  To prevent the AV at design-time, either drop TApdComPorts on 
the form before dropping the TApdDataPackets, or rebuild the run-time and 
design-time packages after making this change.

procedure TApdDataPacket.SetComPort(const NewComPort : TApdCustomComPort);
var
  Manager : TApdDataPacketManager;
begin
  if NewComPort <> fComPort then begin
    if Assigned(fComPort) then begin
      { remove the old port hooks }
      Manager := PacketManagerList.GetPortManager(fComPort);             {!!.06}
      if Assigned(Manager) then                                          {!!.06}
        Manager.Remove(Self);                                            {!!.06}
    end;                                                                 {!!.06}
    FComPort := NewComPort;
    if Assigned(fComPort) then begin
      { add the new port hooks }
      Manager := PacketManagerList.GetPortManager(fComPort);
      if Manager = nil then
        Manager := TApdDataPacketManager.Create(fComPort);
      Manager.Insert(Self);
    end;
  end;
end;
Back

4016

fix

FConnectFired may have broken DoDisconnect.
Change 3733 (4.05) broke the server's OnDisconnect event generation.  The 
OnDisconnect event would not fire when the client or server disconnected.  To 
fix, make the following change to AdWnPort.pas marked by {!!.06}

procedure TApdCustomWinsockPort.DoDisconnect;
begin
  if (FConnectFired or (FWsMode = WsServer))and Assigned(FOnWsDisconnect){!!.06}
    then FOnWsDisconnect(Self);
  FConnectFired := False;                                                {!!.05}
end;
Back

4050

fix

Request for read only properties to indicate if scroll bars in use.
Make the following changes to AdCustomTerminal in the AdTrmEmu unit.

      property Scrollback : boolean
                  read FScrollback write tmSetScrollback;
      property UseLazyDisplay : boolean
                  read FUseLazyDisplay write tmSetUseLazyDisplay
                  default adc_TermUseLazyDisplay;
      property UsingHScrollBar : Boolean                                 {!!.06}
               read FUseHScrollbar;                                      {!!.06}
      property UsingVScrollBar : Boolean                                 {!!.06}
               read FUseVScrollbar;                                      {!!.06}
      property WantAllKeys : boolean
                  read FWantAllKeys write tmSetWantAllKeys
                  default adc_TermWantAllKeys;
      property FreezeScrollBack : boolean
                  read FFreezeScrollBack write tmSetFreezeScrollBack
                  default adc_FreezeScrollBack;
Back

4055

fix

TAdModem - incorrect exception if modemcap folder not found
If the TAdModem.ModemcapFolder is not found, an exception was raised in the XML 
parsing code that wasn't very clear.  To fix, make the following change to 
AdMdm.pas marked by {!!.06}

function TAdCustomModem.SelectDevice: Boolean;
  { display the modem selection dialog }
begin
  try
    Result := False;                                                     {!!.06}
    if not DirectoryExists(FModemCapFolder) then                         {!!.06}
      raise EInOutError.CreateFmt(                                       {!!.06}
        'Modemcap folder not found'#13#10'(%s)', [FModemCapFolder]);     {!!.06}
Back

4056

fix

TApdModemStatusDialog - Cancel button doesn't work
The Cancel button on the modem status dialog doesn't work. To fix, make the 
following change to AdMdmDlg.pas marked by {!!.06}

procedure TApdModemStatusDialog.btnCancelClick(Sender: TObject);
begin
  if Assigned(FModem) then
    Postmessage(FModem.Handle, apw_CancelCall, 0, 0);                    {!!.06}
end;

Back

4057

fix

TAdModem - AV if port not opened
An AV can be raised when showing the modem status dialog if the port is not 
open. To fix, make the following change to AdMdmDlg.pas marked by {!!.06}:

procedure TApdModemStatusDialog.SetModem(const NewModem : TAdCustomModem);
begin
  FModem := NewModem;
  if Assigned(FModem) then begin                                         {!!.06}
    lblUsingDevice.Caption := FModem.SelectedDevice.Name;
    if Assigned(FModem.ComPort) then                                     {!!.06}
      lblUsingPort.Caption := Format('COM%d', [FModem.ComPort.ComNumber]){!!.06}
    else                                                                 {!!.06}
      lblUsingPort.Caption := 'No com port component assigned';          {!!.06}
  end;                                                                   {!!.06}
end;
Back

4062

fix

Data packet - AV on destroy revisited
This bug was entered to consolidate the code changes to fix the AV problems 
with the 4.05 TApdDataPacket. 


procedure TApdDataPacketManager.DisablePackets;
var
  i : integer;
begin
  { this can get called when destroying, and called in the context of }
  { different threads, make sure the PacketList is still around }
  if Assigned(PacketList) do                                             {!!.06}
    for i := 0 to pred(PacketList.Count) do
      if Assigned(PacketList[i]) then                                    {!!.06}
        with TApdDataPacket(PacketList[i]) do
          Disable;
end;



destructor TApdDataPacketManagerList.Destroy;
begin
  while ManagerList.Count > 0 do
    with TApdDataPacketManager(ManagerList[pred(ManagerList.Count)]) do begin
      { we're only being destroyed from the Finalization block, it's OK to   }
      { set fComPort to nil here since that will be destroyed shortly anyway }
      fComPort := nil;                                                   {!!.06}
      Free;                                                              {!!.06}
    end;
  ManagerList.Free;
  inherited Destroy;
end;
Back

4064

enh

RAS - Add support for programatic phonebook additions
There wasn't a way to programatically add a phone book entry (without showing 
the RAS phonebook dialog and requiring user intervention).  To add this 
enhancement, TApdRasDialer.AddPhonebookEntry, .ValidateEntryName 
and .GetPhonebookEntry methods were added.  To add these methods, make the 
following changes marked with {!!.06} to the following units. An example of 
using these new methods will be available from 
ftp://ftp.turbopower.com/pub/apro/demos/_Index.htm (ExRasPB.zip)

Since these are rather extensive changes, with lots of duplications, only some 
changes are listed.  Instructions for applying the changes are marked below 
with "**". The changes span several units, do not attempt to test-compile until 
all changes are in-place (it won't work until everything is changed.)

AdRas.pas

**add the following 3 methods to the TApdCustomRasDialer in the public section:

function TApdCustomRasDialer.AddPhonebookEntry(PBEntryName : string;     {!!.06}
  RasEntry : TRasEntry; TapiConfigRec : TTapiConfigRec): Integer;
{ add a new phonebook entry }
var
  EntrySize : DWORD;
  DevInfoSize : DWORD;
  TempPhoneBook : string;
begin
  { make sure the entry name is valid }
  Result := AdRasValidateEntryName(FPhoneBook, PBEntryName);
  if Result = 0 then begin
    EntrySize := SizeOf(TRasEntry);
    if IsWinNT then begin
      TempPhoneBook := FPhoneBook;
      DevInfoSize := 0;
    end else begin
      { Win9x/ME doesn't use phone book or TAPI config params }
      TempPhoneBook := '';
      DevInfoSize := SizeOf(TTapiConfigRec);
    end;
    { Required items for RasEntry are szPLocalPhoneNumber, szDeviceName, }
    { szDeviceType, dwFramingProtocol and dwfOptions. See help for       }
    { RasSetEntryProperties for details }
    Result := AdRasSetEntryProperties(TempPhonebook,
                                      PBEntryName,
                                      @RasEntry,
                                      EntrySize,
                                      @TapiConfigRec,
                                      DevInfoSize)
  end;
end;

function TApdCustomRasDialer.GetPhonebookEntry(PBEntryName: string;      {!!.06}
  var RasEntry: TRasEntry; var TapiConfigRec: TTapiConfigRec): Integer;
var
  RasEntrySize : DWORD;
  DevInfoSize : DWORD;
begin
  RasEntrySize := SizeOf(TRasEntry);
  FillChar(RasEntry, RasEntrySize, 0);
  RasEntry.dwSize := RasEntrySize;
  DevInfoSize := SizeOf(DevInfoSize);
  FillChar(TapiConfigRec, DevInfoSize, 0);
  Result := AdRasGetEntryProperties(FPhoneBook,
                                    PBEntryName,
                                    @RasEntry,
                                    RasEntrySize,
                                    @TapiConfigRec,
                                    DevInfoSize);    
end;

function TApdCustomRasDialer.ValidateEntryName(EntryName:string):Integer;{!!.06}
  {Validates an entry name}
begin
  Result := AdRasValidateEntryName(FPhoneBook, EntryName);
end;


AdRasUtl.pas

**add AdExcept and OOMisc to the interface uses clause, comment out 
implementation uses clause.

**several type definitions moved to OOMisc.pas. See that section below
and comment out/delete the definition for those types in this unit.

** The RasGetEntryProperties and RasSetEntryProperties used the wrong type 
in the parameters. Search for "EntryProperties" in this unit to find
the proc types, prototypes and methods for them.  Change the lpDevideInfo
parameter type to PTapiConfigRec. Here is one as an example:

  TRasGetEntryProperties = function(lpszPhonebook, lpszEntry: PChar;
                                    lpEntry: PRasEntry;
                                    var lpEntrySize : DWord;
                                    lpDeviceInfo : PTapiConfigRec;       {!!.06}
                                    var lpDeviceInfoSize : DWord
                                    ): DWord; stdcall;

This should be applied to the TRasGetEntryProperties and TRasSetEntryProperties
type definitions, and the interface and implementation of the 
AdRasGetEntryProperties and AdRasSetEntryProperties functions.


OOMisc.pas
**Moved several types and consts to OOMisc.pas so they are available from
a common location. Copy the following section and paste it into OOMisc. The 
EventTimer definition and "const   {Compile-time configurations}" are already
in OOMisc, only placed here to show where to paste. The units where these
were moved from is in comments, comment out the original definitions in those
units as well.

  {Standard event timer record structure used by all timing routines}
  EventTimer = record
    StartTicks : LongInt;  {Tick count when timer was initialized}
    ExpireTicks : LongInt; {Tick count when timer will expire}
  end;

type{ moved from AdTapi.pas }                                            {!!.06}
  { TAPI device config record, opaque and undefined by definition }      {!!.06}
  PTapiConfigRec = ^TTapiConfigRec;                                      {!!.06}
  TTapiConfigRec = record                                                {!!.06}
    DataSize : Cardinal;                                                 {!!.06}
    Data : array[0..1023] of Byte;                                       {!!.06}
  end;

{ moved from AdRasUtl.pas }                                              {!!.06}
const {RasMaximum buffer sizes}                                          {!!.06}
  RasMaxDomain      = 15;                                                {!!.06}
  RasMaxPassword    = 256;                                               {!!.06}
  RasMaxUserName    = 256;                                               {!!.06}
  RasMaxEntryName   = 256;                                               {!!.06}
  RasMaxPhoneBook   = 256;                                               {!!.06}
  RasMaxError       = 256;                                               {!!.06}
  RasMaxEntries     = 64;                                                {!!.06}
  RasMaxDeviceName  = 128;                                               {!!.06}
  RasMaxDeviceType  = 16;                                                {!!.06}
  RasMaxPhoneNumber = 128;                                               {!!.06}
  RasMaxCallBackNum = 128;                                               {!!.06}
  RasMaxAreaCode    = 10;                                                {!!.06}
  RasMaxPadType     = 32;                                                {!!.06}
  RasMaxX25Address  = 200;                                               {!!.06}
  RasMaxIPAddress   = 15;                                                {!!.06}
  RasMaxIPXAddress  = 21;                                                {!!.06}
  RasMaxFacilities  = 200;                                               {!!.06}
  RasMaxUserData    = 200;                                               {!!.06}

type  { moved from AdRasUtl.pas }                                        {!!.06}
  {RAS IP address - "a.b.c.d"}                                           {!!.06}
  PRasIPAddr = ^TRasIPAddr;                                              {!!.06}
  TRasIPAddr = record                                                    {!!.06}
    a : byte;                                                            {!!.06}
    b : byte;                                                            {!!.06}
    c : byte;                                                            {!!.06}
    d : byte;                                                            {!!.06}
  end;                                                                   {!!.06}

type { moved from AdRasUtl.pas }                                         {!!.06}
  {RAS phonebook entry properties}                                       {!!.06}
  PRasEntry = ^TRasEntry;                                                {!!.06}
  TRasEntry = record                                                     {!!.06}
    dwSize             : DWord;                                          {!!.06}
    dwOptions          : DWord;                                          {!!.06}
    dwCountryID        : DWord;                                          {!!.06}
    dwCountryCode      : DWord;                                          {!!.06}
    szAreaCode         : array[0..RasMaxAreaCode] of char;               {!!.06}
    szLocalPhoneNumber : array[0..RasMaxPhoneNumber] of char;            {!!.06}
    dwAlternatesOffset : DWord;                                          {!!.06}
    IPAddr             : TRasIPAddr;                                     {!!.06}
    IPAddrDns          : TRasIPAddr;                                     {!!.06}
    IPAddrDnsAlt       : TRasIPAddr;                                     {!!.06}
    IPAddrWins         : TRasIPAddr;                                     {!!.06}
    IPAddrWinsAlt      : TRasIPAddr;                                     {!!.06}
    dwFrameSize        : DWord;                                          {!!.06}
    dwNetProtocols     : DWord;                                          {!!.06}
    dwFramingProtocol  : DWord;                                          {!!.06}
    szScript           : array[0..Max_PATH-1] of char;                   {!!.06}
    szAutodialDll      : array[0..Max_PATH-1] of char;                   {!!.06}
    szAutodialFunc     : array[0..Max_PATH-1] of char;                   {!!.06}
    szDeviceType       : array[0..RasMaxDeviceType] of char;             {!!.06}
    szDeviceName       : array[0..RasMaxDeviceName] of char;             {!!.06}
    szX25PadType       : array[0..RasMaxPadType] of char;                {!!.06}
    szX25Address       : array[0..RasMaxX25Address] of char;             {!!.06}
    szX25Facilities    : array[0..RasMaxFacilities] of char;             {!!.06}
    szX25UserData      : array[0..RasMaxUserData] of char;               {!!.06}
    dwChannels         : DWord;                                          {!!.06}
    dwReserved1        : DWord;                                          {!!.06}
    dwReserved2        : DWord;                                          {!!.06}
  end;                                                                   {!!.06}

const
  {Compile-time configurations}


AdTapi.pas
** comment-out the TTapiConfigRec definition, it has been moved to OOMisc.
  {TTapiConfigRec definition moved to OOMisc to support RAS}             {!!.06}
Back

4065

enh

RAS - Add support to retrieve connection statistics
The 4.05 TApdRasDialer did not have a way to retrieve the connection 
statistics. To add this enhancement, make the following changes marked by 
{!!.06} to the following units. 
NOTE: Several new types and DLL imports are added, exact placement in their 
respective units is not important. Placement instructions are provided in-line, 
marked with **.
See the ExRasStat.zip archive on 
ftp://ftp.turbopower.com/pub/apro/demos/_Index.htm for an example.

OOMisc.pas
{**can be placed anywhere in the interface section}
type
  PRasStatistics = ^TRasStatistics;                                      {!!.06}
  TRasStatistics = record                                                {!!.06}
    dwSize                    : DWORD;                                   {!!.06}
    dwBytesXmited             : DWORD;                                   {!!.06}
    dwBytesRcved              : DWORD;                                   {!!.06}
    dwFramesXmited            : DWORD;                                   {!!.06}
    dwFramesRcved             : DWORD;                                   {!!.06}
    dwCrcErr                  : DWORD;                                   {!!.06}
    dwTimeoutErr              : DWORD;                                   {!!.06}
    dwAlignmentErr            : DWORD;                                   {!!.06}
    dwHardwareOverrunErr      : DWORD;                                   {!!.06}
    dwFramingErr              : DWORD;                                   {!!.06}
    dwBufferOverrunErr        : DWORD;                                   {!!.06}
    dwCompressionRatioIn      : DWORD;                                   {!!.06}
    dwCompressionRatioOut     : DWORD;                                   {!!.06}
    dwBps                     : DWORD;                                   {!!.06}
    dwConnectDuration         : DWORD;                                   {!!.06}
  end;                                                                   {!!.06}


AdRasUtl.pas
{RASAPI32 DLL function prototypes}
{**can be placed anywhere in this section}
  TRasClearConnectionStatistics = function(Conn : HRasConn               {!!.06}
                                           ) : DWORD; stdcall;           {!!.06}

  TRasGetConnectionStatistics = function(Conn : HRasConn;                {!!.06}
                                         lpStatistics : PRasStatistics   {!!.06}
                                         ) : DWord; stdcall;             {!!.06}

{ RAS DLL routine wrappers and public routines }
{**can be placed anywhere in this section}
function AdRasClearConnectionStatistics(HConn : THandle) : Integer;      {!!.06}

function AdRasGetConnectionStatistics(HConn : THandle;                   {!!.06}
                                      PStatistics : PRasStatistics       {!!.06}
                                      ) : Integer;                       {!!.06}

var {RAS DLL functions}
{**can be placed anywhere in this section}
  RasClearConnectionStatistics : TRasClearConnectionStatistics = nil;    {!!.06}
  RasGetConnectionStatistics : TRasGetConnectionStatistics = nil;        {!!.06}

{ Misc utilities }
procedure LoadRASDLL;
begin
  ...
    @RasDial := GetProcAddress(RASModule, 'RasDialA');
    @RasEnumConnections := GetProcAddress(RASModule, 'RasEnumConnectionsA');
    @RasClearConnectionStatistics := GetProcAddress(RasModule,           {!!.06}
      'RasClearConnectionStatistics');                                   {!!.06}
    @RasGetConnectionStatistics := GetProcAddress(RASModule,             {!!.06}
      'RasGetConnectionStatistics');                                     {!!.06}
    @RasGetConnectStatus := GetProcAddress(RASModule, 'RasGetConnectStatusA');
    @RasGetErrorString := GetProcAddress(RASModule, 'RasGetErrorStringA');
  ...

{**Following methods can be placed immediately before Initialization block}
function AdRasClearConnectionStatistics(HConn : THandle) : Integer;      {!!.06}
begin                                                                    {!!.06}
  LoadRASDLL;                                                            {!!.06}
  if Assigned(RasClearConnectionStatistics) then                         {!!.06}
    Result := RasClearConnectionStatistics(HConn)                        {!!.06}
  else                                                                   {!!.06}
    Result := ecRasFunctionNotSupported;                                 {!!.06}
end;                                                                     {!!.06}

function AdRasGetConnectionStatistics(HConn : THandle;                   {!!.06}
                                      PStatistics : PRasStatistics       {!!.06}
                                      ) : Integer;                       {!!.06}
begin                                                                    {!!.06}
  LoadRASDLL;                                                            {!!.06}
  if Assigned(RasGetConnectionStatistics) then                           {!!.06}
    Result := RasGetConnectionStatistics(HConn, PStatistics)             {!!.06}
  else                                                                   {!!.06}
    Result := ecRasFunctionNotSupported;                                 {!!.06}
end;                                                                     {!!.06}


AdRas.pas
{**Add to public section of TApdCustomRasDialer}
    function  ClearConnectionStatistics : Integer;                       {!!.06}
    function  GetConnectionStatistics(                                   {!!.06}
      var Statistics : TRasStatistics) : Integer;                        {!!.06}

function TApdCustomRasDialer.ClearConnectionStatistics : Integer;        {!!.06}
begin                                                                    {!!.06}
  Result := AdRasClearConnectionStatistics(Connection);                  {!!.06}
end;                                                                     {!!.06}

function  TApdCustomRasDialer.GetConnectionStatistics(                   {!!.06}
  var Statistics : TRasStatistics) : Integer;                            {!!.06}
begin                                                                    {!!.06}
  FillChar(Statistics, SizeOf(TRasStatistics), 0);                       {!!.06}
  Statistics.dwSize := SizeOf(TRasStatistics);                           {!!.06}
  Result := AdRasGetConnectionStatistics(Connection, @Statistics);       {!!.06}
end;                                                                     {!!.06}
Back

4066

fix

Invalid Scroll Regions cause AV
Make the following changes to AdTrmBuf.pas

procedure TAdTerminalBuffer.SetScrollRegion(aTopRow, aBottomRow : integer);
var
  Temp : integer;
begin
  FBeyondMargin := false;
  {if the top row is greater than the bottom row, they're out of
   order, so switch 'em round}
  if (aTopRow > aBottomRow) then begin
    Temp := aTopRow;
    aTopRow := aBottomRow;
    aBottomRow := Temp;
  end;
  {$IFDEF UseRangeChecks}
  if ((aBottomRow - aTopRow) < 1) or
     (aTopRow < 1) or (aTopRow > RowCount) or
     (aBottomRow < 1) or (aBottomRow > RowCount) then
    raise Exception.Create('TAdTerminalBuffer.SetScrollRegion: invalid row 
number(s)');
  {$ELSE}                                                                {!!.06}
  if ((aBottomRow - aTopRow) < 1) then                                   {!!.06}
    Exit;                                                                {!!.06}
  if (aTopRow < 1) then                                                  {!!.06}
    aTopRow := 1;                                                        {!!.06}
  if (aTopRow > RowCount) then                                           {!!.06}
    aTopRow := RowCount;                                                 {!!.06}
  if (aBottomRow < 1) then                                               {!!.06}
    aBottomRow := 1;                                                     {!!.06}
  if (aBottomRow > RowCount) then                                        {!!.06}
    aBottomRow := RowCount;                                              {!!.06}
  {$ENDIF}
  FSRStartRow := tbCvtToInternalRow(aTopRow, true);
  FSREndRow := tbCvtToInternalRow(aBottomRow, true);
  {force the scroll region to be used}
  if UseScrollRegion then
    UseScrollRegion := false;
  if (aTopRow <> 1) or (aBottomRow <> RowCount) then
    UseScrollRegion := true;
end;
Back

4067

fix

Provide manual adjustment of character cell sizes in terminal
Changes are too extensive to list.
Back

4068

fix

TAdTerminalEmulator.teProcessCommand can AV with no terminal
Change is dependant on other changes.
Back

4071

fix

RAS - Missing some consts
In addition to bug 4064, these consts should be added to OOMisc.pas, inserted 
after TRasEntry declaration.

const   {RASENTRY 'dwfOptions' bit flags}                                {!!.06}
  RASEO_UseCountryAndAreaCodes    = $00000001;                           {!!.06}
  RASEO_SpecificIpAddr            = $00000002;                           {!!.06}
  RASEO_SpecificNameServers       = $00000004;                           {!!.06}
  RASEO_IpHeaderCompression       = $00000008;                           {!!.06}
  RASEO_RemoteDefaultGateway      = $00000010;                           {!!.06}
  RASEO_DisableLcpExtensions      = $00000020;                           {!!.06}
  RASEO_TerminalBeforeDial        = $00000040;                           {!!.06}
  RASEO_TerminalAfterDial         = $00000080;                           {!!.06}
  RASEO_ModemLights               = $00000100;                           {!!.06}
  RASEO_SwCompression             = $00000200;                           {!!.06}
  RASEO_RequireEncryptedPw        = $00000400;                           {!!.06}
  RASEO_RequireMsEncryptedPw      = $00000800;                           {!!.06}
  RASEO_RequireDataEncryption     = $00001000;                           {!!.06}
  RASEO_NetworkLogon              = $00002000;                           {!!.06}
  RASEO_UseLogonCredentials       = $00004000;                           {!!.06}
  RASEO_PromoteAlternates         = $00008000;                           {!!.06}
  RASEO_SecureLocalFiles          = $00010000;                           {!!.06}
  RASEO_RequireEAP                = $00020000;                           {!!.06}
  RASEO_RequirePAP                = $00040000;                           {!!.06}
  RASEO_RequireSPAP               = $00080000;                           {!!.06}
  RASEO_Custom                    = $00100000;                           {!!.06}
  RASEO_PreviewPhoneNumber        = $00200000;                           {!!.06}
  RASEO_SharedPhoneNumbers        = $00800000;                           {!!.06}
  RASEO_PreviewUserPw             = $01000000;                           {!!.06}
  RASEO_PreviewDomain             = $02000000;                           {!!.06}
  RASEO_ShowDialingProgress       = $04000000;                           {!!.06}
  RASEO_RequireCHAP               = $08000000;                           {!!.06}
  RASEO_RequireMsCHAP             = $10000000;                           {!!.06}
  RASEO_RequireMsCHAP2            = $20000000;                           {!!.06}
  RASEO_RequireW95MSCHAP          = $40000000;                           {!!.06}
  RASEO_CustomScript              = $80000000;                           {!!.06}

  {RASENTRY 'dwNetProtocols' bit flags}                                  {!!.06}
  RASNP_NetBEUI                   = $00000001;                           {!!.06}
  RASNP_Ipx                       = $00000002;                           {!!.06}
  RASNP_Ip                        = $00000004;                           {!!.06}

  {RASENTRY 'dwFramingProtocols' bit flags}                              {!!.06}
  RASFP_Ppp                       = $00000001;                           {!!.06}
  RASFP_Slip                      = $00000002;                           {!!.06}
  RASFP_Ras                       = $00000004;                           {!!.06}

  {RASENTRY 'szDeviceType' default strings}                              {!!.06}
  RASDT_Modem                     = 'modem';                             {!!.06}
  RASDT_Isdn                      = 'isdn';                              {!!.06}
  RASDT_X25                       = 'x25';                               {!!.06}
  RASDT_Vpn                       = 'vpn';                               {!!.06}
  RASDT_Pad                       = 'pad';                               {!!.06}
  RASDT_Generic                   = 'GENERIC';                           {!!.06}
  RASDT_Serial                    = 'SERIAL';                            {!!.06}
  RASDT_FrameRelay                = 'FRAMERELAY';                        {!!.06}
  RASDT_Atm                       = 'ATM';                               {!!.06}
  RASDT_Sonet                     = 'SONET';                             {!!.06}
  RASDT_SW56                      = 'SW56';                              {!!.06}
  RASDT_Irda                      = 'IRDA';                              {!!.06}
  RASDT_Parallel                  = 'PARALLEL';                          {!!.06}
Back

4082

fix

AV On destroy when turning off mouseselect

Make the changes indicated by a !!.06 to TAdCustomTerminal.HideSelection in the 
AdTrmEmu unit.
 
procedure TAdCustomTerminal.HideSelection;
var
  i        : integer;
  ColCount : integer;
begin
  {Don't clear if nothing is selected }                                  {!!.06}
  if (IsRectEmpty (FLButtonRect)) then                                   {!!.06}
    Exit;                                                                
{!!.06} 
  {clear the current selection}
  ColCount := FEmulator.Buffer.ColCount;
  tmMarkDeselected(FLButtonRect.Top, FLButtonRect.Left, ColCount);
  for i := succ(FLButtonRect.Top) to pred(FLButtonRect.Bottom) do
    tmMarkDeselected(i, 1, ColCount);
  tmMarkDeselected(FLButtonRect.Bottom, 1, FLButtonRect.Right);
  {initialize the selection variables}
  SetRectEmpty(FLButtonRect);
  FLButtonAnchor.X := 0;
  FLButtonAnchor.Y := 0;
  FHaveSelection := false;
end;
Back

4096

fix

TAdModem - incompatible with user's OnTriggerXxx
The TAdModem installed it's own internal OnTriggerTimer and OnTriggerStatus 
event handlers, which would overwrite the developer's event handlers.  
Symptoms are the TApdComPort.OnTriggerStatus and OnTriggerTimer events not 
firing after opening the TAdModem.  The fix is somewhat extensive, contact 
tech support for the new unit.
Back

4121

fix

OnTapiFail getting called twice for one failure.
To fix, move setting the flag above the call to FOnTapiFail from inside the 
TapiFail procedure and make the following changes marked {!!.06} in AdTapi.pas 
unit as follows:

  procedure TApdCustomTapiDevice.TapiFail;
    {-Generate the TapiFail event}
  begin
    {Call the user's event handler}
    if not TapiFailFired then begin
      TapiFailFired := True;                                            {!!.06}
      if Assigned(FOnTapiFail) then
        FOnTapiFail(Self);
      //TapiFailFired := True;  moved up above                          {!!.06}
      if not Open then                                                  {!!.04}
        { if we're open, then we were either already waiting for a call }
        { or have a call already } 
        FWaitingForCall := False;                                       {!!.04}
    end                                                                
  end;
Back

4132

fix

Fonts changing works incorrectly with VT100
Make the following changes indicated by !!.06 to the 
TAdVT100Emulator.vttExecutePaintScript method in the AdTrmEmu.pas unit.  Make 
sure that you keep an unmodified version of AdTrmEmu.pas around in case things 
go wrong.

...
      {display the bit o'text}
      if (FontName = DefaultFontName) then
        Canvas.Font := Font
      else begin
        FSecondaryFont.Name := FontName;
        Canvas.Font := FSecondaryFont;
      end;
      Canvas.Font.Color := ForeColor;
      {$IFDEF VERSION3}
      if Assigned (Terminal.Font) then                                   {!!.06}
        Canvas.Font.CharSet := Terminal.Font.CharSet                     {!!.06}
      else                                                               {!!.06}
        Canvas.Font.CharSet := DEFAULT_CHARSET;
      {$ENDIF}
      if DblHeight then
        Canvas.Font.Size := Canvas.Font.Size * 2;

      ExtTextOut(Canvas.Handle,
                 WorkRect.Left,
                 WorkRect.Top,
                 ETO_OPAQUE,
                 @WorkRect,
                 FDisplayStr,
                 PartTextLen,
                 @FCellWidths^);
...
Back

4159

fix

AdModem - SetDevConfig not forcing initialization
Calling the TAdModem.SetDevConfig with a new configuration does not cause the 
modem to be reinitialized.  To fix, make the following change to AdMdm.pas 
marked by {!!.06}

procedure TAdCustomModem.SetDevConfig(const Config: TApdModemConfig);
  { forces new configuration }
begin
  {$IFDEF AdModemDebug}
  if Assigned(FComPort) then
    FComPort.AddStringToLog('ConfigChange');
  {$ENDIF}
  if CompareMem(@FModemConfig, @Config, SizeOf(TApdModemConfig)) then   {!!.06}
    Initialized := False;                                               {!!.06}
  FModemConfig := Config;
end;
Back

4177

fix

TApdFaxConverter - idShell conversion may leave reg/ini keys
When using the idShell converter in the TApdFaxConverter, the TApdFaxConverter 
adds registry/ini keys when the conversion starts, and the printer driver 
deletes them when the print job ends.  Under some conditions, the printer 
driver does not start (see "Keys left in registry after conversion timeout" in 
the apro.fax newsgroup, 12/13/2002), so the printer driver does not delete the 
keys.  As a failsafe measure, add the following changes marked by {!!.06} to 
AdFaxCvt.pas, which will delete the keys from the TApdFaxConverter also.

procedure TApdCustomFaxConverter.ConvertShell(const FileName: string);
  { print the selected document to the fax printer driver using ShellExecute }
begin
  ...
  finally
    if DefPrnChanged then                                               {!!.01}
      ChangeDefPrinter(False);                                          {!!.01}
    Status(False, True, FShellPageCount, 0, 0, 0, DummyBool);           {!!.01}
    { remove the registry/ini keys, just in case the printer driver }
    { failed to do so }
    if IsWinNT then begin                                               {!!.06}
      Reg := TRegistry.Create;                                          {!!.06}
      try                                                               {!!.06}
        Reg.RootKey := HKEY_LOCAL_MACHINE;                              {!!.06}
        Reg.OpenKey(ApdRegKey,False);                                   {!!.06}
        Reg.DeleteValue('ShellName');                                   {!!.06}
        Reg.DeleteValue('ShellHandle');                                 {!!.06}
      finally                                                           {!!.06}
        Reg.Free;                                                       {!!.06}
      end;                                                              {!!.06}
    end else begin                                                      {!!.06}
      Ini := TIniFile.Create(ApdIniFileName);                           {!!.06}
      try                                                               {!!.06}
        Ini.DeleteKey(ApdIniSection, 'ShellHandle');                    {!!.06}
        Ini.DeleteKey(ApdIniSection, 'ShellName');                      {!!.06}
        {$IFDEF Delphi4}                                                {!!.06}
        Ini.UpdateFile;                                                 {!!.06}
        {$ENDIF}                                                        {!!.06}
      finally                                                           {!!.06}
        Ini.Free;                                                       {!!.06}
      end;                                                              {!!.06}
    end;                                                                {!!.06}
  end;                                                                  {!!.01}
end;
Back

4186

fix

TApdSendFax - Class1 error handling
When sending a fax using fcClass1 we report an error when the receiver 
disconnects after we send out 'last page' ack request. This only happens in 
Class1, only with some receivers, and only when they disconnect after we say 
there are no more pages to send. According to the fax specs, a remote that 
doesn't ack the last page message causes the session to fail; however, it is a 
relatively common implementation to diconnect like this.  Since the page data 
has already been transmitted, and it's the last page, we're going to deviate a 
bit from the specs and report this as a successful transmission. Apply the 
following changes marked by {!!.06} to AwFax.pas:

          tf1PrepareEOP :
            begin
              Inc(cRetry);
              if cRetry > 3 then begin
                if fState = tf1WaitMCF then begin                       {!!.06}
                { some receivers will disconnect after receiving the MCF }
                { frame, which is our message that all pages have been   }
                { sent. According to the spec, this is a fatal error, but}
                { it's a common implementation in real-life. This change }
                { generates the OnFaxError event with ErrorCode = -8071, }
                { but also generates an OnFaxFinish with ErrorCode = 0.  }
                { HangupCode is set to 52 ("MPS sent three times without }
                { response"), but it can still be considered a successful}
                { fax since the remote received all pages.               }
                  afReportError(FP, ecFaxMCFNoAnswer);                  {!!.06}
                  aFaxError := ecOK;                                    {!!.06}
                  cHangupCode := 52;                                    {!!.06}
                  cForceStatus := True;                                 {!!.06}
                  fState := tf1Hangup;                                  {!!.06}
                end else begin                                          {!!.06}
                  afReportError(FP, ecTimeout);
                  cForceStatus := True;
                  fState := tfAbort;
                end                                                     {!!.06}
           end else begin
                DelayMS(PreEOPDelay);

Also, add the following to OOMisc.pas:
...
  ecNoAnswer               = -8074;   {Remote fax did not answer}
  ecAlreadyMonitored       = -8075;   {MonitorDir already being used}
  ecFaxMCFNoAnswer         = -8076;{Remote disconnected after last page}{!!.06}

const
Back