APRO ReferenAPRO ReferenceGuideceGuide
APRO ReferenAPRO ReferenceGuideceGuide
For over fifteen years youve depended on TurboPower to provide the best
tools and libraries for your development tasks. Now try SysTools 3 and
XMLPartner Professionaltwo of TurboPowers best selling products
risk free. Both are fully compatible with Borland Delphi and C++Builder,
and are backed with our expert support and 60-day money back guarantee.
SYSTOOLS 3
D E V E LO P, D E B U G , O P T I M I Z E
TM
H E L P S YO U B U I L D YO U R B E S T
F R O M S TA RT TO F I N I S H , T U R B O P O W E R
Async
Professional
Async Professional
TM
Our new XSL Processor with XPath support, filter set, and EXMLPro utility
make it easy to add XML capabilities to your applications.
www.turbopower.com
Async Professional 4 requires Microsoft Windows (9x,Me,NT,2000 or XP) and Borland Delphi 3 and above,or C++Builder 3 and above
Reference Guide
XMLPARTNER PROFESSIONAL
REFERENCE GUIDE
The comprehensive guide to using Async Professional
Async Professional
4
Reference Guide
TurboPower Software Company
Colorado Springs, CO
www.turbopower.com
1998-2001 TurboPower Software Company. All rights reserved.
First Edition January 1998
Second Edition November 1999
Third Edition September 2001
License Agreement
This software and accompanying documentation are protected by United States copyright law and also by International
Treaty provisions. Any use of this software in violation of copyright law or the terms of this agreement will be prosecuted to
the best of our ability.
Copyright 1998-2001 by TurboPower Software Company, all rights reserved.
TurboPower Software Company authorizes you to make archival copies of this software for the sole purpose of back-up and
protecting your investment from loss. Under no circumstances may you copy this software or documentation for the
purposes of distribution to others. Under no conditions may you remove the copyright notices made part of the software or
documentation.
You may distribute, without runtime fees or further licenses, your own compiled programs based on any of the source code
of Async Professional. You may not distribute any of the Async Professional source code, compiled units, or compiled
example programs without written permission from TurboPower Software Company.
Note that the previous restrictions do not prohibit you from distributing your own source code, units, or components that
depend upon Async Professional. However, others who receive your source code, units, or components need to purchase
their own copies of Async Professional in order to compile the source code or to write programs that use your units or
components.
The supplied software may be used by one person on as many computer systems as that person uses. Group programming
projects making use of this software must purchase a copy of the software and documentation for each member of the
group. Contact TurboPower Software Company for volume discounts and site licensing agreements.
This software and accompanying documentation is deemed to be commercial software and commercial computer
software documentation, respectively, pursuant to DFAR Section 227.7202 and FAR 12.212, as applicable. Any use,
modification, reproduction, release, performance, display or disclosure of the Software by the US Government or any of its
agencies shall be governed solely by the terms of this agreement and shall be prohibited except to the extent expressly
permitted by the terms of this agreement. TurboPower Software Company, 15 North Nevada Avenue, Colorado Springs, CO
80903-1708.
With respect to the physical media and documentation provided with Async Professional, TurboPower Software Company
warrants the same to be free of defects in materials and workmanship for a period of 60 days from the date of receipt. If you
notify us of such a defect within the warranty period, TurboPower Software Company will replace the defective media or
documentation at no cost to you.
TurboPower Software Company warrants that the software will function as described in this documentation for a period of
60 days from receipt. If you encounter a bug or deficiency, we will require a problem report detailed enough to allow us to
find and fix the problem. If you properly notify us of such a software problem within the warranty period, TurboPower
Software Company will update the defective software at no cost to you.
TurboPower Software Company further warrants that the purchaser will remain fully satisfied with the product for a period
of 60 days from receipt. If you are dissatisfied for any reason, and TurboPower Software Company cannot correct the
problem, contact the party from whom the software was purchased for a return authorization. If you purchased the product
directly from TurboPower Software Company, we will refund the full purchase price of the software (not including shipping
costs) upon receipt of the original program media and documentation in undamaged condition. TurboPower Software
Company honors returns from authorized dealers, but cannot offer refunds directly to anyone who did not purchase a
product directly from us.
TURBOPOWER SOFTWARE COMPANY DOES NOT ASSUME ANY LIABILITY FOR THE USE OF ASYNC
PROFESSIONAL BEYOND THE ORIGINAL PURCHASE PRICE OF THE SOFTWARE. IN NO EVENT WILL
TURBOPOWER SOFTWARE COMPANY BE LIABLE TO YOU FOR ADDITIONAL DAMAGES, INCLUDING ANY
LOST PROFITS, LOST SAVINGS, OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF
THE USE OF OR INABILITY TO USE THESE PROGRAMS, EVEN IF TURBOPOWER SOFTWARE COMPANY HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
By using this software, you agree to the terms of this section and to any additional licensing terms contained in the
DEPLOY.HLP file. If you do not agree, you should immediately return the entire Async Professional package for a refund.
All TurboPower product names are trademarks or registered trademarks of TurboPower Software Company. Other brand
and product names are trademarks or registered trademarks of their respective holders.
Table of Contents
Chapter 1: Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
Files Supplied . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4
The Component Hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8
Organization of this Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17
Technical Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19
3
4
6
7
196
201
224
229
234
238
245
253
262
263
9
10
11
12
13
14
15
16
17
1
1
1
1
FTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
TApdProtocol Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
TApdFtpClient Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
TApdAbstractStatus Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
TApdProtocolStatus Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
TApdProtocolLog Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
521
523
559
578
582
583
1
2
3
588
591
594
624
649
674
689
693
695
698
704
715
736
754
764
769
779
809
815
822
826
828
830
834
4
5
6
7
8
9
10
11
12
13
838
839
841
856
862
865
872
875
14
15
16
17
1
1
Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .888
Name Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .894
Identifier Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i
7
8
9
10
11
12
13
14
15
16
17
1
1
Chapter 1: Introduction
1
2
3
4
A flexible data packet component that informs you when data that meets your criteria
New state machine components that let you design and implement protocols.
New SAPI components to add Speech to your applications. Now your applications
can speak (Text to Speech) and listen (Speech to Text).
New IP Telephony components to implement full streaming audio and video over
your network.
New Non-TAPI modem database using TurboPowers NEW modemcap XML format.
10
Use the TAPI modem definitions (from the INF files) to control your modem when
TAPI doesnt cut it.
New SMS pager component to take advantage of the Short Message System.
11
A scripting component that contains properties and methods for automating basic
12
communication operations like logging on and off, file upload and file download.
13
14
A RAS dialing component to that gives you more control over your Dial-Up
Networking via the Remote Access Server API.
15
File Transfer Protocol (FTP) components that take care of the FTP protocol details
and present a friendly interface, allowing you to transfer huge files from the Internet
and support resumable transfers. An FTP logging component automates the process
of logging an FTP client-server dialog for auditing FTP activities.
16
17
1
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
TAPI components for working with modems in TAPI environments like Windows
95/98, Windows NT 4.0, and Windows 2000.
A new modem component that provides a simple interface for accessing the most
commonly used modem operations. TAdModem integrates the selection of the
modem from the new modem database and the dialog to show the current status of
the modem.
A file transfer protocol component for transferring files using an Xmodem, Ymodem,
Zmodem, Kermit, or ASCII protocol.
File transfer status and file transfer logging components to display the progress of a
file transfer and create a history file of files sent or received.
Fax Client and Server components that make it easy to create a distributed fax server
system.
A fax conversion component that converts color BMP, monochrome PCX, DCX,
TIFF and text files to a faxable format, and a fax unpacking component that unpacks
received faxes into image files or memory bitmaps. Components for printing and
viewing faxes are also included.
Fax printer drivers and an interface component that provide a print-to-fax feature
from any Windows program.
Fax send and receive components for transmitting and receiving fax files using Class
1, Class 1.0, Class 2 and Class 2.0 faxmodems.
14
15
16
17
2 Chapter 1: Introduction
1
1
Deprecated components
As Async Professional has matured through the years, several components have become
obsolete, or have been replaced by components with greater functionality. Some of these
components have been deprecated to allow APRO to evolve, while still maintaining some
degree of backwards compatibility.
Previous version of APRO have moved the deprecated components to a separate tab on the
component palette, this version of APRO has deprecated even that. The deprecated
components are installed on your installation destination folder in the \Bonus folder. The
units in this folder contain the component source for several components that can be
installed in your palette.
We do not plan to make any enhancements to these components, and technical support for
these products will have a very low priority. These components may be completely removed
from future versions of APRO. In short, we highly recommend that you do not use these
components for new development.
6
7
TApdModem, TApdSModem: These files were used for non-TAPI modem control
using the TApdModemDBase component. They have been replaced by the
TAdModem and TApdLibModem components.
Modem dialer and status components using the TApdModem and TApdSModem
components.
8
9
10
11
12
13
14
15
16
17
Chapter 1: Introduction 3
1
1
Files Supplied
README.HLP
4
A help file that describes changes to the manual and new features added after the manual
was printed. Please read this file before using the product.
APRO.XXX
A text file that summarizes changes between successive versions of Async Professional.
XXX is replaced with the version number. For example, APRO.4.01summarizes changes
between versions 4.00 and 4.01 of Async Professional.
APRO.HLP or APROBCB.HLP
A Windows help file containing information about Async Professional. The help system is
generated from this manual and contains the complete text of the reference sections along
with abbreviated versions of each component introduction.
Units supplied
10
11
12
13
14
15
16
The Async Professional components depend on several low-level units that are not
documented in this manual and should never need to be used directly by your program.
These include AdFaxCtl, AdMeter, AdPackEd, AdPropEd, AdRasUtl, AdSelCom, AdTSel,
AdTUtil, and AdWUtil.
The AdXDial, AdXDown, AdXPort, AdXProt, and AdXUp bonus units provide example
dialogs for dialing, downloading, selecting port options, selecting protocol options, and
uploading, respectively. Although these units are not documented in this manual, you can
easily use the forms in your program or modify them for your needs. Units that will be used
in your applications to access the Async Professional VCL components are shown in Table
1.1.
Table 1.1: Async Professional units
Unit
Description
AdAbout
AdExcept
17
4 Chapter 1: Introduction
1
1
AdFax
AdFaxCvt
AdFaxPrn
AdFaxSrv
AdFPStat
2
3
4
AdFStat
AdFtp
AdFView
AdLibMdm
AdModem
AdPacket
6
7
AdPager
AdPort
AdProtcl
AdPStat
AdRas
AdRStat
AdSapiEn
AdScript
AdSocket
AdState
12
AdStatLt
13
AdTapi
AdTrmBuf
AdTrmEmu
AdTrmMap
AdTrmPsr
8
9
10
11
14
15
16
17
Files Supplied 5
1
1
1
2
3
4
5
6
7
8
9
AdVoIP
AdWnPort
AproReg is the unit used to register all of the Async Professional components and to add
them to the component palette. Refer to the installation section of the Developers Guide for
more information.
10
Name
Description
TermDemo
11
12
SendFax
RcvFax
Cvt2Fax
13
14
ViewFax
FaxMon
FaxServr
FaxSrvX
15
16
17
6 Chapter 1: Introduction
1
1
VoIPDemo
TTSDemo
SRDemo
StatDemo
ModemCap
InfParsr
RasDemo
A simple RAS dialer program that can dial and manipulate RAS
phonebooks. It is based on the TApdRasDialer component.
FTPDemo
ExPaging
The example programs are discussed fully in the Example section for each of the
components throughout the manual. See EXAMPLES.TXT in the installation directory for a
list of the example programs included in Async Professional. The list provides the name of
the project (DPR) file for each example. The main form/unit file name typically consists of
the project name followed by 0.
3
4
8
9
10
11
12
13
14
15
16
17
Files Supplied 7
1
1
In order to provide the user easy access to a product version number, a Version property is
associated with the Async Professionals non-visual TApdBaseXxx components. The VCL
ancestor is listed in the hierarchy for each TApdBaseXxx component.
Version
4
5
6
7
8
9
10
11
12
13
14
15
16
17
8 Chapter 1: Introduction
1
1
read-only property
TComponent (VCL)
TApdBaseComponent (OOMisc)
TApdCustomComPort (AdPort)
TApdComPort (AdPort)
TApdCustomWinsockPort (AdWnPort)
TApdFtpLog (AdFtp)
TApdDataPacket (AdPacket)
TApdSocket (AdSocket)
Scripting component
9
10
11
12
13
TComponent (VCL)
14
TApdBaseComponent (OOMisc)
TApdCustomScript (AdScript)
15
TApdScript (AdScript)
This diagram shows the hierarchy of the TApdScript component which contains properties
and methods for automating basic communications sessions.
16
17
1
1
RAS dialing
TComponent (VCL)
2
3
4
TApdBaseComponent (OOMisc)
TApdCustomRasDialer (AdRas)
TApdRasDialer (AdRas)
TApdCustomRasStatus (AdRas)
TApdRasStatus (AdRStat)
5
6
7
8
9
This diagram shows the components used to establish and monitor a connection to another
computer via Dialup Networking. TApdRasDialer provides an easy to use interface to the
Microsoft Remote Access Services API and a set of standard functions for manipulating
phonebook entries and displaying dial status information. The TApdRasStatus component
provides a standard RAS dialing status dialog for use on machines whose RAS DLL does not
provide a status display.
10
11
12
TApdCustomTapiDevice (AdTapi)
TApdTapiDevice (AdTapi)
TApdAbstractTapiStatus (AdTapi)
TApdTapi Status (AdTapi)
TApdTapiLog (AdTapi)
13
14
15
16
This diagram shows the family of components used for Telephony Application
Programming Interface (TAPI) modem management. TApdTapiDevice provides modem
dialing, answering, and configuration services using Windows TAPI support. The
TApdTapiDevice also provides support for advanced voice modem features like WAV file
playing and recording, and DTMF tone detection and generation. TApdAbstractTapiStatus
is an abstract class that can be attached to a TApdTapiDevice object to display the TAPI
status. TApdTapiStatus is an implementation of this abstract class that displays status in a
particular format. TApdTapiLog is a small component that can be attached to a
TApdTapiDevice object to keep a log file of TAPI actions.
17
10 Chapter 1: Introduction
1
1
Modem operations
TComponent (VCL)
TApdBaseComponent (OOMisc)
TApdCustomSModem (AdSModem)
TApdSModem (AdSModem)
This diagram shows the ancestry of the TApdSModem (simple modem) component. It
provides a simple interface for accessing the most commonly used modem operations. It
integrates the selection of the modem from the modem database and the dialog to show the
current status of the modem.
Terminal
TObject (VCL)
TAdTerminalBuffer (ADTrmBuf)
TAdKeyboardMapping (ADTrmMap)
TAdCharSetMapping (ADTrmMap)
TAdTerminalParser (ADTrmPsr)
TAdVT100Parser (ADTrmPsr)
10
TComponent (VCL)
11
TApdBaseComponent (OOMisc)
TAdTerminalEmulator (ADTrmEmu)
12
TAdTTYEmulator (ADTrmEmu)
13
TAdVT100Emulator (ADTrmEmu)
TWinControl (VCL)
14
TApdBaseWinControl (OOMisc)
TAdTerminal (ADTrmEmu)
15
16
17
The Component Hierarchy 11
1
1
1
2
3
4
5
6
7
8
9
This diagram shows the family of components and classes used for terminals and emulators.
The TAdTerminalBuffer class defines a data structure for maintaining the data required for a
communications terminal display. The TAdTerminalParser class is the ancestor class that
defines the functionality of a terminal parser. The TAdVT100Parser class defines a parser
that understands VT100 terminal data streams.
The TAdKeyboardMapping class provides a simple, convenient method to specify the PC
keystrokes that map onto the emulated terminal keystrokes, and also what control sequence
those terminal keystrokes are going to send to the host computer. The TAdCharSetMapping
class provides a method to emulate the different character sets used by terminals by using
glyphs from different fonts.
The TAdTerminalEmulator class is the base class for all terminal emulators. The
TAdTTYEmulator class emulates a teletype terminal. The TAdVT100Emulator class
emulates a Digital Equipment Corporation (DEC) VT100 terminal and supports some
common extensions to the normal VT100 escape sequence set.
The TAdTerminal component represents the visual part of a terminal. It is the only visual
component in the Async Professional suite of terminal classes. It is responsible for
maintaining the window handle and for performing the low-level processing to get all the
possible keystrokes available on a PC keyboard.
10
11
12
TApdBaseComponent (OOMisc)
TApdCustomSLController (AdStatLt)
TApdSLController (AdStatLt)
TControl (VCL)
TGraphicControl (VCL)
13
TApdCustomStatusLight (AdStatLt)
TApdStatusLight (AdStatLt)
14
15
16
This diagram shows the family of components used for modem status lights.
TApdStatusLight is a graphical component used to display the light in a lit or unlit state.
TApdSLController manages a group of TApdStatusLight components and lights them based
on events it receives from an associated comport component.
17
12 Chapter 1: Introduction
1
1
Paging
TComponent (VCL)
TApdBaseComponent (OOMisc)
TApdAbstractPager (AdPager)
TApdCustomModemPager (AdPager)
TApdTAPPager (AdPager)
TApdCustomINetPager (AdPager)
TApdSNPPPager (AdPager)
This diagram shows the family of components used for sending alphanumeric pages.
TApdAbstractPager provides properties and methods that are common to paging regardless
of the transmission medium. TApdTAPPager sends alphanumeric pages to paging services
that support Telelocator Alphanumeric Protocol and the Motorola Personal Entry Terminal
Protocol. TApdSNPPPager implements Internet based paging using the Simple Network
Paging Protocol.
6
7
8
9
10
11
12
13
14
15
16
17
1
1
2
3
4
!TApdBaseComponent (OOMisc)
!TApdCustomFaxConverter (AdFaxCvt)
!TApdFaxConverter (AdFaxCvt)
!TApdCustomFaxUnpacker (AdFaxCvt)
!TApdFaxUnpacker (AdFaxCvt)
5
6
!TApdCustomFaxPrinter (AdFaxPrn)
!TApdFaxPrinter (AdFaxPrn)
!TApdAbstractFaxPrinterStatus (AdFaxPrn)
7
8
9
!TApdFaxPrinterStatus (AdFaxPrn)
!TApdCustomFaxPrinterLog (AdFaxPrn)
!TApdFaxPrinterLog (AdFaxPrn)
!TControl (VCL)
!TWinControl (VCL)
10
!TApdCustomFaxViewer (AdView)
!TApdFaxViewer (AdView)
11
12
13
14
15
This diagram shows the family of components used for fax conversion, unpacking, viewing,
and printing. TApdFaxConverter converts ASCII text, BMP, PCX, DCX, and TIFF files to
Async Professional Fax (APF) format. TApdFaxUnpacker unpacks fax files to memory
bitmaps or image files. TApdFaxViewer allows viewing of faxes with scaling, rotation, and
white space compression. TApdFaxPrinter prints faxes with scaling and headers and footers.
TApdAbstractFaxPrinterStatus is an abstract class that can be attached to a TApdFaxPrinter
object to display print status. TApdFaxPrinterStatus is an implementation of this abstract
class that displays status in a particular format. TApdFaxPrinterLog is a small component
that can be attached to a TApdPrinter object to keep a log file of printer actions.
16
17
14 Chapter 1: Introduction
1
1
TComponent (VCL)
!TApdBaseComponent (OOMisc)
!TApdCustomAbstractFax (AdFax)
!TApdAbstractFax (AdFax)
!TApdCustomSendFax (AdFax)
!TApdSendFax (AdFax)
!TApdCustomReceiveFax (AdFax)
!TApdReceiveFax (AdFax)
!TApdCustomFaxServer
!TApdFaxServer
!TApdFaxJobHandler
!TApdFaxServerManager
!TApdFaxClient
!TApdAbstractFaxStatus (AdFax)
10
!TApdFaxStatus (AdFax)
!TApdFaxLog (AdFax)
11
!TApdFaxDriverInterface (AdFaxCtl)
This diagram shows the family of components used for fax sending and receiving.
TApdAbstractFax provides the set of properties, methods, and events that are common to
both sending and receiving. The send and receive components are derived from
TApdAbstractFax. TApdSendFax sends single or multiple faxes with optional cover pages.
TApdReceiveFax receives faxes. TApdFaxServer is the faxing engine for the Fax Server
Components. It handles the physical communication with the fax modem to send and
receive faxes. Since this component can both transmit and receive faxes, it shares many
properties with TApdSendFax and TApdReceiveFax.
TApdFaxJobHandler provides methods to manipulate the Async Professional Job file
format. TApdFaxServerManager component provides fax scheduling and queuing
capability. TApdFaxClient provides the ability to create APJ fax job files with a design-time
interface.
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
16 Chapter 1: Introduction
1
1
Overview
6
7
8
Hierarchy
Shows the ancestors of the class being described, generally stopping at a VCL class. The
hierarchy also lists the unit in which each class is declared and the number of the first page of
the documentation of each ancestor. Some classes in the hierarchy are identified with a
number in a bullet: !. This indicates that some of the properties, methods, or events listed
for the class being described are inherited from this ancestor and documented in the
ancestor class.
10
11
12
13
The properties, methods, and events for the class or component are listed. Some of these
may be identified with a number in a bullet: !. In these cases, they are documented in the
ancestor class from which they are inherited.
14
15
16
17
1
1
1
2
Reference section
Details the properties, methods, and events of the class or component. These descriptions
are in alphabetical order. They have the following format:
Description of the property, method, or event. Parameters are also described here.
The See also section lists other properties, methods, or events that are pertinent to
7
8
9
10
Throughout the manual, the "symbol is used to mark a warning or caution. Please pay
special attention to these items.
Naming conventions
To avoid class name conflicts with components and classes included with the compiler or
from other third party suppliers, all Abbrevia class names begin with TAb. The Ab
stands for Abbrevia.
12
Custom in a component name means that the component is a basis for descendant
components. Components with Custom as part of the class name do not publish any
properties. Instead, descendants publish the properties that are applicable to the derived
component. If you create descendant components, use these custom classes instead of
descending from the component class itself.
13
On-line help
11
14
15
Although this manual provides a complete discussion of Abbrevia, keep in mind that there is
an alternative source of information available. Once properly installed, help is available from
within the IDE. Pressing <F1> with the caret or focus on an Abbrevia property, routine or
component displays the help for that item.
16
17
18 Chapter 1: Introduction
1
1
Technical Support
The best way to get an answer to your technical support questions is to post it in the Async
Professional newsgroup on our news server (news.turbopower.com). Many of our customers
find the newsgroups a valuable resource where they can learn from others experiences and
share ideas in addition to getting answers to questions
To get the most from the newsgroups, we recommend that you use dedicated newsreader
software. Youll find a link to download a free newsreader program on our web site at
www.turbopower.com/tpslive.
Newsgroups are public, so please do NOT post your product serial number, 16-character
product unlocking code or any other private numbers (such as credit card numbers) in
your messages.
The TurboPower KnowledgeBase is another excellent support option. It has hundreds of
articles about TurboPower products accessible through an easy to use search engine
(www.turbopower.com/search). The KnowledgeBase is open 24 hours a day, 7 days a week. So
you will have another way to find answers to your questions even when were not available.
Other support options are described in the product support brochure included with Async
Professional. You can also read about support options at www.turbopower.com/support.
3
4
6
7
8
9
10
11
12
13
14
15
16
17
Technical Support 19
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
20 Chapter 1: Introduction
1
1
1
2
The Async Professional port component builds the foundation for all communications
applications. The simplest application might contain a single TApdComPort; a more
complex application might contain one or more port components and many other
components that rely on the services of a TApdComPort (terminal windows, modems, and
so on).
3
4
This chapter describes the TApdComPort component, which contains properties and
methods for the following:
Configuring the serial port hardware and Windows communications driver (buffer
sizes, line parameters, flow control).
Providing information about the state of the serial port (modem signals, line errors).
Transmitting and receiving data.
Interfacing with the TApdDataPacket component (see page 132) to identify and
Assigning VCL events to handle received data, matched strings, status changes, and
timers.
In addition to its support for standard serial ports, the TApdComPort includes specialized
support for the RS-485 communication standard (see page 31).
10
If you need to support network or Internet communications using Winsock, you should
consider using the TApdWinsockPort (see page 106) instead of the TApdComPort. Since the
TApdWinsockPort is a descendant of the TApdComPort, it retains all capabilities of the
TApdComPort, and adds support for Winsock.
11
12
13
14
15
16
17
21
1
1
TApdComPort Component
An application uses the TApdComPort component to control serial port hardware. All serial
port I/O is performed by calling methods of TApdComPort and by writing event handlers
that respond to serial events. Higher level communications actions such as dialing a modem
or transferring a file use a TApdComPort to interact with the hardware.
3
4
5
6
7
8
9
10
11
12
13
Sending and receiving data through the serial port is obviously part of the process, but most
communications applications also need to identify and handle data according to a specific
need. Async Professional provides many high level components that simplify common tasks
such as displaying the data (see Chapter 11: Status Light Components on page 373) and
transferring data using an error-correcting protocol (see Chapter 12: File Transfer
Protocols on page 383).
In addition to such common and well-defined tasks, a flexible component is provided that
allows you to define the type of data you are looking for, automatically collect the data for
you, and notify you when the data has arrived (see Chapter 3: Data Packet Component on
page 105). Be sure to investigate whether or not these high level components could meet
your needs before venturing too far into the low level facilities of the TApdComport
discussed in the following sectionyou could save yourself a lot of time and effort.
14
Note: In 32-bit applications, TApdComPort events are synchronized to the thread that sets
Open to True (in other words, the thread that instantiates the dispatcher). In most cases, this
will end up being the main VCL thread.
15
16
17
22 Chapter 2: Port Component
1
1
This code adds a timer trigger and stores the trigger handle in TrigHandle. The timer is
activated and set to expire in 36 ticks (about 2 seconds). When the timer expires, an
OnTriggerTimer event will be generated. An event handler must be assigned to the
OnTriggerTimer property to gain control when the timer expires.
procedure Form1.TriggerTimer(CP : TObject; TriggerHandle : Word);
begin
...
end;
...
ApdComPort.OnTriggerTimer := TriggerTimer;
Here are the TApdComPort event properties and event handler declarations that correspond
to the four Async Professional trigger types, and the data they contain.
1
2
3
4
6
7
8
OnTriggerAvail
procedure(CP : TObject; Count : Word) of object;
Generated when a certain number of bytes of received serial data are available for
processing. Count is the actual number of bytes that have been received at the instant the
trigger is generated.
Its likely that more than one byte of data will be available when the message handler is
called. The amount of data received in a given event depends on several factors, such as the
nature of the data itself (does it get sent one character at a time by the transmitter, or is it
being sent in blocks or streams?), and the hardware/driver supplying the data to Async
Professional (standard Windows communications drivers typically supply data in small
blocks (8 bytes or less), but Winsock can supply data in large blocks (1,000 bytes or more).
" Caution: Be sure to process the exact number of bytes passed in the Count parameter of this
handler. If you process fewer bytes, you risk losing characters to another component
extracting data during the event (such as the terminal). If you process a number of bytes
greater than the value of the Count property, you risk receiving events for overlapping
datawhich may eventually lead to an EBufferIsEmpty exception.
10
11
12
13
14
15
16
17
TApdComPort Component 23
1
1
1
2
3
4
5
6
7
8
9
The OnTriggerAvail and OnTriggerData events are generated from the dispatcher thread,
and synchronized with the appropriate thread through the use of SendMessageTimeout.
The timeout value is 3 seconds. If your OnTriggerAvail or OnTriggerData event handlers
take longer than 3 seconds to execute (starting at the time the SendMessageTimeout method
was called), you run the risk of losing data. If the timeout period expires, the dispatcher will
assume that a deadlock has occurred and will continuing processing the serial port
notification messages. If you need to perform lengthy processing, you should collect the
received data in a buffer, then process the buffer outside the context of the OnTriggerAvail
event handler.
OnTriggerData
procedure(CP : TObject; TriggerHandle : Word) of object;
10
11
12
13
14
15
16
17
Generated when the dispatcher finds a match in the received data for a data string previously
specified using the AddDataTrigger method. TriggerHandle is the trigger handle returned
by AddDataTrigger.
Usually the dispatcher finds the match in the middle of a block of bytes it is examining. In
this case the dispatcher first generates an OnTriggerAvail event for all the data leading up the
matched string, then it generates the OnTriggerData event to advertise the match, and
finally it generates another OnTriggerAvail event for the data associated with the match.
The data trigger does not guarantee that the notification will be exactly synchronized with
the actual occurrence of the data match. In other words, if you set a data trigger for the
string MYDATA, it is not reliable nor was it intended for you to start capturing those
characters in an OnTriggerAvail event immediately following the OnTriggerData event for
that string. Refer to the APROFAQ.HLP file for example code.
" Caution: Be sure to process the exact number of bytes passed in the Count parameter of this
handler. If you process fewer bytes, you risk losing characters to another component
extracting data during the event (such as the terminal).If you process a number of bytes
greater than the value of the Count property, you risk receiving events for overlapping
datawhich may eventually lead to an EBufferIsEmpty exception.
1
1
In most cases, the TApdDataPacket component is the best way to capture a specific string.
See Chapter 3: Data Packet Component on page 105 for more information on how to use
the TApdDataPacket component.
OnTriggerTimer
Generated when the dispatcher determines that a timer has expired. TriggerHandle is the
trigger handle returned when AddTimerTrigger was called.
3
4
OnTriggerStatus
procedure(CP : TObject; TriggerHandle : Word) of object;
Generated when a status change occurs. Status types include: changes in modem signals
(CTS, DSR, RING, and DCD), changes in line status (line break received and data overrun,
parity, and framing errors), output buffer free space reaching a specified level, and output
buffer used space reaching a certain level.
TriggerHandle is the trigger handle returned when AddStatusTrigger was called.
When a status trigger is used to track more than one modem signal, the event handler must
check the appropriate modem status properties to determine exactly which modem signal
generated the trigger. You can avoid these calls by adding a separate trigger for each modem
signal that you need to trap.
Specialized versions of the OnTriggerStatus event are also available through several events
that are generated only when one particular kind of status change occurs. Event handlers for
these events are called after the OnTriggerStatus event handler. It is possible to have an
OnTriggerStatus handler and also one or more specific status event handlers. Here are the
event properties and event handler declarations for these specialized events.
6
7
8
9
10
11
OnTriggerLineError
procedure(
CP : TObject; Error : Word; LineBreak : Boolean) of object;
12
Generated when the dispatcher determines that a line error or break signal occurred while
receiving data. Error contains one of the following values (a subset of all possible values of
the LineError property):
13
leOverrun = 2;
leParity = 3;
leFraming = 4;
14
15
LineBreak is True if a break signal was received. Note that breaks are often accompanied by
framing errors.
16
17
TApdComPort Component 25
1
1
1
2
3
4
OnTriggerModemStatus
procedure(CP : TObject) of object;
Generated when a monitored modem status signal changes. The signals to monitor are
passed in SetStatusTrigger. Note that there is no TriggerHandle parameter to this event
handler. As such, it cannot differentiate among multiple modem status triggers. If you need
to add more than one modem status trigger, use an OnTriggerStatus event handler instead
of this specialized one.
OnTriggerOutbuffFree
procedure(CP : TObject) of object;
Generated when the number of bytes free in APros output buffer is greater than or equal to
the number passed to SetStatusTrigger for this event.
OnTriggerOutbuffUsed
procedure(CP : TObject) of object;
Generated when the number of bytes used in Apros output buffer is less than or equal to the
number passed to SetStatusTrigger for this event.
OnTriggerOutSent
procedure(CP : TObject) of object;
10
The TApdComPort component has one more event type that is a superset of all of those just
described. This event is generated for every trigger reported by the Async Professional
dispatcher to the component.
11
OnTrigger
12
13
14
15
16
procedure(
CP : TObject; Msg, TriggerHandle, Data : Word) of object;
Generated for all trigger events. Msg is the internal message number that corresponds to the
event. For example, the message APW_TRIGGERAVAIL corresponds to the OnTriggerAvail
event (the other message names are documented in the reference section for the OnTrigger
event on page 69). TriggerHandle is the trigger handle returned when the trigger was added.
Data is the data associated with this trigger.
This event is generated prior to the associated specific event type. For example, when a
modem status signal generates a trigger, the OnTrigger event is generated with Msg set to
APW_TRIGGERSTATUS, then the OnTriggerStatus event is generated with TriggerHandle
set to the status trigger handle, then the OnTriggerModemStatus event is generated.
17
26 Chapter 2: Port Component
1
1
In most cases you would not want to use an OnTrigger event handler, but instead provide
individual event handlers. OnTrigger is provided primarily for script or protocol-oriented
processes where it is more efficient to manage all tasks from one central routine.
With the exceptions of OnTriggerAvail, OnTriggerData, and OnTriggerOutSent, all triggers
must be reactivated within the event handler. That is, the triggers generate a single message
and do not restart themselves automatically. The following example uses triggers:
{$IFDEF Win32}
{$APPTYPE CONSOLE}
{$ENDIF}
unit Extrig0;
1
2
3
4
interface
uses
{$IFNDEF Win32}
WinCrt,
{$ENDIF}
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, AdPort, AdTerm;
type
TExTrigTest = class(TForm)
ApdComPort1: TApdComPort;
StartTest: TButton;
Label1: TLabel;
procedure ApdComPort1TriggerAvail(
CP : TObject; Count : Word);
procedure ApdComPort1TriggerData(
CP : TObject; TriggerHandle : Word);
procedure ApdComPort1TriggerTimer(
CP : TObject; TriggerHandle : Word);
procedure StartTestClick(Sender : TObject);
private
TimerHandle : Word;
DataHandle : Word;
end;
var
ExTrigTest: TExTrigTest;
implementation
{$R *.DFM}
6
7
8
9
10
11
12
13
14
15
16
17
TApdComPort Component 27
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
end.
1
1
This is the unit containing the form for the example project EXTRIG. It contains two
components: StartTest (a TButton) and ApdComPort1 (a TApdComPort). StartButton
implements a Click event handler named StartButtonClick that starts the trigger
demonstration. StartButtonClick adds and sets a timer for 91 ticks (5 seconds) and adds a
data trigger for the string OK. Finally, it transmits the string ATI^M. If a modem is
attached to the serial port, this tells the modem to return its version information, followed
by the response OK.
The form implements three event handlers:
1
2
3
4
6
7
8
9
Integrated Service Digital Network (ISDN) connections are becoming more commonplace
in todays communications applications as the associated costs steadily decline.
ISDN introduces a number of features to the world of PC communications. ISDN lines
have digital channels as opposed to the analog lines (also called POTS for Plain Old
Telephone Service) that standard AT-compatible modems use. Digital channels provide
much higher bandwidths that allow faster communication speeds and higher data
throughput. ISDN lines consist of multiple channels, whereas POTS consists of a single line.
With multiple channels, various types of information (e.g., data, voice, and video) can be
transmitted simultaneously.
ISDN is available in a number of configurations. Basic Rate Interface ISDN (BRI-ISDN)
comes with two B-channels and a D-channel. B-channels allow for 64 Kbps or 56 Kbps
throughput depending on what your local carrier provides. In some configurations, these
channels can be utilized as a single 128 Kbps or 112 Kbps line. The D-channel provides a 16
Kbps channel that is normally used to send signaling information and additional control
data (e.g., the calling partys name, location, and configuration). Primary Rate Interface
ISDN (PRI-ISDN) is much more expensive and provides up to 23 B-channels and one Dchannel in the U.S., Canada, and Japan. It provides up to 30 B-channels and two D-channels
in Europe.
10
11
12
13
14
15
16
17
TApdComPort Component 29
1
1
Async Professional supports basic ISDN services with many AT-compatible adapters
through the TApdTapiDevice component. In general, non-TAPI and non-AT-compatible
ISDN adapters (e.g., those used strictly for PPP or dial-up connections) are not supported
by Async Professional for serial communications. The TApdTapiDevice treats ISDN
adapters as standard AT-compatible modems that control a single channel. A
TApdTapiDevice cannot control multiple channels. You can use the other channels in your
ISDN connection by creating a TApdTapiDevice for each one.
Note that Async Professional support ISDN devices through the TApdTapiDevice interface.
Async Professional does not support the CAPI interface to ISDN devices.
1
2
5
6
7
8
9
10
11
12
13
14
15
16
Analog modem (TAPI) driver support (used when connecting to standard modems
on POTS lines).
17
30 Chapter 2: Port Component
1
1
RS-485 serial networks usually consist of two or more serial devices all connected to the
same 2-wire serial cable. The transmitted data is represented by voltage differences between
the two lines instead of a voltage difference between a single line and a common ground as
in RS-232. This difference allows RS-485 networks to operate over much greater distances
than RS-232.
RS-485 requires specific serial port hardware that supports RS-485 voltages and
conventions. Most standard serial ports provided on a motherboard and even most add-in
serial ports do not support RS-485 mode.
Since both RS-485 wires are required to transmit data, an RS-485 device can either receive
data or transmit data (but not both) at any given moment. RS-485 devices usually spend
most of their time in receive mode, monitoring the line for incoming data. When one device
starts transmitting all other devices in the network receive that data, so messages usually
include an address byte to allow devices to ignore messages not addressed to them.
With such a network, the PC normally acts as a masteraddressing and sending data to
each remote slave device and processing its response before moving on to the next device.
Before the PC can transmit, it must take control of the data line. While transmitting, it
cannot receive any data so it must release control of the line after transmitting so it can
receive the response. This switch from transmit to receive mode can be either automatic
(controlled by the RS-485 board or converter), or it can be manual (controlled by the PC
software or driver).
The mechanism provided by RS-485 boards for switching the data line from receive to
transmit mode falls into three categories:
RTS Control
2
3
4
6
7
8
9
10
11
Automatic
12
Other
Most currently available RS-485 boards use the RTS line to control the state of the data line.
Before transmitting data, the application raises the RTS line of the port, which tells the
RS-485 board to switch to transmit mode. After transmitting the data the application lowers
RTS to switch the line back to receive mode. These boards are supported by the
TApdComport by using the RS485Mode property (with some exceptions noted below).
Some boards and converters handle the RS-485 data line switch automatically, with no
assistance from the software. These boards are supported by Async Professional but do not
require use of the RS485Mode property.
13
14
15
16
17
TApdComPort Component 31
1
1
1
2
The few remaining boards use proprietary techniques for providing RS-485 support instead
of the RTS or automatic switching described above. These boards are not specifically
supported by Async Professional, but can probably be used anyway if your code performs
the actions required by the boards documentation.
RTS control
3
4
5
6
7
8
9
10
Since the TApdComPort provides an RTS property your application could manually raise
RTS before transmitting data and lower RTS after transmitting. This would work in theory,
but is somewhat problematic in that when a PutXxx method has returned, the data may not
have been completely transmitted and lowering RTS at that time would result in some data
being truncated. Even lowering RTS after a calculated delay would be error prone since the
calculation would have to account for delays in UART (the serial port chip) buffering and
would be susceptible to unpredictable delays due to multitasking.
A better approach is to use Async Professionals built-in RTS line control, which is available
through the RS485Mode property. When RS485Mode is set to True all PutXxx methods
raise RTS before transmitting the first byte, wait for the data to be completely transmitted,
then lower RTS. The wait accurately accounts for data in the UART, assuring that RTS is
lowered at the proper time.
" Caution: The RTS line control follows the output buffer. If the output buffer empties while
your code is formatting and transmitting a command, the RTS line could be lowered and
re-raisedwhich might cause some RS-485 devices to misinterpret the message.
It is better to pre-format a command in a buffer and use a single PutBlock call to transmit it
than to format and transmit at the same time using multiple PutXxx commands.
For example, use the first code example rather than the second:
11
12
PutChar('!');
PutChar(Address);
PutChar(MsgLength)
PutString(Message, MsgLength);
PutChar('$');
13
14
15
Under Windows 95/98/ME, the waiting is handled within Async Professional since the
communications API doesnt provide the necessary accuracy. Under Windows NT, the
waiting is handled by the serial port driver, since it does provide the necessary accuracy.
16
17
32 Chapter 2: Port Component
1
1
The automatic handling of the RTS line is possible for standard ports in all environments
and for all non-standard serial ports that provide the necessary driver support. Part of this
support (in Windows 95/98/ME) includes the detection of the serial port hardwares base
address. If this address cannot be detected, attempts to transmit in RS-485 mode will raise
the EBaseAddressNotSet exception. If you know the base address of the port, you can set it
manually using the BaseAddress run-time property.
If the serial port doesnt use standard serial port hardware, then RS485Mode cannot provide
automatic RTS line control for that port. In such cases, however, the board likely provides
some other mechanism for handling RS-485 support (assuming its RS-485 capable) and
you will need to consult the boards documentation for details.
Under Windows NT, the waiting is handled within the serial port driver and replacement
drivers must also provide this support in order for Async Professionals RS485Mode
property to work. If they do not, it is again likely that the board provides some other
mechanism for supporting RS-485.
Debugging facilities
1
2
3
4
6
7
In a perfect world all programs would work flawlessly as they were typed in. Since things
rarely work out this nicely, it is often necessary to break out the debugging tools and apply
some hard-won debugging knowledge to get programs to behave themselves.
Communications programs introduce some new debugging issues, and your existing tools
and knowledge may no longer be adequate.
8
9
For example, suppose youre writing a data collection program that regularly receives data
from an instrument and writes the data to a database. While testing, you notice that a small
percentage of the data in the database is wrong. Broadly speaking, there are two
explanations for such a problem: 1) the instrument sent bad data; or 2) your program
somehow corrupted the good data before writing it to disk. Given that the errors occur
infrequently, youd probably have to add specific debugging code to your program to create
an audit report of all received data. Later youd compare this audit report to the data in the
database. If the data matched, you would know that the instrument sent bad data; otherwise
you could conclude that your program corrupted the data. Either way, you would know what
debugging steps to take next.
10
Tracing
14
Variations of this need for an audit trail can occur in almost any communications program.
Rather than force you to add such debugging code to your applications, Async Professional
provides a general auditing facility called tracing.
15
Simply put, tracing gives you the ability to keep track of all characters transmitted and
received by a program, in the form of a text file that your program creates on request.
11
12
13
16
17
TApdComPort Component 33
1
1
1
2
3
4
5
6
Every time an application successfully retrieves a received character (i.e., GetChar returns a
character) a trace entry is created. Every time an application successfully sends a character
to the Windows communications driver (i.e., PutChar is called successfully) another trace
entry is created.
These entries are stored in a circular queue of a specified size. Since the queue is circular, it
always contains information about the most recent transmitted or received characters. In
Delphi 1, the queue can hold at most 32760 entries. In 32-bit compilers, the queue can hold
up to 4 million entries.
The queue can be dumped to a text file at any time. This text file is a report of all data
transmitted and received by the application in the following format:
Transmit:
**[24]B0100000027fed4[13][138][17]
Receive:
rz[13]**[24]B00800000000dd38[13][138][17]
Transmit:
**[24]B0100000027fed4[13][138][17]
Receive:
[17]*[24]C[4][1][0][0][0][184]6[30][139]a.txt[0]6048
4734111064 0 0 3 18144[0][24]kP[251]B6
9
10
11
12
13
14
15
This report happens to be the first few exchanges of a Zmodem protocol transfer. Printable
characters are displayed as ASCII strings; non-printable characters are displayed as decimal
values in square brackets (e.g., [13] is a carriage return) or optionally as hex values.
Notice that the data is grouped in blocks of received and transmitted characters
representing the sequence in which the program made calls to GetChar and PutChar. A
new block is created whenever the program switches from transmitting to receiving or vice
versa. For example, if a program transmitted a continuous stream of data without ever
stopping to receive data, the report would consist of a single transmit block. Conversely, if
a program contained a character-by-character terminal loop, each block might consist of
only one character because the program constantly switched between sending and receiving
single characters.
The sequence in a trace report is not necessarily the same as the sequence in which data
arrived or departed from the serial port. Suppose that a program transmits the string
ABCD to a remote device that echoes the characters it receives. In a chronological report,
the echo characters received by the transmitter would be intermingled with, but slightly
behind, the transmitted characters.
16
17
34 Chapter 2: Port Component
1
1
Thats not what tracing was designed to do. It was designed to show the data in the order it
was processed by an application. The major benefit to such ordering is that it permits
checking program logic against the data the program is actually processing. For example,
tracing was extremely valuable during the development of the modem and file transfer
protocol portions of Async Professional. If a particular test went awry, it was a simple matter
to review the trace and find out what went wrong (of course, finding out why it went wrong
was another matter).
The mechanics of using tracing are quite simple. A typical use would look something like
the following:
...create comport component
ApdComPort.TraceSize := 1000;
ApdComPort.Tracing := tlOn;
...use comport component
ApdComPort.TraceName := 'TEST.TRC';
ApdComPort.Tracing := tlDump;
...destroy comport component
1
2
3
4
The state of the tracing facility is controlled by setting the Tracing property to one of the
following values shown in Table 2.1.
7
8
Value
Effect
tlOff
tlOn
tlDump
tlAppend
tlClear
tlPause
Pauses tracing.
10
11
12
When inspected, either at run time or design time, Tracing will always be one of tlOff, tlOn,
or tlPause. Setting Tracing to any other value causes an action (such as writing the trace file)
then sets Tracing to either tlOff or tlOn. For example, setting Tracing to tlDump writes the
trace data to a new file, then turns Tracing off, so inspecting Tracing immediately after
setting it to tlDump would return tlOff.
13
14
15
16
17
TApdComPort Component 35
1
1
1
2
3
4
5
6
7
8
9
10
After you create a comport component, set the TraceSize property to specify the trace buffer
size, then set the Tracing property to tlOn to begin tracing. From then on, every successful
call to PutXxx and GetXxx is automatically recorded. If more than the specified number of
trace entries is generated, the queue always contains the most recent. Set the TraceName
property to the name of the file where the trace file should be stored. Optionally, you can set
the TraceHex property to True to enable writing of non-printable characters to the trace file
in hexadecimal format. When Tracing is set to tlDump, the current contents of the trace
buffer are written to disk.
Dispatch logging
Tracing is a great tool for examining the incoming and outgoing data processed by your
program. One of tracings major strengths is that it shows only the data processed when your
program calls the GetXxx and PutXxx routines. Comparing the resulting trace file to your
program logic can often point out logic errors.
In some situations, however, a more appropriate debugging tool is one that shows the true
chronology of incoming and outgoing data. It may be more important to see exactly when
data arrived at the port rather than seeing how your program processed that data.
The standard Windows communications driver doesnt provide enough information to
determine exactly when data arrived. The next best thing is knowing when the Async
Professional internal dispatcher got the data, and thats how dispatch logging works.
Dispatch logging creates an audit trail of each action taken by Async Professional
components. These entries are stored in a circular queue of a specified size. Since the queue
is circular, it contains information about the most recent transmitted or received characters.
Entries in this queue are of variable length, and the queue can be as large as 16 million bytes.
11
12
13
14
15
16
17
36 Chapter 2: Port Component
1
1
The queue can be dumped to a text file at any time. This text file is a report of all dispatcher
events in the following format:
APRO v4.00
Compiler : Delphi 6
Operating System : Windows NT 4.0
Time
Type
SubType
-------- -------- -----------00000010 TrDatChg Avail
00000010 TrgHdAlc Window
00000010 TrgHdAlc Window
00000010 TrDatChg Avail
00000010 TrgHdAlc Procedure
00000010 TrDatChg Avail
00000010 TrigAllc Data
00000010 TrigAllc Data
00000010 TrigAllc Data
00000010 TrigAllc Data
00000010 TrigAllc Status
1
2
Service Pack 4
Data
OtherData
-------- --------00000001
7DDE03CE
870302A2
00000001
00000000
00000001
00000008
rz[0D]
00000010
[05]
00000018
[10]
00000020
[1B]I
00000029
(Modem status)
The first three lines are the header of the text file a provide the installed version of Async
Professional, the current compiler, and the current operating system.
The first column of the report is a timestamp. It represents the time elapsed from the time
dispatch logging was turned on to when the entry was made, measured in milliseconds. The
multimedia API TimeGetTime is used to calculate this timestamp, so it should be accurate
to the nearest millisecond.
The second column is the major category of log entry, the third column identifies the log
entry subtype, the forth column provides additional information related to the event (often
a handle or data count), and the remaining column adds any additional information that
could be useful for the event being logged.
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdComPort Component 37
1
1
1
2
3
4
5
6
7
8
9
Data
Other Data
A translation of the
numeric value. (DCTS,
DDSR, TERI, DDCD, CTS,
DSR, RI, DCD.)
10
11
12
13
14
15
16
17
38 Chapter 2: Port Component
1
1
Data
Status - A status
trigger is being
dispatched.
Other Data
2
3
4
Occur only if the DebugThreads define is enabled in AWUSER.PAS. They are designed to
provide detail about the operation of APROs threads.
Subtype - Meaning
Start - One of the three background threads associated with each comport
(dispatcher thread, communications thread, output thread) is starting.
10
11
12
13
14
15
16
17
TApdComPort Component 39
1
1
Subtype - Meaning
Data
Other Data
The handle
of the
trigger.
The handle
of the
trigger.
The handle
of the
trigger.
3
4
5
6
7
8
9
Subtype - Meaning
Data
10
11
12
13
Data
14
15
16
17
40 Chapter 2: Port Component
1
1
Data
2
3
6
Subtype - Meaning
Data
Other Data
The new
length.
The handle
of the
timer
trigger.
The handle
of the
trigger
being
changed.
7
8
9
10
11
12
13
14
15
16
17
TApdComPort Component 41
1
1
Logs the telnet negotiation conversation during a Winsock telnet session. Each SubType
shows the type of negotiation being logged.
2
3
Subtype - Meaning
Data
Other Data
The numeric
value of
the command
being
negotiated.
A translation of the
numeric command.
The numeric
value of
the command
being
negotiated.
A translation of the
numeric command.
The numeric
value of
the command
being
negotiated.
A translation of the
numeric command.
The numeric
value of
the command
being
negotiated.
A translation of the
numeric command.
The numeric
value of
the command
being
negotiated.
A translation of the
numeric command.
The numeric
value of
the command
being
negotiated.
A translation of the
numeric command.
The numeric
value of
the command
being
negotiated.
A translation of the
numeric command.
4
5
6
7
8
9
10
11
12
13
14
15
16
17
42 Chapter 2: Port Component
1
1
Data
Other Data
The numeric
value of
the command
being
negotiated.
A translation of the
numeric command.
The numeric
value of
the command
being
negotiated.
The numeric
value of
the command
being
negotiated.
1
2
3
4
6
7
Subtype - Meaning
Other Data
If the end condition was a string, the next log entry is another
StringPacket event with the value of the end string in the other data
column. If the end condition was a size event, the next log entry is a
SizePacket event.
Disable - The packet is being enabled.
If the end condition was a string, the next log entry is another
StringPacket event with the value of the end string in the other data
column. If the end condition was a size event, the next log entry is a
SizePacket event.
SizePacket - Describes the end value for a
StringPacket.
9
10
11
12
13
14
15
16
17
TApdComPort Component 43
1
1
Other Data
The event is always generated as a part of the enable sequence for the
packet, if it has a start string. See the Enable event above.
5
6
7
8
The event is always generated as a part of the enable sequence for the
packet, if it has an end string. See the Enable event above.
Idle - The packet is not currently
collecting data and is not waiting for a
string.
Waiting - The packet is waiting for its
start string to come in.
Collecting - The packets start condition
has been met and thus the packet currently
has ownership to the incoming data.
9
10
The dispatcher was called recursively. This is an error and can cause events to be missed.
The cause is usually that event handlers take too long to process their data. No SubTypes
exist for this type of entry.
Log entry type: Fax
11
Entries for this Type track APROs progress through the send or receive fax state machine.
The SubType indicates the current state of the state machine.
12
13
14
15
16
Entries for this Type track APROs progress through the send or receive xmodem protocol
state machine. The SubType indicates the current state of the state machine.
Log entry type: YModem
Entries for this Type track APROs progress through the send or receive ymodem protocol
state machine. The SubType indicates the current state of the state machine.
Log entry type: ZModem
Entries for this Type track APROs progress through the send or receive zmodem protocol
state machine. The SubType indicates the current state of the state machine.
17
44 Chapter 2: Port Component
1
1
Entries for this Type track APROs progress through the send or receive kermit protocol
state machine. The SubType indicates the current state of the state machine.
Entries for this Type track APROs progress through the send or receive ASCII protocol state
machine. The SubType indicates the current state of the state machine.
This type is currently not implemented due to an enumeration capacity limitation in the
C++ Builder 3 compiler.
A user defined event type. You can add custom strings to a comports logfile using the
comports AddStringToLog method. These strings have the type User in the log file.
Logging facility
The state of the logging facility is controlled by setting the Logging property to one of the
values shown in Table 2.2.
7
8
Explanation
tlOff
tlOn
tlDump
tlAppend
tlClear
tlPause
Pauses logging.
See Tracing on page 33, for more information and a related example.
9
10
11
12
Example
13
This example shows how to construct and use a comport component. Create a new project,
add the following components, and set the property values as indicated in Table 2.3.
14
15
Component
Property
Value
TApdComPort
ComNumber
TButton
Name
Test
16
17
TApdComPort Component 45
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
Double-click on the Test button and modify the generated method to match this:
procedure TForm1.TestClick(Sender : TObject);
begin
ApdComPort1.Output := 'ATZ'^M;
end;
This method transmits ATZ (the standard modem reset command), followed by a carriage
return, to the serial port opened by TApdComPort. If a modem is attached to the serial port
it should echo the command, then return OK.
Double-click on the TApdComPort OnTriggerAvail event handler in the Object Inspector
and modify the generated method to match this:
procedure TForm1.ApdComPort1TriggerAvail(
CP : TObject; Count : Word);
var
I : Word;
C : Char;
S : string;
begin
S := '';
for I := 1 to Count do begin
C := ApdComPort1.GetChar;
case C of
#0..#31 : {don't display} ;
else S := S + C;
end;
end;
ShowMessage('Got an OnTriggerAvail event for: ' + S);
end;
This method collects all of the received data into the string S, discarding non-printable
characters, then displays S using ShowMessage.
To run this program you need to attach a modem to the serial port, then compile and run
the project. Clicking on the Test button sends ATZ^M to the modem. The modems
responses are shown through one or more message boxes.
14
15
16
17
46 Chapter 2: Port Component
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomComPort (AdPort)
2
3
TApdComPort (AdPort)
Properties
AutoOpen
HWFlowOptions
Parity
BaseAddress
InBuffFree
PromptForPort
Baud
InBuffUsed
RI
BufferFull
InSize
RS485Mode
BufferResume
LineBreak
RTS
ComNumber
LineError
StopBits
CTS
LogAllHex
SWFlowOptions
DataBits
Logging
TapiMode
DCD
LogHex
TraceAllHex
DeltaCTS
LogName
TraceHex
DeltaDCD
LogSize
TraceName
DeltaDSR
ModemStatus
TraceSize
DeltaRI
Open
Tracing
DeviceLayer
OutBuffFree
UseEventWord
DSR
OutBuffUsed
DTR
Output
XOffChar
FlowState
OutSize
XOnChar
! Version
6
7
8
9
10
11
12
13
14
15
16
17
TApdComPort Component 47
1
1
1
2
3
4
5
6
7
Methods
ActivateDeviceLayer
FlushInBuffer
PutString
AddDataTrigger
FlushOutBuffer
RemoveAllTriggers
AddStatusTrigger
GetBlock
RemoveTrigger
AddStringToLog
GetChar
SendBreak
AddTimerTrigger
ProcessCommunications
SetBreak
AddTraceEntry
PutBlock
SetStatusTrigger
CharReady
PutChar
SetTimerTrigger
OnPortClose
OnTriggerData
OnTriggerOutbuffUsed
OnPortOpen
OnTriggerLineError
OnTriggerOutSent
OnTrigger
OnTriggerModemStatus
OnTriggerStatus
OnTriggerAvail
OnTriggerOutbuffFree
OnTriggerTimer
Events
8
9
10
11
12
13
14
15
16
17
48 Chapter 2: Port Component
1
1
Reference Section
ActivateDeviceLayer
1
virtual method
2
function ActivateDeviceLayer : TApdBaseDispatcher; virtual;
TApdBaseDispatcher = class;
! Called when the port is first opened to instantiate a device driver object for the port.
Async Professional includes several device layers. The dlWin32 device layer (the default for
32-bit applications) uses the standard Win32 comms drivers. The dlWin32 device layer have
a descendant device layer that is used if TapiMode is set to tmOn. The TAPI device layers
rely on TAPI to open and close the serial port, but are otherwise identical to their ancestor
device layers. The dlWinsock device layer is available only if you use TApdWinsockPort
component (see page 105).
You can create custom device layers by deriving them from TApdBaseDispatcher and
creating a new port descendant from TApdCustomComport where you override
ActivateDeviceLayer to return the newly defined device layer.
See Device Independence on page 725 for more information on device layers.
method
function AddDataTrigger(
const Data : string; const IgnoreCase : Boolean) : Word;
9
10
11
Data is the string the dispatcher attempts to match in the received data stream. If IgnoreCase
is True, case is not considered when checking for a match.
12
If the trigger is added successfully, the function returns the handle of the trigger. Otherwise,
it generates an exception. No subsequent call is required to activate the trigger.
13
When the internal dispatcher finds incoming data that matches Data it generates an
OnTriggerData event.
14
The following example tells the internal dispatcher to generate an OnTriggerData event
whenever it receives the string UserID:. Because False is passed for IgnoreCase the case of
the strings must match exactly.
ApdComPort.AddDataTrigger('UserID:', False);
15
16
17
TApdComPort Component 49
1
1
AddStatusTrigger
method
3
4
5
6
7
8
9
10
11
12
13
14
Value
Meaning
stModem
stLine
stOutBuffFree
stOutBuffUsed
stOutSent
See the SetStatusTrigger method on page 88 or more information about these status trigger
types.
If the trigger is added successfully, the function returns the handle of the trigger; otherwise
it generates an exception. The trigger is not activated until a subsequent call to
SetStatusTrigger. The data associated with the trigger (such as the buffer free level for a
stOutBuffFree trigger event) is supplied at that time.
The following example adds a status trigger and enables the trigger to generate an
OnTriggerStatus event as soon as at least 100 bytes become free in the output buffer. Later
it deactivates the trigger but does not delete it. Note that status triggers are not selfrestarting; the applications message handler must call SetStatusTrigger again once an event
is generated.
var
StatusHandle : Word;
...
StatusHandle := ApdComPort.AddStatusTrigger(stOutBuffFree);
ApdComPort.SetStatusTrigger(StatusHandle, 100, True);
...
ApdComPort.SetStatusTrigger(StatusHandle, 0, False);
15
16
17
50 Chapter 2: Port Component
1
1
AddStringToLog
method
This procedure can be called to add custom entries to the dispatcher log. These entries will
show up in the dispatcher log as User entries.
AddStringToLog can be very useful when debugging the application. Custom strings can be
added to the log to show when you process events, or start other operations, or just for
general logging purposes.
3
4
method
6
function AddTimerTrigger : Word;
If the trigger is added successfully, the function returns the handle of the trigger; otherwise,
it generates an exception. The timer must be activated subsequently with a call to
SetTimerTrigger.
The following example adds a timer trigger and enables it to expire in 36 ticks (2 seconds),
when it will generate an OnTriggerTimer event. Note that timer triggers are not
self-restarting; the applications event handler must call SetTimerTrigger again once an event
is handled.
var
Timer : Word;
...
Timer := ApdComPort.AddTimerTrigger;
ApdComPort.SetTimerTrigger(Timer, 36, True);
8
9
10
11
12
13
14
15
16
17
TApdComPort Component 51
1
1
AddTraceEntry
method
2
3
4
5
6
7
8
9
10
When AddTraceEntry is mixed in with a normal set of transmit and receive blocks, it looks
something like this:
Transmit:
ATZ[13]
Special-X:
Y
Receive:
ATZ[13][13[10]OK[13][10]
11
In this example the program transmitted ATZ<CR>, called AddTraceEntry(X, Y), then
used one of the GetXxx routines to retrieve the received data.
12
13
14
property
Default: True
If AutoOpen is True and a method or property that requires an open serial port is accessed,
the TApdComPort component automatically opens the port. If AutoOpen is False, the port
must be opened explicitly by setting the Open property to True.
See also: Open
17
52 Chapter 2: Port Component
1
1
BaseAddress
run-time property
Default: 0
property
3
4
6
7
8
9
Default: 19200
10
Generally acceptable values for Baud include 300, 1200, 2400, 4800, 9600, 19200, 38400,
57600, and 115200.
If the port is open when Baud is changed, the line parameters are updated as soon as any
data existing in the output buffer has drained. Baud does not validate the assigned value
before passing it on to the communications driver. The driver may reject the value, leading
to an exception.
You can enter a baud rate using the Object Inspector or invoke the SelectBaudRate property
editor, which provides a drop-down list box of standard baud rates.
See also: ComNumber, DataBits, Parity, StopBits
11
12
13
14
15
16
17
TApdComPort Component 53
1
1
BufferFull
property
Default: 0
! Determines the input buffer level at which receive flow control is imposed.
3
4
5
6
7
8
9
10
11
When hardware flow control is used, BufferFull should typically be set to 90% of the input
buffer size. When software flow control is used, it should typically be set to 75% of the buffer
size, since it may take the remote some time to receive the XOff character and stop sending.
If flow control is enabled and BufferFull has not been set, or has been set to an invalid value,
the level is set to 90% of the input buffer size.
See also: BufferResume, HWFlowOptions, SWFlowOptions
BufferResume
property BufferResume : Word
Default: 0
! Determines the input buffer level at which receive flow control is deactivated.
When hardware flow control is used, BufferResume should typically be set to 10% of the
input buffer size. When software flow control is used, it should typically be set to 25% of the
buffer size, since it may take the remote some time to receive the XOn character and start
sending again. If flow control is enabled and BufferResume has not been set, or has been set
to an invalid value, the level is set to 10% of the input buffer size.
See also: BufferFull, HWFlowOptions, SWFlowOptions
CharReady
12
13
14
15
17
54 Chapter 2: Port Component
method
16
property
ComNumber
property
Default: 0
! Determines the serial port number (Com1, Com2, ...) used by the TApdComPort
component.
ComNumber does not validate the port number. When the port is opened, the Windows
communications driver will determine whether the port number is valid and generate an
error if it is not. To validate the port, use the IsPortAvailable method described on page 896.
If the port is open when ComNumber is changed, the existing port is closed and then
reopened using the new number. Triggers are maintained during this operation.
This property is ignored when the TAPI and Winsock device layers are used.
The following example creates, configures, and opens a comport component at run time:
ApdComPort := TApdComPort.Create(Self);
ApdComPort.ComNumber := 1; {use Com1}
ApdComPort.Baud := 9600;
ApdComPort.Parity := pNone;
ApdComPort.DataBits := 8;
ApdComPort.StopBits := 1;
ApdComPort.Open := True;
CTS
8
9
read-only, run-time property
10
11
12
13
14
15
16
17
TApdComPort Component 55
1
1
DataBits
property
Default: 8
DCD
7
8
9
10
11
12
! Returns True if the ports data carrier detect line (DCD) is set.
DCD is usually set only for serial connections made through a modem. Your modem sets
DCD to indicate that it has a connection with another modem. If either modem hangs up or
the connection is lost for another reason, your modem clears DCD (assuming it is
configured to do so.) Hence, if your application uses a modem connection, you might want
to check DCD periodically to assure that the connection is still valid or, better yet, use a
modem status trigger for the same purpose.
The following example detects carrier loss and handles the error:
if not ApdComPort.DCD then
{handle unexpected disconnect}
13
14
15
! Returns True if the ports delta clear to send bit (DeltaCTS) is set.
DeltaCTS is set only if CTS has changed since the last time the application read the value of
DeltaCTS.
See also: CTS
16
17
56 Chapter 2: Port Component
1
1
DeltaDCD
! Returns True if the ports delta data carrier detect bit (DeltaDCD) is set.
DeltaDCD is set only if DCD has changed since the last time the application read the value
of DeltaDCD.
2
3
! Returns True if the ports delta data set ready bit (DeltaDSR) is set.
DeltaDSR is set only if DSR has changed since the last time the application read the value
of DeltaDSR.
! Returns True if the ports delta ring indicator bit (DeltaRI) is set.
DeltaRI is set only if RI (the ring indicator) has changed since the last time the application
called CheckDeltaRI.
10
The formal name for this bit is trailing edge ring indicator or TERI. DeltaRI is used for
consistency with other Async Professional naming conventions.
11
It is generally better to use DeltaRI to detect incoming calls than to use RI. RI toggles rapidly
as rings are detected, making it easy for your application to miss the brief periods that it
returns True. By contrast, DeltaRI returns True if any ring was detected since the last call to
the routine.
The following example calls the Answer method of TApdModem to connect a modem after
a ring is detected:
if ApdComPort.DeltaRI then
Modem.Answer;
12
13
14
15
See also: RI
16
17
TApdComPort Component 57
1
1
DeviceLayer
property
3
4
5
6
7
8
9
10
11
12
! Returns True if the ports data set ready line (DSR) is set.
DSR is a signal that the remote device sets to indicate that it is attached and active. It may be
a good idea to check this signal before transmitting and periodically thereafter.
See also: DeltaDSR, CTS
13
14
15
16
17
58 Chapter 2: Port Component
1
1
DTR
property
Default: True
! Determines the current state of the data terminal ready signal (DTR).
Some types of remote devices require that this signal be raised before they transmit. For
example, the default configuration of many modems is not to transmit data unless the PC
has raised the DTR signal.
3
4
The following example lowers the DTR signal after opening the port and later raises it again:
ApdComPort := TApdComPort.Create(Self);
ApdComPort.Open := True;
ApdComPort.DTR := False;
...
ApdComPort.DTR := True;
6
7
9
10
fcOff indicates that flow control is not in use. fcOn indicates that flow control is enabled, but
that blocking is not currently imposed in either direction.
fcDsrHold, fcCtsHold and fcDcdHold indicate that the application cannot transmit because
the other side has lowered DSR, CTS, or DCD respectively. Note that Async Professional
doesnt currently provide DCD flow control.
Windows doesnt provide information on the state of receive hardware flow control, so fcOn
is returned even if the local device is blocking received data by using a hardware flow control
line.
fcXOutHold indicates that the application cannot transmit because it has received an XOff
character from the remote. fcXInHold indicates that the application has sent an XOff
character to the remote to prevent it from transmitting data. fcXBothHold indicates that the
application has both sent and received an XOff.
11
12
13
14
15
16
17
TApdComPort Component 59
1
1
1
2
In the rare case where both hardware and software flow control are enabled for a port,
FlowState can return ambiguous results. In particular, if flow is blocked by both hardware
and software flow control, FlowState can return only the fact that one type is causing the
block.
See also: HWFlowOptions, SWFlowOptions
3
4
FlushInBuffer
method
procedure FlushInBuffer;
! Clears the input buffers used by both the Windows device driver and the Async Professional
5
internal dispatcher.
It also resets all data triggers so as to disregard any cleared data.
6
7
8
9
The following example flushes all data currently in the input buffer if a line error is detected.
You probably shouldnt do this routinely after each line error. Logic like this is usually
appropriate only before trying to resynchronize with the transmitter in a file transfer
protocol.
if ApdComPort.LineError <> leNoError then begin
...error handling
ApdComPort.FlushInBuffer;
end;
10
11
12
FlushOutBuffer
method
procedure FlushOutBuffer;
! Clears the output buffers used by both the Windows device driver and the Async
Professional internal dispatcher.
Any data pending in the output buffer is not transmitted.
13
14
15
16
The following example discards any data that hasnt yet been transmitted whenever an
application function named ErrorDetected returns True after a remote device reports an
error:
if ErrorDetected then begin
ApdComPort.FlushOutBuffer;
...resync with remote
end;
17
60 Chapter 2: Port Component
1
1
GetBlock
method
! Returns a block of received characters and removes them from the dispatcher buffer.
This routine makes a request to return the next Len received bytes. The data is moved into
the buffer referenced by Block. If Block is not large enough to hold Len bytes this will result
in a memory overwrite. If fewer than Len bytes are available, none are returned and an
EBufferIsEmpty exception is generated. The returned bytes are removed from the Async
Professional dispatcher buffer.
2
3
4
To determine if line errors occurred while the communications driver was receiving this
data, check the LineError property after calling GetBlock.
The following example calls GetBlock to remove the next 128 bytes from the dispatcher
buffer, and handles the various possible outcomes:
var
Block : array[0..127] of Char;
...
try
ApdComPort.GetBlock(Block, 128);
except
on E : EAPDException do
if E is EBufferIsEmpty then begin
...protocol error, 128 bytes expected
raise;
end;
end;
6
7
8
9
10
11
12
13
14
15
16
17
TApdComPort Component 61
1
1
GetChar
method
If at least one character is available in the dispatcher buffer, GetChar returns the first
available one.
To determine if line errors occurred while the communications driver was receiving this
data, check the LineError property after calling GetChar.
The following example returns the next available character in C:
5
6
var
C : Char;
...
if ApdComPort.CharReady then
C := ApdComPort.GetChar;
HWFlowOptions
property
9
10
11
12
When the options are an empty set, as they are by default, there is no hardware flow control.
The options can be combined to enable hardware flow control.
13
Receive flow control stops a remote device from transmitting while the local input buffer
is too full. Transmit flow control stops the local device from transmitting while the remote
input buffer is too full.
14
15
16
Receive flow control is enabled by including the hwfUseRTS and/or hwfUseDTR elements in
the options set. When enabled, the corresponding modem control signals (RTS and/or
DTR) are lowered when the input buffer reaches the level set by the BufferFull property. The
remote must recognize these signals and stop sending data while they are held low. Because
there is usually little delay before the remote reacts (as there is with software flow control),
BufferFull can be set close to the input buffer size, perhaps at the 90% level.
17
62 Chapter 2: Port Component
1
1
As the application processes received characters, buffer usage eventually drops below the
value set by the BufferResume property. At that point, the corresponding modem control
signals are raised again. The remote must recognize these signals and start sending data
again. Again, because there is usually little delay you can set BufferResume close to zero,
perhaps at 10% of the input buffer size.
Transmit flow control is enabled by including the hwfRequireCTS and/or hwfRequireDSR
elements in the options set. With one or both of these options enabled, the Windows
communications driver doesnt transmit data unless the remote device is providing the
corresponding modem status signal (CTS and/or DSR). The remote must raise and lower
these signals when needed to control the flow of transmitted characters.
1
2
3
4
Note that flow control using RTS and CTS is much more common than flow control using
DTR and DSR.
See Flow Control on page 711 for more information.
The following example enables bi-directional hardware flow control with limits at the 10%
and 90% levels of the buffer. RTS is lowered for receive flow control and CTS is checked for
transmit flow control. Later in the application, hardware flow control is disabled.
8
9
10
11
12
This routine returns the number of bytes of free space in the Async Professional
dispatcher buffer. It does not tell you the free space in the Windows communications
driver input buffer.
13
Because the dispatcher automatically drains the Windows buffer using timer and
notification messages, its status is rarely relevant to the program.
14
The following example checks to see that theres significant free space in the dispatcher
buffer before performing a time-consuming operation that doesnt drain the buffer:
15
16
17
TApdComPort Component 63
1
1
InBuffUsed
2
3
! Returns the number of bytes currently available for reading from the dispatcher buffer.
This routine returns the number of bytes currently loaded in the Async Professional
dispatcher buffer. It does not include bytes in the Windows communications driver input
buffer that havent yet been moved to the dispatcher buffer.
Because the dispatcher automatically drains the Windows buffer using timer and
notification messages, this buffers status is rarely relevant to the program.
The following example checks InBuffUsed to see if received data is available for processing:
7
8
InSize
property
Default: 4096
9
10
11
12
! Determines the size, in bytes, of the Window communications drivers input buffer.
InSize should always be fairly large, perhaps 4096 or 8192. The larger this size, the less likely
the driver loses data if an ill-behaved program takes control of Windows foreground
processing for an extended time.
The Windows communication API does not permit changing the buffer size when a serial
port is open. When InSize is changed for an open port, the port is closed and re-opened
with the new size.
See also: Open, OutSize
13
LineBreak
14
15
! Returns True if a line break signal was received since the last call to LineBreak.
See also: OnTriggerStatus
16
17
64 Chapter 2: Port Component
1
1
LineError
! Returns a non-zero value if line errors have occurred since the last call to LineError.
It returns 0 if no errors were detected or the port is not yet open. Otherwise it returns a
numeric value from the following list that indicates the most severe pending error:
Value
Error Number
Meaning
leBuffer
leOverrun
leParity
leFraming
leCTSTO
leDSRTO
leDCDTO
leTxFull
2
3
4
6
7
8
Line errors can occur during calls to any GetXxx or PutXxx method of the port. If your
application must detect line errors, it should check LineError after each such call or group of
calls, or it should install an OnTriggerLineError event handler.
The following example checks for line errors after receiving data with GetBlock:
9
10
ApdComPort.GetBlock(DataBlock, DataLen);
if ApdComPort.LineError <> 0 then
...error handling
11
property
12
13
Default: False
! Determines whether all characters in the dispatcher log are written as hex or decimal.
This property is useful when you are processing raw data, instead of a mixture of printable
text and raw data.
14
15
16
17
TApdComPort Component 65
1
1
If LogAllHex is False (the default), a received string of 123 will be written to the log as
literal, printable chars:
0000.824
2
3
4
Dispatch
ReadCom
0000000A
123
If LogAllHex is True, the same received string will be written to the log in their hexadecimal
notation:
0000.829
Dispatch
ReadCom
0000000A
[31][32][33]
property
6
7
Default: tlOff
8
9
10
11
12
13
14
15
16
To enable logging, set Logging to tlOn. This allocates an internal buffer of LogSize bytes and
informs the dispatcher to start using this buffer. To disable logging without writing the
contents of the log buffer to a disk file, set Logging to tlOff. This also frees the internal buffer.
To write the contents of the logging buffer to disk, set Logging to tlDump (which overwrites
any existing file named LogName, or creates a new file) or tlAppend (which appends to
an existing file, or creates a new file). After the component writes to the file it sets Logging
to tlOff.
To clear the contents of the logging buffer and continue logging, set Logging to tlClear. After
the component clears the buffer, it sets Logging to tlOn.
To temporarily pause logging, set Logging to tlPause. To resume logging, set Logging
to tlOn.
See Dispatch logging on page 36 for more information.
The following example turns on logging and later dumps the logging buffer to APRO.LOG:
ApdComPort.Logging := tlOn;
...
ApdComPort.LogName := 'APRO.LOG';
ApdComPort.Logging := tlDump;
17
66 Chapter 2: Port Component
1
1
LogHex
property
Default: True
! Determines whether non-printable characters stored in a dispatch logging file are written
3
property
Default: APRO.LOG
7
8
property
9
10
Default: 10000
! Determines the number of bytes allocated for the dispatch logging buffer.
The assigned value limit is 16 million. Each dispatch entry consumes at least 10 bytes. Many
entries use additional buffer space to store a sequence of received or transmitted characters.
This property should normally be set before a logging session begins. If a changed value is
assigned to LogSize while a logging session is active, the current session is aborted (which
clears all information from the logging buffer), the new buffer is allocated, and a new
logging session is started.
11
12
13
14
15
16
17
TApdComPort Component 67
1
1
ModemStatus
2
3
4
5
6
7
8
9
! Returns the modem status byte and clears all delta bits.
The status is returned in the byte format used by the UARTs modem status register. The
returned value can be used with the following bit masks to isolate the desired bits:
Mnemonic
Value
Description
DeltaCTSMask
01h
DeltaDSRMask
02h
DeltaRIMask
04h
DeltaDCDMask
08h
CTSMask
10h
Clear to send.
DSRMask
20h
RIMask
40h
Ring indicator.
DCDMask
80h
Youll probably find it easier to use the CTS, DSR, RI, DCD, and related DeltaXxx properties
instead of ModemStatus, but ModemStatus is more efficient when you need to check several
signals at once.
10
ModemStatus also clears the internal delta bits used to indicate changes in the CTS, DSR, RI,
and DCD signals. This affects the results of subsequent checks of DeltaCTS, etc.
11
The following example uses ModemStatus to check for dropped carrier. It would have been
simpler in this case to check the DCD property directly.
12
13
Status := ApdComPort.ModemStatus;
if Status and DCDMask = 0 then
...port dropped carrier
14
15
16
17
68 Chapter 2: Port Component
1
1
OnPortClose
event
! OnPortClose is generated when the serial port associated with the TApdComPort is
physically closed.
Setting the Open property to False does not close the associated serial port immediately.
Buffers and structures need to be reset, and the physical hardware needs to be closed before
the port can be considered closed. This event is generated when the physical port is actually
closed and available to other processes.
3
4
event
! OnPortOpen is generated when the serial port associated with the TApdComPort is
physically opened.
Setting the Open property to True begins a series of actions, ending with the physical serial
port being opened and ready for use. This includes creating the buffers, data structures and
the three threads required by the component. This process may take a few milliseconds,
depending on the responsiveness of the Windows serial port drivers, unconventional
configurations, etc. This event is generated when the physical serial port is opened and ready
for use.
See also: OnPortClose, Open
OnTrigger
event
! Defines an event handler that is called whenever any serial data trigger occurs.
OnTrigger can be used to handle all kinds of trigger events in one location. Normally it is
easier to use the more specific kinds of serial data triggers. The OnTrigger event handler is
always called first, then the more specific event handlers are also called if they are assigned.
8
9
10
11
12
13
14
15
16
17
TApdComPort Component 69
1
1
1
2
3
4
5
6
7
8
9
10
CP is the TApdComPort component that generated the trigger. Msg is the Windows message
that specifies the kind of trigger:
Trigger
Description
APW_TRIGGERAVAIL
Corresponds to OnTriggerAvail.
APW_TRIGGERDATA
Corresponds to OnTriggerData.
APW_TRIGGERTIMER
Corresponds to OnTriggerTimer.
APW_TRIGGERSTATUS
Corresponds to OnTriggerStatus.
TriggerHandle is the handle number returned when the trigger was added. Data is a
numeric value that is relevant for the APW_TRIGGERAVAIL, APW_TRIGGERDATA, and
APW_TRIGGERSTATUS events. See the corresponding event handlers for more
information.
The following example waits for and responds to a login prompt, processing
APW_TRIGGERDATA, APW_TRIGGERAVAIL, and APW_TRIGGERTIMER messages in
a single routine:
DataTrig := ApdComPort.AddDataTrigger('login:', True);
TimerTrig := ApdComPort.AddTimerTrigger;
ApdComPort.SetTimerTrigger(TimerTrig, 182, True);
...
procedure TMyForm.ApdComPortTrigger(
CP : TObject; Msg, TriggerHandle, Data : Word);
var
I : Word;
C : Char;
11
12
13
14
15
16
17
70 Chapter 2: Port Component
1
1
begin
case Msg of
APW_TRIGGERDATA :
{got 'login', send response}
ApdComPort.PutString('myname');
APW_TRIGGERAVAIL :
{extract and display/process the data}
for I := 1 to Data do begin
C := ApdComPort.GetChar;
...process data
end;
APW_TRIGGERTIMER :
{timed out waiting for login prompt, handle error}
...
end;
end;
1
2
3
4
7
OnTriggerAvail
event
TTriggerAvailEvent = procedure(
CP : TObject; Count : Word) of object;
! Defines an event handler that is called whenever a certain amount of serial input data is
available for processing.
10
This event is generated when data has been transferred into the dispatcher buffer.
CP is the TApdComPort component that generated the trigger. Count is the actual number
of bytes that are available to read at the instant the event is generated. Your event handler
should process exactly the number of bytes of input equal to the value of the Count
parameter (by calling GetChar or GetBlock). It should not use CharReady in a loop to
process all available bytes since additional bytes may have transferred into the buffer while
the event handler is active, and removing those bytes could interfere with the dispatchers
data tracking mechanism.
11
If several parts of the same application are using the same comport component and each
part installs its own OnTriggerAvail handler (as would occur if a terminal window and a file
transfer protocol were both in use), the Async Professional dispatcher takes pains to ensure
that all of them can read the same data. Even if the first handler to get control calls GetChar
to read Count bytes of data, the second and subsequent handlers will also be able to read the
same bytes of data by calling GetChar. After all of the OnTriggerAvail handlers have
returned, the dispatcher determines the largest number of characters read by any of the
handlers and removes those characters from the dispatcher buffer. If any data remains in the
14
12
13
15
16
17
TApdComPort Component 71
1
1
buffer, the dispatcher immediately generates another OnTriggerAvail event. Hence, if one
handler reads fewer characters than the other handlers, it will miss seeing the characters it
did not read on its first opportunity.
" Caution: Be sure to process the exact number of bytes passed in the Count parameter of this
handler. If you process fewer bytes, you risk losing characters to another component
extracting data during the event (such as the terminal). If you process more than Count
bytes, you risk receiving events for overlapping data which may eventually lead to an
EBufferIsEmpty exception.
4
5
6
7
8
9
10
11
12
13
14
15
The following example collects incoming data until it finds a carriage return character
(ASCII 13). If the incoming data stream contained TurboPower Software<CR>,
ApdComPortTriggerAvail would be called one or more times until the entire string except
<CR> was received. ApdComPortTriggerData would then be called and could process the
complete string. ApdComPortTriggerAvail would then be called again with the <CR> and
any other data that followed it. ApdComPortTriggerData would not be called again in this
example, because the handler disables the data trigger.
const
S : string = '';
...
CRTrig := ApdComPort.AddDataTrigger(#13, False);
...
procedure TMyForm.ApdComPortTriggerData(
CP : TObject; TriggerHandle : Word);
begin
if TriggerHandle = CRTrig then begin
...do something with S
ApdComPort.RemoveTrigger(TriggerHandle);
end;
end;
procedure TMyForm.ApdComPortTriggerAvail(
CP : TObject; Count : Word);
var
I : Word;
begin
for I := 1 to Count do
S := S + ApdComPort.GetChar;
end;
16
17
72 Chapter 2: Port Component
1
1
OnTriggerData
event
TTriggerDataEvent = procedure(
CP : TObject; TriggerHandle : Word) of object;
! Defines an event handler that is called whenever a string matching a predefined goal is
CP is the TApdComPort component that generated the trigger. TriggerHandle is the handle
number returned when the trigger was added.
Note that data match triggers remain active until explicitly removed. The event handler can
call RemoveTrigger, passing TriggerHandle as the parameter, to remove the trigger that just
generated the event.
OnTriggerLineError
event
! Defines an event handler that is called whenever the dispatcher detects a line error or line
break in the received data.
This event handler is called in a subset of the cases where the more general OnTriggerStatus
handler is called. OnTriggerStatus is called first when a line error is detected, even if an
OnTriggerLineError handler is installed.
CP is the TApdComPort component that generated the trigger. Error is a numeric code that
indicates the most severe line error detected. See the LineError property for details. The
LineBreak parameter is True if a line break was detected.
Note that status triggers are not self-restarting. The event handler must call SetStatusTrigger
again to reactivate the trigger as needed.
10
11
12
13
14
15
16
17
TApdComPort Component 73
1
1
1
2
3
4
5
6
7
8
9
The following example adds a status trigger for line errors and line breaks. The events are
handled using an OnTriggerLineError event handler.
TrigLE : Word;
...
TrigLE := ApdComPort.AddStatusTrigger(stLine);
ApdComPort.SetStatusTrigger(
TrigLE, lsParity or lsFraming or lsOverrun or lsBreak, True);
...
procedure TMyForm.ApdComPortTriggerLineError(
CP : TObject; Error : Word; LineBreak : Boolean);
begin
if Error <> leNone then
...process line error
if LineBreak then
...process line break
{reactivate trigger}
ApdComPort1.SetStatusTrigger(
TrigLE, lsParity or lsFraming or lsOverrun or lsBreak, True);
end;
event
10
! Defines an event handler that is called whenever the dispatcher detects that modem status
signals have changed.
11
12
This event handler is called in a subset of the cases where the more general OnTriggerStatus
handler is called. OnTriggerStatus is called first when a modem status change is detected,
even if an OnTriggerModemStatus handler is installed.
14
The parameter passed to the TNotifyEvent is the TApdComPort component that generated
the trigger. The TApdComPorts modem status properties can be checked by the event
handler to determine the exact reason for the event. No TriggerHandle is passed to the event
handler, so it is not possible to distinguish between multiple modem status triggers in this
event handler. If you need to do so, use the OnTriggerStatus event instead.
15
Note that status triggers are not self-restarting. The event handler must call SetStatusTrigger
again to reactivate the trigger as needed.
13
16
17
74 Chapter 2: Port Component
1
1
The following example adds and activates a modem status trigger for ring indicators and
changes in DSR. Modem status changes are handled using an OnTriggerModemStatus event
handler.
TrigMS : Word;
...
TrigMS := ApdComPort.AddStatusTrigger(stModem);
ApdComPort.SetStatusTrigger(
TrigMS, msRingDelta or msDSRDelta, True);
...
procedure TMyForm.ApdComPortTriggerModemStatus(CP : TObject);
begin
if ApdComPort.DeltaRI then
...handle ring
if ApdComPort.DeltaDSR then
...handle change in DSR
{reactivate trigger}
ApdComPort.SetStatusTrigger(
TrigMS, msRingDelta or msDSRDelta, True);
end;
See also: CTS, DCD, DeltaCTS, DeltaDCD, DeltaDSR, DeltaRI, DSR, ModemStatus, RI
OnTriggerOutbuffFree
event
1
2
3
4
6
7
8
9
! Defines an event handler that is called whenever the dispatcher detects that free space in its
10
11
12
13
14
15
16
17
TApdComPort Component 75
1
1
1
2
3
4
5
6
The following example adds and activates a status trigger for OnTriggerOutbuffFree events;
when the output buffer free level reaches 255 or greater ApdComPortTriggerOutbuffFree
transmits BigString:
TrigOBF : Word;
...
TrigOBF := ApdComPort.AddStatusTrigger(stOutbuffFree);
ApdComPort.SetStatusTrigger(TrigOBF, 255, True);
...
procedure TMyForm.ApdComPortTriggerOutbuffFree(CP : TObject);
begin
{buffer has at least 255 bytes free, transmit a big string}
ApdComPort.Output := BigString;
end;
7
8
9
10
! Defines an event handler that is called whenever the dispatcher detects that used space in its
output buffer has dropped below a certain level.
This event handler is called in a subset of the cases where the more general OnTriggerStatus
handler is called. OnTriggerStatus is called first when used space drops below a particular
level, even if an OnTriggerOutbuffUsed handler is installed. If the output buffer already
contains fewer bytes than the specified level when the trigger is activated, an
OnTriggerOutbuffUsed event is generated as soon as the internal dispatcher gains control.
11
The parameter passed to the TNotifyEvent is the TApdComPort component that generated
the trigger.
12
Note that status triggers are not self-restarting. The event handler must call SetStatusTrigger
again to reactivate the trigger as needed.
13
The following example adds and activates a status trigger for an OnTriggerOutbuffUsed
event; when the output buffer used level drops below 100 bytes
ApdComPortTriggerOutbuffUsed is called and transmits additional data:
14
15
16
TrigOBU : Word;
...
TrigOBU := ApdComPort.AddStatusTrigger(stOutBuffUsed);
ApdComPort.SetStatusTrigger(TrigOBU, 100, True);
...
procedure TMyForm.ApdComPortTriggerOutbuffUsed(CP : TObject);
17
76 Chapter 2: Port Component
1
1
event
begin
{buffer almost empty, start filling up again}
ApdComPort.Output := Stuff;
ApdComPort.Output := MoreStuff;
ApdComPort.Output := EvenMoreStuff;
...
end;
1
2
3
event
! Defines an event handler that is called whenever the dispatcher gets a request to send one or
more characters.
This event handler is called in a subset of the cases where the more general OnTriggerStatus
handler is called. OnTriggerStatus is called first when an output request occurs, even if an
OnTriggerOutSent handler is installed. The parameter passed to the TNotifyEvent is the
TApdComPort component that generated the trigger.
Unlike most triggers, OnTriggerOutSent does not need to be reset. The event is always
generated for output events until the trigger is deactivated.
The following example adds a status trigger for OnTriggerOutSent; thereafter, each time the
program calls any transmit method or property ApdComPortTriggerOutSent is called to
update a status display:
TrigOS : Word;
...
TrigOS := ApdComPort.AddStatusTrigger(stOutSent);
...
procedure TMyForm.ApdComPortTriggerOutSent(CP : TObject);
begin
...update display to indicate data was transmitted
end;
7
8
9
10
11
12
13
14
15
16
17
TApdComPort Component 77
1
1
OnTriggerStatus
event
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TTriggerStatusEvent = procedure(
CP : TObject; TriggerHandle : Word) of object;
! Defines an event handler that is called whenever a line status change of some kind is
detected.
This event handler combines the events described under OnTriggerLineError,
OnTriggerModemStatus, OnTriggerOutbuffFree, OnTriggerOutbuffUsed, and
OnTriggerOutSent.
CP is the TApdComPort component that generated the trigger. TriggerHandle is the handle
number returned when the trigger was added.
With the exception of OnTriggerOutSent, status triggers are not self-restarting. The event
handler must call SetStatusTrigger again to reactivate the trigger as needed.
The following example adds and activates status triggers for line errors and modem status
changes. Subsequent status events are handled by ApdComPortTriggerStatus.
TrigLE : Word;
TrigMS : Word;
...
TrigLE := ApdComPort.AddStatusTrigger(stLine);
TrigMS := ApdComPort.AddStatusTrigger(stModem);
ApdComPort.SetStatusTrigger(
TrigLE, lsParity or lsFraming or lsOverrun or lsBreak, True);
ApdComPort.SetStatusTrigger(
TrigMS, msRingDelta or msDSRDelta, True);
...
procedure TMyForm.ApdComPortTriggerStatus(
CP : TObject; TriggerHandle : Word);
begin
if TriggerHandle = TrigLE then begin
...handle line error or break
...reset line error trigger
end else if TriggerHandle = TrigMS then begin
...handle modem status change
...reset modem status trigger
end;
end;
17
78 Chapter 2: Port Component
1
1
OnTriggerTimer
event
TTriggerTimerEvent = procedure(
CP : TObject; TriggerHandle : Word) of object;
! Defines an event handler that is called when an Async Professional timer expires.
CP is the TApdComPort component that generated the trigger. TriggerHandle is the handle
number returned when the trigger was added.
3
4
Note that timer triggers are not self-restarting. The event handler must call SetTimerTrigger
again to reactivate the trigger as needed.
The following example adds and activates two timer triggers. After 10 seconds and 60
seconds elapse, events are generated and handled by ApdComPortTriggerTimer.
Timer1, Timer2 : Word;
...
Timer1 := ApdComPort.AddTimerTrigger;
Timer2 := ApdComPort.AddTimerTrigger;
ApdComPort.SetTimerTrigger(Timer1, 182, True);
ApdComPort.SetTimerTrigger(Timer2, 1092, True);
...
procedure TMyForm.ApdComPortTriggerTimer(
CP : TObject; TriggerHandle : Word);
begin
if TriggerHandle = Timer1 then begin
...handle 10 second timeout condition
{restart timer}
ApdComPort.SetTimerTrigger(Timer1, 182, True);
end else begin
...handle 60 second timeout condition
{restart timer}
ApdComPort.SetTimerTrigger(Timer2, 1092, True);
end;
end;
6
7
8
9
10
11
12
13
14
15
16
17
TApdComPort Component 79
1
1
Open
property
Default: False
! Determines whether the physical port is opened and initialized with all current port
3
4
5
6
7
properties.
Open must be set to True before a comport component can send or receive characters. If the
AutoOpen property is set to True, the comport component will open itself automatically
under many conditions: calling any I/O method or property or when a component that uses
a TApdComPort is loaded.
When Open is set to True, the TApdComPort uses all current property settings to allocate
input and output buffers, open the physical port, initialize the line settings and flow control
settings, and enable or disable tracing and logging. It then registers a low-level trigger for the
port, which gets the first look at all trigger events and passes control on to the appropriate
OnTriggerXxx event handlers.
When Open is set to False, the TApdComPort turns off tracing and logging (by setting the
associated properties to tlDump, which creates an output file if any information has been
buffered), closes the physical port, and deallocates input and output buffers.
There is no harm done by setting Open to True when it is already True, or setting it to False
when it is already False.
10
11
12
13
14
15
16
17
80 Chapter 2: Port Component
1
1
The following example checks for sufficient output buffer space to transmit a block of
NeededSpace bytes. If enough space is available the block is transmitted. Otherwise, a status
trigger is added to detect the required free space. The code assumes that an OnTriggerStatus
event handler has already been activated.
if ApdComPort.OutBuffFree >= NeededSpace then
ApdComPort.PutBlock(Data, NeededSpace)
else begin
MyHandle := ApdComPort.AddStatusTrigger(stOutBuffFree);
ApdComPort.SetStatusTrigger(MyHandle, NeededSpace, True);
end;
1
2
3
4
Use OutBuffUsed to detect whether or not any outgoing data remains in the output buffer.
The following example checks to see if any outgoing data is still in the output buffer. If so, it
sets a status trigger to go off once the buffer is completely empty. The code assumes that an
OnTriggerStatus event handler has already been activated.
if ApdComPort.OutBuffUsed <> 0 then begin
MyHandle := ApdComPort.AddStatusTrigger(stOutBuffUsed);
ApdComPort.SetStatusTrigger(MyHandle, 0, True);
end;
9
10
11
12
13
Assigning a value to Output is equivalent to calling the PutString method with that same
string.
14
15
ApdComPort.Output := 'ATDT555-1212'^M;
16
17
TApdComPort Component 81
1
1
OutSize
property
Default: 4096
! Determines the size, in bytes, of the output buffer used by the Windows communications
3
4
5
6
driver.
OutSize must be large enough to hold the largest block of data that you might transmit at
one time (using PutBlock, for example). For file transfer protocols OutSize must be at least
2078 bytes. The recommended setting is 4096, which is large enough to work with all
protocols but not so large that it is wasteful.
To obtain a non-default buffer size, OutSize must be set before the port is opened.
See also: Open, InSize
Parity
property
7
property Parity : TParity
Default: pNone
10
If the port is open when Parity is changed, the line parameters are updated immediately.
Parity does not validate the assigned value before passing it on to the communications
driver. The driver may reject the value, leading to an exception.
11
12
ProcessCommunications
method
procedure ProcessCommunications;
13
14
15
16
17
82 Chapter 2: Port Component
1
1
The internal dispatcher, which is responsible for retrieving data from the Windows
communication driver, is normally called from an applications message loop. If an
application isnt calling its message loop then no new received data will be retrieved. To
retrieve new data the application must call ProcessCommunications, usually in a loop, until
it receives its data or times out.
Note that ProcessCommunications is provided for those cases where an application must
wait (for timing reasons) for a particular response. Normally, an application would use
OnTriggerAvail and OnTriggerData event handlers to wait for data.
The following example sends a string and waits for a response:
ET : EventTimer;
S : string;
...
S := '';
ApdComPort.Output := 'login:';
NewTimer(ET, 182);
repeat
ApdComPort.ProcessCommunications;
if ApdComPort.CharReady then
S := S + ApdComPort.GetChar;
until (S = 'ABC') or TimerExpired(ET);
1
2
3
4
6
7
8
PromptForPort
property
10
Default: True
11
! Indicates whether the user should be prompted for the serial port number.
If PromptForPort is True and ComNumber is zero, a dialog is displayed to prompt the user
for the serial port when the port is opened:
If PromptForPort is False and ComPort is zero, an ENoPortSelected exception is raised
when the port is opened. This is the same behavior as older versions of Async Professional,
which do not have a PromptForPort property.
12
13
14
15
16
17
TApdComPort Component 83
1
1
PutBlock
method
! Copies a block of data to the output buffer of the Windows communications driver.
The communications driver then transmits the block byte-by-byte as fast as possible.
3
4
When there is insufficient free space in the output buffer, the documented behavior of the
Windows communications driver is to delete old data from the buffer. To avoid this
behavior, programs should always check OutBuffFree before calling any PutXxx method or
assigning a value to the Output property.
Block refers to the block of data and Len is the number of bytes to transmit. Len must be
smaller than the current value of the OutSize property.
The following example transmits a block of 20 characters after assuring that space is
available:
7
8
9
10
method
! Copies a single character to the output buffer of the Windows communications driver.
The communications driver then transmits the character as soon as possible.
11
12
The following example transmits one character after assuring that space is available:
if ApdComPort.OutBuffFree >= 1 then
ApdComPort.PutChar(C);
13
14
PutString
method
The communications driver then transmits the string as soon as possible. The length byte of
the string is not transmitted.
16
17
84 Chapter 2: Port Component
1
1
The following example transmits a string after assuring that space is available:
S := 'Guinness Stout';
if ApdComPort.OutBuffFree >= Length(S) then
ApdComPort.PutString(S);
method
3
4
procedure RemoveAllTriggers;
" Caution: Calling this method effectively disables the comport component since it removes
all triggers, including the ones that Async Professional requires internally for normal
operation of the comport and associated components.
Normally, its best to keep track of the triggers you add and remove them individually using
RemoveTrigger when they are no longer needed.
method
9
10
11
The following example adds and uses a timer trigger, and later removes it:
12
var
MyHandle : Word;
...
MyHandle := ApdComPort.AddTimerTrigger;
ApdComPort.SetTimerTrigger(MyHandle, 36, True);
...
ApdComPort.RemoveTrigger(MyHandle);
13
14
15
16
17
TApdComPort Component 85
1
1
RI
property RI : Boolean
2
3
4
5
RS485Mode
property
Default: False
! Determines whether the RTS line should be raised or lowered automatically when
transmitting data.
7
8
Set this property to True when using an RS-485 board or converter that uses the RTS line to
enable the transmit line. In this mode, RTS will be raised whenever the program is
transmitting data and lowered at all other times.
" Caution: This property should be set to True only when a program is using RS-485 ports or
9
10
11
12
converters and only if those ports or converters use RTS for line control. Enabling this
property at other times could cause programs to behave erratically or stop working
completely.
Because RS-485 mode requires control over the RTS line, the RTS property is set to False
and CTS/RTS hardware flow control is disabled whenever RS485Mode is set to True.
See RS-485 support overview on page 31 for more information on RS-485 support.
See also: BaseAddress
RTS
13
14
property
Default: True
This signal is usually used for hardware flow control, in which case your application does
not need to set it directly. Less frequently, devices require that your application raise and
lower RTS to control the device, or require that RTS be permanently set. Use this property in
those cases.
17
86 Chapter 2: Port Component
1
1
The following example lowers the RTS signal after opening the port and later raises it again:
ApdComPort := TApdComPort.Create(Self);
ApdComPort.Open := True;
ApdComPort.RTS := False;
...
ApdComPort.RTS := True;
1
2
3
method
When Yield is True, SendBreak yields control back to Windows while sending the break,
giving other applications and other parts of this application a chance to run. When Yield is
False, SendBreak does not yield.
7
8
SetBreak
method
10
11
12
13
14
15
16
17
TApdComPort Component 87
1
1
1
2
3
4
SetStatusTrigger
method
Handle is the value that was returned by the call to AddStatusTrigger. The interpretation of
Value varies between the trigger types, as described below. Activate is True to activate the
trigger, False to deactivate it. When Activate is False the Value parameter is ignored.
For triggers of type stModem, Value is a bit mask that contains one or more of the following
options:
7
8
9
10
11
12
13
14
15
16
Option
Description
msCTSDelta
msDSRDelta
msRingDelta
msDCDDelta
For the msCTSDelta, msDSRDelta, and msDCDDelta options SetStatusTrigger saves the
current state of the corresponding modem signals and checks for changes to those signals.
When a change from the original state is detected an OnTriggerStatus event is generated. If a
single trigger is used to monitor multiple signals, the message response routine must check
the appropriate modem status properties to determine which signal actually changed state.
Alternatively, a separate trigger can be added for each modem signal. Once a trigger
message is sent the trigger is disabled, even if some of the monitored signals did not change
state.
The msRingDelta option triggers an OnTriggerStatus event at the end of the next incoming
ring signal, immediately after the audible termination of the ring. In order to receive another
OnTriggerStatus event using msRingDelta, the application must not only call
SetStatusTrigger again, but it must also read the DeltaRI property to clear the ring condition
in the modem status register.
An stModem trigger also generates an OnTriggerModemStatus event. Note, however, that
no trigger handle is passed to the OnTriggerModemStatus event handler, so it cannot
distinguish among multiple different triggers. If you need to do this, use an OnTriggerStatus
event handler instead.
17
88 Chapter 2: Port Component
1
1
For triggers of type stLine, Value is a bit mask that contains one or more of the following
options:
Option
Description
lsOverrun
lsParity
lsFraming
lsBreak
1
2
3
4
If a single trigger is used to monitor multiple line status signals, the OnTriggerStatus event
handler must read the LineError property to determine the most severe error. When lsBreak
is combined with other options the response routine must read both LineError and
LineBreak to determine whether the trigger was caused by an error or by a received line
break.
An stLine trigger also generates an OnTriggerLineError event, which passes the current
values of LineError and LineBreak as parameters to its handler.
For triggers of type stOutBuffFree, an OnTriggerStatus event is generated when the number
of bytes free in the output buffer is greater than or equal to Value. An OnTriggerOutbuffFree
event is also generated by the trigger.
For triggers of type stOutBuffUsed, an OnTriggerStatus event is generated when the number
of bytes used in the output buffer is less than or equal to Value. An OnTriggerOutbuffUsed
event is also generated by the trigger.
For triggers of type stOutSent, Value is not used. Here, an OnTriggerStatus event is
generated whenever PutChar, PutString, or PutBlock is called. However, the event is not
generated directly from these routines, but is instead generated the next time the dispatcher
gains control. Only one event is generated even if multiple PutXxx calls were made or the
Output property was assigned since the last time the dispatcher ran.
8
9
10
11
12
All status triggers except stOutSent must be restarted within the message handler. That is,
the triggers generate a single message and do not restart themselves automatically.
13
The following example adds an stOutBuffFree status trigger and activates it to send a
message when at least 100 bytes are free in the output buffer:
14
var
MyHandle : Word;
...
MyHandle := ApdComPort.AddStatusTrigger(stOutBuffFree);
ApdComPort.SetStatusTrigger(MyHandle, 100, True);
15
16
17
TApdComPort Component 89
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
The following example adds an stModem trigger and activates it to send a message when
either the DSR or CTS signal changes from its current state:
var
MyHandle : Word;
...
MyHandle := ApdComPort.AddStatusTrigger(stModem);
ApdComPort.SetStatusTrigger(
MyHandle, msDSRDelta or msCTSDelta, True);
16
17
90 Chapter 2: Port Component
1
1
method
StopBits
property
Default: 1
3
4
property
6
7
Default: swfNone
9
10
11
12
13
14
15
16
17
TApdComPort Component 91
1
1
1
2
3
4
5
The following example enables bi-directional software flow control with limits at the 25%
and 75% levels of the buffer. The default characters are used for XOn and XOff. Later in the
application, software flow control is disabled.
ApdComPort.BufferFull := Trunc(0.75*ApdComPort.InSize);
ApdComPort.BufferResume := Trunc(0.25*ApdComPort.InSize);
ApdComPort.SWFlowOptions := swfBoth;
...
ApdComPort.SWFlowOptions := swfNone;
property
Default: tmAuto
7
8
9
10
11
12
13
14
15
16
TapiMode is changed to tmOn to indicate that the TApdComPort is being controlled by the
associated TApdTapiDevice. AutoOpen and Open are both set to False because the
TApdComPort should no longer control when it is opened or closedthat is now done by
TAPI.
To turn off TAPI mode, or to prevent a TAPI device from taking control of the
TApdComPort, set TapiMode to tmOff. To re-enable TAPI mode later, set TapiMode back to
tmAuto or tmOn. You must also set AutoOpen and Open to False because the
TApdTapiDevice automatically sets these properties only when either the TApdTapiDevice
or TApdComPort are first created.
The value tmNone isnt used.
17
92 Chapter 2: Port Component
1
1
See the ADXPORT form/unit in the TERMDEMO demonstration program (see the Async
Professional Developers Guide) for an example of a program that uses both TAPI devices
and direct serial port access. It modifies TapiMode accordingly as the user selects either
TAPI devices or direct serial ports.
1
2
See Chapter 8: TAPI Components on page 203 for more information on TAPI.
property
Default: False
! Determines when the trace log will contain literal printable characters, or if all characters
will be written in hexadecimal notation.
7
TraceHex
property
Default: True
! Determines whether non-printable characters stored in a trace file are written using
10
property
11
12
Default: APRO.TRC
13
14
15
16
17
TApdComPort Component 93
1
1
TraceSize
property
Default: 10000
6
7
Tracing
property
8
9
10
11
12
13
14
Default: tlOff
15
To clear the contents of the tracing buffer and continue tracing, set Tracing to tlClear. After
the component clears the buffer, it sets Tracing to tlOn.
16
To temporarily pause tracing, set Tracing to tlPause. To resume, set Tracing to tlOn.
See Tracing on page 33 for more information.
17
94 Chapter 2: Port Component
1
1
The following example turns on tracing and later dumps the tracing buffer to APRO.TRC:
ApdComPort.Tracing := tlOn;
...
ApdComPort.TraceName := 'APRO.TRC';
ApdComPort.Tracing := tlDump;
3
property
4
property UseEventWord : Boolean
Default: True
" Caution: Yielding introduces the possibility of reentrancy, which your application must
anticipate and prevent. For example, if WaitForString is called from within a buttons
OnClick event handler with Yield set to True, the user is able to navigate back to the button
and click on it again. Although WaitForString would work in this situation (and would
thereby start a wait within a wait) you probably do not want this to happen. Its up to the
application to prevent this by disabling the button or the screen containing the button or by
checking for reentrancy within the OnClick event handler.
The reentrancy issue also applies to other parts of the application since most applications
provide menu options and dialog boxes for changing port parameters, starting file transfers,
dialing the modem, and so on. The application must prevent the user from instigating any
actions that interfere with WaitForString until WaitForString returns.
6
7
8
9
10
11
12
13
14
15
16
17
TApdComPort Component 95
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
None of these problems apply when Yield is False because WaitForString wont allow other
message processing while it is waiting. However, you should use this approach only for brief
periods of just a few ticks since it prevents Windows from processing other applications and,
worse yet, worries your user since the machine appears frozen until WaitForString returns.
Note that WaitForString uses GetChar to retrieve data, which may prevent this data from
being seen by any trigger handlers for the same comport component (unless WaitForString
is called from within a trigger handler itself). However, each received character generates an
OnWaitChar event, so an event handler can be implemented to pass the data to other
processes.
Note that WaitForString is depreciated and maintained for backward compatibility. In most
cases, other alternatives, such as using the TApdDataPacket component or data triggers, are
more appropriate for Windows applications. Data triggers avoid the reentrancy problems
while still allowing Windows to process messages for other applications and other windows
in the current application. Data triggers are more complex to use than WaitForString but are
well worth the effort in the long run.
The following example shows an OnWaitChar event handler that manually stuffs received
data into a terminal window:
procedure TForm.ApdComPort1WaitChar(CP : TObject; C : Char);
begin
ApdTerminal1.StuffChar(C);
ApdTerminal1.ForcePaint;
end;
The following example is the OnClick event handler from a Login button that waits for
and responds to login and password prompts from a remote host:
procedure TForm1.LoginClick(Sender : TObject);
begin
ApdComPort.Output := 'ATDT260-9726'^M;
if not ApdComPort.WaitForString('login', 1092, True, True) then
...handle timeout error
ApdComPort.Output := 'myname';
if not ApdComPort.WaitForString(
'password', 182, True, True) then
...handle timeout error
ApdComPort.Output := 'secret';
...
end;
17
96 Chapter 2: Port Component
1
1
XOffChar
property
! Determines the character that is sent to disable remote sending when software flow control is
active.
Software flow control almost universally uses the XOff (ASCII 19) character to suspend
transmission, and this is the default character used by Async Professional. If you should
encounter a device that requires a different character, you can use XOffChar to set it.
property
6
property XOnChar : Char
! Determines the character that is sent to enable remote sending when software flow control is
active.
Software flow control almost universally uses the XOn (ASCII 17) character to enable
transmission, and this is the default character used by Async Professional. If you should
encounter a device that requires a different character, you can use XOnChar to set it.
9
10
11
12
13
14
15
16
17
TApdComPort Component 97
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
98 Chapter 2: Port Component
1
1
1
2
Windows includes routines for network and Internet communications. These routines are
contained in DLLs which are collectively called Winsock (for WINdows SOCKets). Winsock
is a Windows-specific implementation of the Berkley Sockets API. The Berkley Sockets API
was developed as a protocol to allow UNIX machines to communicate with each other over
networks. The concept of sockets is analogous to a telephone operator in the early days of
telephones. When a call came in, the operator used a patch cord to connect the callers
socket to the socket of the person being called. Winsock does essentially the same thing. It
provides a means of connecting a calling computer to a host computer so that the two can
exchange information. The calling application is called a client and the host application is
called a server.
3
4
5
6
Before a connection can be established, Winsock needs to know how to find the host
computer. Each network computer has an address associated with it. This address, called the
IP address, is a 32-bit value that uniquely identifies the machine. Since a number like
32,147,265 is difficult to remember, network addresses are often displayed in dot notation.
Dot notation specifies an IP address as a series of four bytes, each separated by a dot. For
example, the TurboPower Web site address can be specified in dot notation as
165.212.210.12. Network software translates the address specified in dot notation to a real
32-bit value.
7
8
9
" Caution: Leading zeros in a dot notation IP address (for example, 198.168.010.012)
10
causes Winsock to interpret the respective portion of the address in octal (the above IP
would actually be interpreted by Winsock as 198.168.8.10). APRO does not interfere with
this behavior, it simply passes the entered address to Winsock as is.
11
While expressing a network address in dot notation is a little better than dealing with a raw
32-bit value, it is still not particularly easy to remember. For that reason, a global database
gives you the capability to specify an IP address in plain text. This database, called the
Domain Name Service (DNS), has text entries that correspond to IP address values. For
example, the TurboPower Web site DNS entry is www.turbopower.com. If Winsock does a
lookup for the host name www.turbopower.com, it gets the IP address 165.212.210.12.
12
13
Not all computers have DNS entries. A DNS entry is usually used to provide public access to
a computer. Servers that are for private use only dont publish their IP addresses.
14
Most software allows you to specify either the host name or the IP address in dot notation
when attempting to connect to a server. To illustrate, start your favorite Web browser and
type www.turbopower.com at the address prompt. When you hit Enter, your browser
displays the home page of the TurboPower Web site. Now try again, but this time type
165.212.210.12 at the address prompt. Once again the browser takes you to the
TurboPower Web site.
15
16
17
99
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Async Professional includes a device layer, dlWnsock, that utilizes Winsock for network and
Internet communications.
The Async Professional implementation of Winsock consists of two components.
TApdWinsockPort is a component that replaces the TApdComPort component and can be
placed on a form at design time. TApdWinsockPort includes properties to allow you to set
the network address, the port number, and the mode of the socket (server mode or client
mode).
TApdWinsockPort is derived from TApdCustomComPort and therefore inherits all of its
properties and methods. Many of these properties and methods are not applicable to
TApdWinsockPort when operating in Winsock mode, but are retained in the descendent
component so that TApdWinsockPort behaves exactly like TApdComPort when the
DeviceLayer property is not set to dlWinsock. The properties and methods that do not
apply to Winsock operation (e.g., Baud, DataBits, Parity, and StopBits) are simply ignored
when DeviceLayer is set to dlWinsock. Certain Async Professional components (e.g., the
modem and TAPI components) are not applicable when using the dlWinsock device layer.
Faxing over the Internet is not supported because Internet faxing uses a different protocol
than faxmodems.
TApdSocket is a low-level component that provides access to most standard Winsock
services. This component is used internally by Async Professional. A global instance of this
component, ApdSocket, is created for use by the Winsock device layer in the initialization
code of the AwWnsock unit. In most cases you wont need to, but you can create your own
instance of this class.
The Winsock support in Async Professional is not intended as a full-featured Winsock
implementation. Rather, it is intended to allow you to perform basic communications
operations over local networks or over the Internet. Certain concessions were made (such as
allowing only one client connection to a server socket) to allow the Winsock
implementation to fit into the existing Async Professional communications model.
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
102 Chapter 3: Winsock Components
1
1
TApdSocksServerInfo Class
If the connection attempt fails, the OnWsError event is generated and the Open property is
set to False. The developer can test the ErrorCode parameter of the OnWsError event to
determine whether the failure was due to the SOCKS server or due to some other type of
failure.
3
4
Hierarchy
7
TPersistent (VCL)
TApdSocksServerInfo (AdWnPort)
Properties
Address
SocksVersion
Password
Port
UserCode
9
10
11
12
13
14
15
16
17
1
1
Reference Section
Address
run-time property
2
property Address : string
run-time property
4
property Password : string
run-time property
6
property Port : Word
run-time property
8
property SocksVersion : TApdSocksVersion
Meaning
svNone
svSocks4
Specifies Socks4.
svSocks5
Specifies Sock5.
12
13
14
15
Socks4a has extended Socks4 by adding DNS lookup by the server. Both Socks4 and
Socks4a are supported. If SocksVersion is set to svSocks4, Socks4 will be attempted if the
WsAddress property contains a dotted-quad IP address, or Socks4a will be used if the
WsAddress property contains a domain name.
16
17
104 Chapter 3: Winsock Components
1
1
run-time property
2
3
4
! Specifies the user name or code needed to access the proxy server.
6
7
8
9
10
11
12
13
14
15
16
17
TApdSocksServerInfo Class 105
1
1
TApdWinsockPort Component
The TApdWinsockPort component provides a Winsock port that can be used to establish a
TCP/IP connection. In addition, it provides all of the services of the standard
TApdComPort component. For a description of the properties, events, and methods of
TApdComPort, see TApdComPort Component on page 22. To put the TApdWinsockPort
in Winsock mode, simply set the DeviceLayer property to dlWinsock.
3
4
5
6
7
8
If you use the TApdWinsockPort in Winsock mode, it cannot be used with the TAdModem
because in this case Async Professional is not directly controlling a modem. It also cannot be
used with TApdSendFax or TApdReceiveFax because in this case Async Professional is not
directly communicating with a faxmodem or fax machine.
The TApdWinsockPort component is an implementation of the Winsock version 1.1 API.
Example
This example shows how to connect to the Library of Congress via telnet. Create a new
project, add the following components, and set the property values as indicated in Table 3.1.
Table 3.1: Example components and property values
Component
Property
Value
TApdWinsockPort
DeviceLayer
dlWinsock
10
11
15
16
80
25
Caption
Open
TButton
Caption
Close
Double-click on the Open buttons OnClick event handler in the Object Inspector and
modify the generated method to match this:
procedure TForm1.OpenClick(Sender : TObject);
begin
ApdWinsockPort1.Open := True;
end;
Columns
Rows
17
False
TButton
12
14
locis.loc.gov
AutoOpen
TAdEmulator
TAdTerminal
13
WsAddress
Double-click on the Close buttons OnClick event handler in the Object Inspector and
modify the generated method to match the following code:
procedure TForm1.CloseClick(Sender : TObject);
begin
ApdWinsockPort1.Open := False;
end;
1
2
3
4
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
" TApdComPort (AdPort) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
TApdWinsockPort (AdWnPort)
Properties
" AutoOpen
" DSR
Open
" BaseAddress
" DTR
" OutBuffFree
" Baud
" FlowState
" OutBuffUsed
" BufferFull
" HWFlowOptions
" Output
" BufferResume
" InBuffFree
" OutSize
" ComHandle
" InBuffUsed
" Parity
" ComNumber
" InSize
" RI
" CTS
" LineBreak
" RS485Mode
" DataBits
" LineError
" RTS
" DCD
" LogAllHex
" StopBits
" DeltaCTS
" Logging
" SWFlowOptions
" DeltaDCD
" LogHex
" TapiMode
" DeltaDSR
" LogName
" TraceAllHex
" DeltaRI
" LogSize
" TraceHex
" ModemStatus
" TraceName
DeviceLayer
9
10
11
12
13
14
15
16
17
1
1
1
2
" TraceSize
WsLocalAddresses
" Tracing
WsLocalAddressIndex
" XOffChar
" UseEventWord
WsMode
" XOnChar
! Version
WsPort
WsAddress
3
4
5
6
7
8
9
10
11
" ActivateDeviceLayer
" ForcePortOpen
" PutString
" AddDataTrigger
" GetBlock
" RemoveAllTriggers
" AddStatusTrigger
" GetChar
" RemoveTrigger
" AddTimerTrigger
" InitPort
" SendBreak
" AddTraceEntry
" PeekBlock
" SetBreak
" CharReady
" PeekChar
" SetStatusTrigger
" CheckForString
" ProcessCommunications
" SetTimerTrigger
" FlushInBuffer
" PutBlock
" FlushOutBuffer
" PutChar
Events
" OnPortClose
" OnTriggerModemStatus
OnWsAccept
" OnPortOpen
" OnTriggerOutbuffFree
OnWsConnect
" OnTrigger
" OnTriggerOutbuffUsed
OnWsDisconnect
" OnTriggerAvail
" OnTriggerOutSent
OnWsError
" OnTriggerData
" OnTriggerStatus
" OnTriggerLineError
" OnTriggerTimer
13
14
15
16
17
108 Chapter 3: Winsock Components
WsSocksServerInfo
Methods
12
WsTelnet
Reference Section
DeviceLayer
property
2
property DeviceLayer : TDeviceLayer
TDeviceLayer = (dlWin16, dlFossil, dlWin32, dlWinsock);
Default: dlWinsock
You can create custom device layers by deriving them from TApdBaseDispatcher and
creating a new port descendant from TApdCustomComport where you override
ActivateDeviceLayer to return the newly defined device layer.
OnWsAccept
8
event
! Defines an event handler that is called when a client attempts to connect to a server.
This event is generated when an application is acting as a server (WsMode equals WsServer)
and a client application attempts a connection. Addr is the network address of the client. To
accept the connection, set Accept to True. To refuse the connection, set Accept to False.
OnWsAccept is not generated when an application is acting as a client.
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
OnWsConnect
event
11
12
13
14
15
16
17
110 Chapter 3: Winsock Components
1
1
OnWsDisconnect
event
3
4
6
7
OnWsError
event
9
property OnWsError : TWsErrorEvent
TWsErrorEvent = procedure(
Sender : TObject; ErrorCode : Integer) of object;
10
11
12
13
14
15
16
17
1
1
Open
property
Default: False
Open must be set to True before a Winsock port can send or receive characters. When Open
is set to True, the TApdWinsockPort uses all current property settings to allocate input and
output buffers, create a socket, open the Winsock port, and enable or disable tracing and
logging. It then registers a low-level trigger handler, which gets the first look at all trigger
events and passes control on to the appropriate OnTriggerXxx event handlers.
When Open is set to False, the TApdWinsockPort sets the tracing and logging properties to
tlDump (which creates output files if any information was buffered), closes the Winsock
port, and deallocates input and output buffers.
There is no harm done by setting Open to True when it is already True, or setting it to False
when it is already False. If WsMode equals WsServer and you set Open to True, a socket is
created and it listens at the port designated by the WsPort property. If WsMode equals
WsClient and you set Open to True, the component attempts to connect to a server at the
designated WsAddress and WsPort.
WsAddress
property WsAddress : string
" Caution: Do not add leading zeros in dot notation addresses (e.g., 165.212.210.010).
Leading zeros will cause the number to be interpreted as an octal value.
14
15
16
17
112 Chapter 3: Winsock Components
1
1
property
WsLocalAddresses
3
4
run-time property
WsMode
property
9
property WsMode : TWsMode
TWsMode = (wsClient, wsServer);
10
Default: WsClient
11
12
13
14
15
16
17
TApdWinsockPort Component 113
1
1
WsPort
property
Default: telnet
WsPort is the Winsock port on which to connect (for a client application) or on which to
listen (for a server application). WsPort accepts the port as an integer or a service name
(e.g., telnet). If a service name is used, Winsock performs a lookup when the port is opened
to match the service name with a port number. For a list of service names and their
corresponding port numbers, see the SERVICES file in the Windows directory (for
Windows NT it is in the WINNT\SYSTEM32\DRIVERS\ETC directory.
See also: WsAddress
WsSocksServerInfo
7
8
9
10
run-time property
property
11
12
13
14
Default: True
15
16
17
114 Chapter 3: Winsock Components
1
1
TApdSocket Component
The TApdSocket component is a low-level class that provides many standard Winsock
services. It is essentially a thin wrapper around the Winsock API and transparently handles
tasks such as loading, starting, and shutting down Winsock. It is used internally by the
Async Professional Winsock device layer and the TApdWinsockPort component. In most
cases you wont need to make use of the TApdSocket component directly, but it is
documented here in case you do.
A global instance of the TApdSocket class (ApdSocket) is created in the initialization code of
the Winsock device layer unit (AwWnsock), and is available for use in your application. To
use its services, simply add AwWnsock to your units uses clause. Because it is a low-level
class, the Winsock services it provides access to are not documented in detail here. There are
many Winsock references available to consult. The following were useful in the development
of TApdSocket:
3
4
6
7
8
9
ISBN 0-201-63372-8
Roberts, Developing for the Internet with Winsock, Coriolis Group Books,
10
ISBN 1-883577-42-X
11
12
13
14
15
16
17
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdSocket (AdSocket)
3
4
5
Properties
Description
LocalAddress
Handle
LocalHost
HighVersion
MaxSockets
LastError
SystemStatus
! Version
WSVersion
Methods
7
8
9
10
11
12
AcceptSocket
htons
ntohl
BindSocket
ListenSocket
ntohs
CheckLoaded
LookupAddress
ReadSocket
CloseSocket
LookupName
SetAsyncStyles
ConnectSocket
LookupPort
String2NetAddr
CreateSocket
LookupService
WriteSocket
htonl
NetAddr2String
Events
OnWsAccept
OnWsDisconnect
OnWsRead
OnWsConnect
OnWsError
OnWsWrite
13
14
15
16
17
116 Chapter 3: Winsock Components
1
1
Reference Section
AcceptSocket
method
2
function AcceptSocket(
Socket : TSocket; var Address : TSockAddrIn) : TSocket;
TSockAddrIn = packed
case Integer of
0: (sin_family :
sin_port
:
sin_addr
:
sin_zero
:
1: (sa_family :
sa_data
:
end;
record
Word;
Word;
TInAddr;
array[0..7] of AnsiChar);
Word;
array[0..13] of AnsiChar)
method
function BindSocket(
Socket : TSocket; Address : TSockAddrIn) : Integer;
TSockAddrIn = packed
case Integer of
0: (sin_family :
sin_port
:
sin_addr
:
sin_zero
:
1: (sa_family :
sa_data
:
end;
7
8
9
10
record
11
Word;
Word;
TInAddr;
array[0..7] of AnsiChar);
Word;
array[0..13] of AnsiChar)
12
13
14
15
16
17
TApdSocket Component 117
1
1
CheckLoaded
method
procedure CheckLoaded;
Call CheckLoaded to see if Winsock is ready for use. If Winsock is not initialized,
CheckLoaded raises an EApdSocketException. This exception can be caught in your
application and responded to accordingly.
CloseSocket
method
! Closes a socket.
CloseSocket closes a socket and frees the memory allocated for it. Socket is the handle of the
socket to close.
8
9
10
11
12
13
14
ConnectSocket
method
function ConnectSocket(
Socket : TSocket; Address : TSockAddrIn) : Integer;
TSockAddrIn = packed
case Integer of
0: (sin_family :
sin_port
:
sin_addr
:
sin_zero
:
1: (sa_family :
sa_data
:
end;
record
Word;
Word;
TInAddr;
array[0..7] of AnsiChar);
Word;
array[0..13] of AnsiChar)
15
16
17
118 Chapter 3: Winsock Components
1
1
CreateSocket
method
! Creates a socket.
If the socket is created successfully, CreateSocket returns a unique socket descriptor that is
used to refer to this socket in subsequent Winsock operations. If the socket cannot be
created, CreateSocket raises an EApdSocketException.
Description
8
9
10
11
12
13
! Contains the highest version of the Winsock specification supported by the current
14
Winsock DLL.
For the Windows NT 4.0 and 2000 Winsock, HighVersion is 2.2, which indicates that it can
support version 2.2 of the Winsock specification. For the Windows 95/98/ME Winsock,
HighVersion is 1.1.
15
16
17
TApdSocket Component 119
1
1
htonl
method
2
3
4
! Translates a 32-bit value from host byte order to network byte order.
IBM-compatible computers typically store data in memory in little-endian byte order (the
least significant byte stored first followed by the most significant byte) or host byte order.
TCP/IP stipulates that data should be sent in big-endian byte order (most significant byte
followed by least significant byte) or network byte order.
See also: htons, ntohl, ntohs
5
6
7
8
9
htons
function htons(HostShort : Word) : Word;
! Translates a 16-bit value from host byte order to network byte order.
IBM-compatible computers typically store data in memory in little-endian byte order (the
least significant byte stored first followed by the most significant byte) or host byte order.
TCP/IP stipulates that data should be sent in big-endian byte order (most significant byte
followed by least significant byte) or network byte order.
See also: htonl, ntohl, ntohs
LastError
10
11
12
14
15
16
17
120 Chapter 3: Winsock Components
13
method
ListenSocket
method
function ListenSocket(
Socket : TSocket; Backlog : Integer) : Integer;
1
2
3
4
7
8
9
10
11
12
13
14
15
16
17
TApdSocket Component 121
1
1
LookupAddress
method
2
3
4
5
6
7
8
9
10
11
12
13
14
LookupName
function LookupName(const Name : string) : TInAddr;
TInAddr = packed record
case Integer of
0 : (S_un_b : SunB);
1 : (S_un_w : SunW);
2 : (S_addr : LongInt);
end;
! LookupName gets an Internet address for the host name specified by Name.
The Internet address is returned as a TInAddr structure.
15
16
17
122 Chapter 3: Winsock Components
1
1
method
The following example gets an Internet address from the host name
www.turbopower.com and then uses the NetAddr2String method to display the address in
a label:
1
2
var
MyAddr : TInAddr;
with TApdSocket.Create(Self) do try
MyAddr := LookupName('www.turbopower.com');
AddressLabel.Caption := NetAddr2String(MyAddr);
finally
Free;
end;
3
4
method
! Gets a text string of the service name for the port specified by Port.
There are certain well-known ports used in Winsock. For example, port 25 is typically used
for SMTP (mail), port 23 is used for telnet, and port 119 is used for NNTP (news):
with TApdSocket.Create(Self) do try
ServiceLabel.Caption := LookupPort(25);
finally
Free;
end;
8
9
10
11
12
13
14
15
16
17
TApdSocket Component 123
1
1
LookupService
method
2
3
4
5
6
7
! Gets the port number for the service name specified by Service.
The service name should be one of the Winsock well-known services (such as SMTP). If
the service cannot found, LookupService returns an empty string.
var
MyPort : Integer;
with TApdSocket.Create(Self) do try
MyPort := LookupService('smtp');
finally
Free;
end;
8
9
! The maximum number of sockets available for the current version of Winsock.
NetAddr2String
function NetAddr2String(InAddr : TInAddr) : string;
10
11
12
13
14
15
16
17
124 Chapter 3: Winsock Components
1
1
method
The following example converts an Internet address to a string. The string is then displayed
in a label component.
var
MyAddr : TInAddr;
with TApdSocket.Create(Self) do try
MyAddr := LookupName('www.turbopower.com');
AddressLabel.Caption := NetAddr2String(MyAddr);
finally
Free;
end;
1
2
3
4
method
! Translates a 32-bit value from network byte order to host byte order.
IBM-compatible computers typically store data in memory in little-endian byte order (the
least significant byte stored first followed by the most significant byte) or host byte order.
TCP/IP stipulates that data should be sent in big-endian byte order (most significant byte
followed by least significant byte) or network byte order.
8
9
method
10
11
! Translates a 16-bit value from network byte order to host byte order.
IBM-compatible computers typically store data in memory in little-endian byte order (the
least significant byte stored first followed by the most significant byte) or host byte order.
TCP/IP stipulates that data should be sent in big-endian byte order (most significant byte
followed by least significant byte) or network byte order.
12
13
14
15
16
17
TApdSocket Component 125
1
1
OnWsAccept
event
2
3
TWsNotifyEvent = procedure(
Sender: TObject; Socket: TSocket) of object;
! Defines an event handler that is called when the server accepts a connection.
This event is primarily used when an application is operating as a server. The server
application listens on a specific port for possible connections. When a client socket tries to
connect, the OnWsAccept event is generated.
6
7
8
9
event
10
11
12
OnWsDisconnect
property OnWsDisconnect : TWsNotifyEvent
TWsNotifyEvent = procedure(
Sender: TObject; Socket: TSocket) of object;
13
14
15
16
17
126 Chapter 3: Winsock Components
1
1
event
OnWsError
event
Socket identifies the socket for which the error occurred. ErrorCode contains the Winsock
error code. See Error Handling and Exception Classes on page 900 for a list of the error
codes.
event
! Defines an event handler that is called when data is available to be read on a socket.
event
10
TWsNotifyEvent = procedure(
Sender : TObject; Socket : TSocket) of object;
! Defines an event handler that is called when Winsock can accept more data from a socket.
See also: OnWsRead
ReadSocket
11
12
method
13
function ReadSocket(
Socket : TSocket; var Buf; BufSize, Flags : Integer) : Integer;
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SetAsyncStyles
function SetAsyncStyles(
Socket : TSocket; lEvent : LongInt) : Integer;
17
128 Chapter 3: Winsock Components
method
16
method
SystemStatus
method
function WriteSocket(
Socket : TSocket; var Buf; BufSize, Flags : Integer) : Integer;
Socket is the socket on which to send data. Buf is the buffer that contains the data. BufSize is
the size of Buf in bytes. Flags determines the send method. Set Flags to zero for normal
operation or see your Winsock documentation for other possible values.
WriteSocket does not send the data directly to the receiving end. Winsock queues the data
and sends it when possible. The return value from WriteSocket is the number of bytes
queued for transmission.
See also: ReadSocket
WsVersion
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
The following example gets the version number, translates it into a text string, and displays it
in a label component:
var
MyVer : Word;
with TApdSocket.Create(Self) do try
MyVer := WsVersion;
VerLabel.Caption := Format('%d.%d', [LoByte(MyVer),
HiByte(MyVer)]);
finally
Free;
end;
6
7
8
9
10
11
12
13
14
15
16
17
130 Chapter 3: Winsock Components
1
1
1
2
The purpose of the data packet component is to provide a simple solution to the common
task of looking for a particular sequence of bytes in the incoming data. Data packet
components collect data that has certain properties and pass that data as a complete unit to
the client application.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
131
1
1
TApdDataPacket Component
The TApdDataPacket component provides automatic data packet delivery from the
incoming data stream based on simple properties set in the component.
A data packet can be thought of as an advanced data trigger. Packets automatically collect
data from the incoming data stream based on criteria specified in the properties of the data
packet component, and deliver the data when the criteria have been met. As opposed to
traditional data triggers, data packets do their own buffering. This means that data packets
do not have the same limitation as data triggers (that data may no longer be available in the
input buffer for processing when the data trigger fires).
4
5
6
You would typically use data packets in place of data triggers when the data you are looking
for has a fixed length or starts or ends with a known string of data. These conditions can be
set in the data packet component at design time or run time.
Data as packets
8
9
10
11
Most data arriving at the serial port can be described as a packet. It will have a start
condition (something that defines the beginning of the data) and an end condition
(something that defines the end of the data). The TApdDataPacket component supports
start conditions of a character or characters, or any data. The TApdDataPacket component
supports end conditions of a character or characters, timeout, or a specific number of
characters. The simplest data packet is a single string, such as hello, and can progress
through more complicated packets that define other packets within the collected data. In
broad strokes, packets can be categorized as follows:
A specific character/string: The StartString defines the packet in its entirety. Set
StartCond to scString (the default) and StartString to the string to detect:
12
13
14
15
...
ApdDataPacket1.StartCond := scString;
ApdDataPacket1.StartString := 'hello';
...
A bracketed packet: This is the most common usage, where the beginning and ending
of the data is defined by known characters/strings. For example, you may be
expecting data starting with an <STX> (#2) character, followed by a chunk of data,
16
17
132 Chapter 4: Data Packet Component
1
1
1
2
3
4
Note: C++Builder uses a more difficult implementation of sets than Delphi does, use the
following syntax to set the EndCond property:
...
ApdDataPacket1->EndCond.Clear();
ApdDataPacket1->EndCond << ecString;
...
...
ApdDataPacket1.StartCond := scString
ApdDataPacket1.StartString := #2; // STX char
ApdDataPacket1.EndCond := [ecPacketSize];
ApdDataPacket1.IncludeStrings := True;
ApdDataPacket1.PacketLength := 19; // 18 data chars,
1 start char
...
These are only a few of the possibilities. Your data may vary. You may have a start string,
followed by a character indicating the length of the data (use two data packets, one to collect
the start string and length char, the other to capture the next length number of chars), or
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
you may have something that needs a more liberal packet interpretation. If you can
conceptualize the expansibility of the packet format, you can usually work something up
that works for your conditions.
Data ownership
There is no limit on the number of data packet components for a port, however, any
incoming character can be part of only one data packet. The first enabled data packet that
has its start condition met takes ownership of all incoming data until the packet is complete.
If a data packet times out, the data it has collected up to that point is made available to any
other enabled data packets for the port.
The TApdDataPacket component has a component editor, shown in Figure 4.1, where all
properties can conveniently be set at once. You can invoke it by right clicking on the contextmenu of the component.
7
8
9
10
11
12
13
Figure 4.1: TApdDataPacket component editor.
14
15
The Packet Start Condition defines the start of the packet. You have the option to start the
packet as soon as any data is received or you can start data collection when a particular
string is received.
16
Refer to the StartCond and StartString properties in the reference section for more
information on starting a packet.
17
134 Chapter 4: Data Packet Component
1
1
1
2
Refer to the EndCond, EndString and PacketSize properties in the reference section for
more information on terminating a packet.
Additional properties
The additional properties define details about how the packet should operate: Whether it
should be initially enabled, whether it should automatically re-enable after having been
received (the default is that it re-enables itself), whether case should be ignored on the start
and end strings, whether or not the start and end strings should be included in the packet
delivered in the OnPacket events and whether the packet collection logic can time out for
this packet and what the time-out period should be.
Refer to the AutoEnable, IgnoreCase, IncludeStrings and TimeOut properties in the
reference section for more information on these additional properties.
6
7
8
10
Wildcards in the packet definition can be very useful. The wildcard character is a single
question mark (?). This is interpreted as any single character. Since a single ? is now
considered a wildcard, use \? to detect a literal ? in the data stream.
12
For example, a relatively common packet will contain a block of data terminated by a
character that is followed by a checksum character. This can be captured by setting the
EndString to the terminating character and a ?:
...
ApdDataPacket1.EndString := #3 + '?'; // ETX and the next char
...
If IncludeStrings is True, the last char in the collected data will be the checksum.
11
13
14
15
16
17
1
1
Example
Property
Value
TApdComport
TApdDataPacket
5
6
StartString
ATI3#13
EndString
OK#13
EndCond
[ecString]
IncludeStrings
False
TButton
7
8
9
10
11
12
13
Double-click on the buttons OnClick event handler in the Object Inspector and modify the
generated source code to match this:
procedure TForm1.Button1Click(Sender : TObject);
begin
ApdComPort1.PutString('ATI3'#13);
end;
Compile and run the application. When prompted, select a serial port that has a modem
attached. When you press the button, you should see the caption change to the data set
name (the response to ATI3) reported by the modem.
14
15
16
17
136 Chapter 4: Data Packet Component
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdDataPacket (AdPacket)
2
3
Properties
AutoEnable
EndString
StartCond
ComPort
IgnoreCase
StartString
Enabled
IncludeStrings
EndCond
PacketSize
TimeOut
! Version
Events
OnPacket
OnTimeout
OnStringPacket
7
8
9
10
11
12
13
14
15
16
17
1
1
Reference Section
AutoEnable
property
2
property AutoEnable : Boolean
Default: True
AutoEnable controls what happens after the packet is received (the start string and end
condition for the packet are met in the data stream). If AutoEnable is True, the data packet is
enabled again and TApdDataPacket starts watching for the start string again. If AutoEnable
is False, the data packet is disabled.
ComPort
property
7
8
property
9
10
11
Default: True
12
13
14
15
16
17
138 Chapter 4: Data Packet Component
1
1
EndCond
property
Default: []
Result
[]
[EcString]
[EcPacketSize]
Note: C++Builder uses a more difficult implementation of sets than Delphi does, use the
following syntax to set the EndCond property:
6
7
8
9
10
11
...
ApdDataPacket1->EndCond.Clear();
ApdDataPacket1->EndCond << ecString;
...
12
13
14
15
16
17
TApdDataPacket Component 139
1
1
EndString
property
If EndCond contains ecString, the packet stops collecting data when the string specified by
EndString is received.
See the StartString property on page 143 for information about specifying characters and
using fixed-length wildcards in the string.
See also: EndCond, StartString
5
6
IgnoreCase
property
Default: True
7
8
9
10
11
12
Default: True
! Determines whether the strings that define a packet are made available to the event handler.
For example, assume that StartString is Async, EndString is al, and the string Async
Professional arrives at the port. If IncludeStrings is True, the packet will contain Async
Professional. If IncludeStrings is False, the packet will contain Profession.
See also: EndString, StartString
13
14
15
16
17
140 Chapter 4: Data Packet Component
1
1
property
OnPacket
event
TPacketNotifyEvent = procedure(
Sender : TObject; Data : pointer; Size : Integer) of object;
! Defines an event handler that is called when a complete data packet is available.
Data is a pointer to the actual collected data. Size is the length of the collected data. The data
at Data is only valid for the duration of this event. Since Data is temporary, you can move the
collected data into your own buffer for storage or further processing outside of this event.
The following snippet demonstrates one technique of doing this:
var
Buffer: array[0..255] of byte;
procedure TForm1.ApdDataPacket1Packet(
Sender: TObject; Data: Pointer; Size: Integer);
begin
Move(Data^, Buffer[0], Size);
end;
7
8
OnTimeout
9
10
event
11
! Defines an event handler that is called when a timeout occurs during receipt of a packet.
12
The OnTimeout event is generated when a packet is in data collection mode but hasnt
completed within the number of ticks specified by TimeOut. By default, packets are disabled
when they time out, but they can be re-enabled from within the event handler if desired.
13
The data collected up to the point of the timeout is available through the GetCollectedString
and GetCollectedData methods.
14
The timeout timer does not start until the start condition has been met. If StartCond =
scString, the timer starts once the string defined by StartString has been received. If
StartCond = scAnyData, the timer starts once the data packet has been enabled. If you need
to start the timer once the packet starts actually collecting data, set the StartCond to scString
and StartString to the wildcard char (?).
15
16
17
1
1
OnStringPacket
event
2
3
4
TStringPacketNotifyEvent = procedure(
Sender : TObject; Data : string) of object;
! Defines an event handler that is called when a complete data packet is available.
Data is the actual data in the packet. The data packet is only available for the duration of
the event.
Note that a null character (#0) in the collected data may terminate the Data string
prematurely. This is due to the way that Delphi and C++Builder implement huge strings. If
you are expecting null characters in the collected data, use the OnPacket event instead.
7
8
property
Default: 0
If EndCond contains ecCharCount, PacketSize determines the size of the data packet.
If IncludeStrings is True, PacketSize will not compensate for the length of the start and end
strings. For example, assume that the StartString is Async, PacketSize is 13 and the string
Async Professional arrives at the port. If IncludeStrings is True, the collected data will
contain Async Profess (13 characters); if IncludeStrings is False, the collected data will
contain Professional.
See also: EndCond
13
14
15
16
17
142 Chapter 4: Data Packet Component
1
1
StartCond
property
Default: scString
Value
Result
scString
scAnyData
property
7
8
9
10
11
12
13
14
15
16
17
TApdDataPacket Component 143
1
1
1
2
3
4
5
6
7
8
property
! Determines how long a data packet waits for completion of a data stream.
9
10
11
12
13
If TimeOut is non-zero, it determines how long (in ticks) a data packet is allowed to wait for
completion after it has started collecting data. After TimeOut ticks, the data packet
relinquishes ownership of the data stream. If TimeOut is zero, the data packet holds
ownership of the data stream until the EndString is received.
The timeout timer does not start until the start condition has been met. If StartCond =
scString, the timer starts once the string defined by StartString has been received. If
StartCond = scAnyData, the timer starts once the data packet has been enabled. If you need
to start the timer once the packet starts actually collecting data, set the StartCond to scString
and StartString to the wildcard char (?).
See Data ownership on page 134 for more information.
See also: EndString, OnTimeOut
14
15
16
17
144 Chapter 4: Data Packet Component
1
1
1
2
This chapter describes the TApdScript component, which contains properties and methods
for automating basic communications sessions.
A script is a list or file containing communications commands. Script languages are often
provided by general-purpose communications programs to automate standard operations
like logging on and off, file upload, and file download. The scripting support in TApdScript
provides similar, though much simpler, script facilities for Async Professional applications.
4
5
6
7
8
9
10
11
12
13
14
15
16
17
145
1
1
TApdScript Component
2
3
5
6
7
8
9
10
11
12
13
In this line of code, <command> describes the action to perform, <data1> and <data2> are
optional arguments, and <comment> is an optional comment. The format of the arguments
vary among commands. The various components of each line must be separated by at least
one space or a comma. Additional spaces are permitted, but ignored. Commands are not
case-sensitive.
The following is a list of supported commands followed by brief descriptions and
discussions of the relationships between various commands:
:<label>
GOTO <label>
DISPLAY 'XX XX'
;<comment>
SENDBREAK <duration in ms>
INITPORT <1..99>
DELAY <duration in ms>
IF CONNECTED <label>
SET <option> <data>
DONEPORT
UPLOAD <protocol>
SEND 'XXXXXX'
DOWNLOAD <protocol>
CHDIR <pathname>
DELETE <filemask>
RUN <command> <wait>
EXIT <exitcode>
IF SUCCESS <label>
WAIT 'XXXX' <timeout in ms>
IF TIMEOUT <label>
IF FAIL <label>
IF 1,2,3...127
WAITMULT 'XXX|YYY|ZZZ' <timeout in ms>
:<label>
14
15
A point in the script file that can be jumped to via a GOTO or IF instruction. A label name
can be any type of string without embedded spaces. For example :TopOfLoop,
:TOP_OF_LOOP are both acceptable; :top of loop is not.
;<comment>
16
Any line that starts with a semicolon is considered a comment. Blank lines are also
considered comments and may be freely added for readability.
17
146 Chapter 5: Script Component
1
1
INITPORT <Com1..Com99>
Opens the specified port. Only one port at a time may be opened. This number directly
correlates with the ComNumber property of the TApdComPort component.
DONEPORT
Closes a port previously opened with INITPORT.
1
2
3
SEND 'XXXXXX'
Transmits the string XXXXXX. Control characters may transmitted by preceding a
character with ^. For example, a control C character is represented by ^C. Youll use this
feature most often when sending carriage returns. For example, SEND myname^M might
be an appropriate response to a logon prompt where you would normally type your name
and press Enter.
Note: Unlike Object Pascal, control characters must be inside the quote marks, if quote
marks are necessary.
If the string does not contain any embedded blanks the beginning and ending quotes can be
omitted. The quotes are required if the string has embedded blanks. For example:
SEND ABC
4
5
6
7
8
sends ABC
10
11
12
13
14
15
IF SUCCESS/TIMEOUT/FAIL <label>
Tests the condition set by the last command and, if the tested condition is True, script
execution jumps to <label>. If the condition is not True then execution continues with the
next statement.
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
GOTO <label>
Unconditionally jumps to <label>.
DISPLAY 'Just did something'
Generates a call to the TApdScript components OnScriptDisplay event handler. If the
DisplayToTerminal property is True and a terminal component exists on the form, then the
string is also displayed to the terminal. This can be used to monitor the progress of the script
and to aid in debugging.
17
148 Chapter 5: Script Component
1
1
Delays for <duration in ms> milliseconds. The script doesnt yield during delays so you
should keep the delays as short as possible.
DATABITS <5,6,7,8>
FLOW <RTS/CTS,XON/XOFF,NONE>
PARITY <NONE,ODD,EVEN,MARK,SPACE>
STOPBITS <1,2>
6
7
8
9
10
11
12
13
14
15
16
17
1
1
DIRECTORY <pathname>
FILEMASK <filemask>
FILENAME <filename>
WRITEFAIL
WRITERENAME
WRITEANYWAY
ZWRITECLOBBER
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
150 Chapter 5: Script Component
1
1
ZWRITENEWER
ZSKIPNOFILE <True/False>
1
Sets the ZmodemFileOption property
to zfWriteProtect option. This means
that if an incoming file already
exists the incoming file is skipped.
6
7
UPLOAD <protocol>
Starts transmitting files using <protocol>. <protocol> must be one of the following:
XMODEM, XMODEM1K, XMODEM1KG, YMODEM, YMODEMG, ZMODEM or
KERMIT. All files matching the mask previously specified by SET FILEMASK are
transmitted.
8
9
DOWNLOAD <protocol>
Starts receiving files using <protocol>. <protocol> must be one of the following:
XMODEM, XMODEM1K, XMODEM1KG, YMODEM, YMODEMG, ZMODEM or
KERMIT. When using any of the Xmodem protocols, you must call SET FILENAME before
DOWNLOAD to specify the name of the received file.
10
CHDIR <pathname>
12
Changes the current directory to the one specified by <pathname>. If the directory does not
exist, the FAIL condition is set.
11
13
DELETE <filemask>
Deletes all files matching <filemask>. If no path is specified the current directory is used.
14
15
16
17
1
1
Executes the specified command, batch file or program. <wait> can be True or False and
determines whether the script waits for the command to complete its execution. <wait> is
True by default.
Following is an example script showing how these commands might be used to log on to a
host or terminal server:
4
5
6
7
SET RETRY 10
:Again
SEND ^C
WAIT 'READY' 182
IF SUCCESS Logon
IF TIMEOUT Again
IF FAIL, Done
:Logon
SEND 'Name, password^M'
...
:Done
SEND 'Bye^M'
;Try 10 times
;Send an attention character
;Wait 10 seconds for response
;Got prompt, continue with logon
;Try again if we timed out
;Give up after 10 tries
;Send name and password
EXIT <exitcode>
This will terminate the script and return the exit code as the Condition parameter in the
OnScriptFinish event. If the exitcode is not specified, a Condition of SUCCESS will be
passed to the OnScriptFinish event.
10
11
12
13
User functions and variables are designed to provide a means by which your scripts can
interact with the host application. When a user function or user variable are encountered,
the script will fire events to either handle the event or to supply the value for the user
variable.
User functions
14
User functions are indicated by a & as the first character in the name of the function. User
functions can take a single optional parameter.
15
16
17
1
1
Following are examples of calls to user functions. In all cases, the OnScriptUserFunction
event will be called with a Command parameter of MYFUNCTION. In the first example,
the value of Parameter is empty. In the second and third examples, the value of Parameter is
the string Parameter and 1234 respectively:
&MyFunction
&MyFunction 'Parameter'
&MyFunction 1234
1
2
3
User variables
User variables are indicated by a $ as the first character in the name of the variable. User
variables can appear in any place where a parameter is expected and they can appear as the
parameter to a user function. In the latter case, the user variable will be evaluated before the
user function.
When a user variable is encountered in the script, it will generate the OnScriptUserVariable
event. The name of the user variable will be passed in the Variable parameter of the
OnScriptUserVariable event. The name of the variable will be exactly as it appears in the
script (including the leading $). You will need to specify the value of the variable in the
NewValue parameter of the event.
Following are examples of using user variables:
DISPLAY $MyVariable
&MyFunction $MyVariable
4
5
6
7
8
9
Executing scripts
10
A script is a list of commands in the format described in the previous section. The script can
be an external ASCII text file or can be contained within a TStringList component. Scripts
must be prepared with a call to PrepareScript before they can be executed. Preparing the
script translates (compiles) it into memory. Syntax errors cause the EApxScriptError
exception to be raised with one of the following error messages:
Not a valid script command. Line #
Bad format for first parameter. Line #
Bad format for second parameter. Line #
Label is referenced but never defined. Line #
Bad option in SET command. Line #
Error XXX while processing script. Line #
11
12
13
14
15
16
17
1
1
1
2
3
Scripts are always executed in the background in a fashion similar to file transfer protocols.
Scripts are started with a call to StartScript, which returns immediately. If no script
commands have been prepared (or can be prepared) StartScript raises the EApxScriptError
exception. If the script was started successfully it continues in the background until
completion (either successfully or due to an error). When the script is finished, it generates
the OnScriptFinish event.
Other components
4
5
6
7
8
9
10
11
12
Debugging scripts
14
A script file is really an interpreted program and TApdScript is the interpreter. Like any
program you write, script files may require a bit of debugging. Simple syntax errors will
always be detected and reported by PrepareScript. Logic errors, however, may require some
debugging effort on your part to find and correct.
15
TApdScript provides a variety of tools for debugging scripts. First, it provides three events
for tracking the progress of the script:
13
16
17
1
1
It also provides the OnScriptDisplay event, which is called in response to each DISPLAY
command in the script.
Finally, you can use the debug log available within the TApdComPort component to
examine the data sent and received during a script session.
Example
This example creates a very simple script file to send the ATI4 command to a modem and
wait for the OK response. Because this example includes a terminal window, the results of
the ATI4 command are displayed in that window.
Create a new project, add the following components, and set the property values as
indicated in Table 5.2.
Component
Property
Value
TApdComPort
ComNumber
<as required>
ScriptCommands
send ati4^m
TAdTerminal
TApdScript
wait ok 36
TButton
Name
Start
Double-click on the Start button and modify the generated method to look like this:
procedure TForm1.StartClick(Sender: TObject);
begin
ApxScript1.StartScript;
end;
10
11
This method starts the script. StartScript returns immediately while the script continues
running in the background. Note that PrepareScript was not called. StartScript calls
PrepareScript itself when either ScriptCommands contains commands or ScriptFile
contains a file name. If the script contains any syntax errors, StartScript will raise an
EApdScriptError exception.
12
13
14
15
16
17
1
1
1
2
3
4
5
6
Hierarchy
TComponent (VCL)
! TApdBaseComponent (AdMisc). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomScript (AdScript)
7
8
9
10
11
12
13
TApdScript (AdScript)
Properties
ComPort
Protocol
DisplayToTerminal
ScriptCommands
InProgress
ScriptFile
Methods
CancelScript
PrepareScript
StartScript
OnScriptCommandStart
OnScriptDisplay
OnScriptParseVariable
OnScriptCommandFinish
OnScriptFinish
OnScriptUserFunction
Events
14
15
16
17
156 Chapter 5: Script Component
1
1
Terminal
! Version
Reference Section
CancelScript
method
2
procedure CancelScript;
Once a script is started, it executes all commands in the background without any help or
interference from the foreground process. The only way to stop the script, short of letting it
run to completion, is to call CancelScript. CancelScript stops the script and removes any
resources (i.e., triggers, event handlers) the script may have installed. CancelScript does not
free any components (TApdComPort or TApdProtocol) that the script may have created.
Those components are re-used in subsequent calls to StartScript and are freed only when the
script component is destroyed.
ComPort
4
5
6
property
! The comport component used by the script to send and receive data.
When the script is created it assigns the first comport component it finds on the form to
ComPort. ComPort is also automatically filled in if a comport is created after the script
component. If ComPort is unassigned when StartScript is called, StartScript dynamically
creates a TApdComPort component and fills in ComPort.
DisplayToTerminal
property
9
10
11
! When True, the script DISPLAY commands display data to the terminal window.
Set this to True if the application has a terminal window and the terminal window should be
used to display the strings from the scripts DISPLAY commands. If the application doesnt
have a terminal window this property is ignored. If this property is set to False or the
application doesnt have a terminal window, the application must implement an
OnScriptDisplay event handler in order to see the contents of the scriptss DISPLAY
commands.
12
13
14
15
16
17
1
1
InProgress
Use this property to determine whether or not a script is executing in the background. A
typical use would be to prevent a user from starting a new script or any other
communications operation until the current script is finished.
OnScriptCommandFinish
6
7
8
9
10
11
12
13
14
15
16
17
158 Chapter 5: Script Component
1
1
event
OnScriptCommandStart
event
TScriptCommandEvent = procedure(
CP : TObject; Node : TApdScriptNode;
Condition : SmallInt) of object;
TApdScriptNode = class(TObject)
Command : TApdScriptCommand; Data : String; Option : TOption;
Timeout : Word; Condition : Word;
TApdScriptCommand = (
scNone, scComment, scLabel, scInitPort, scDonePort, scSend,
scWait, scWaitMulti, scIf, scDisplay, scGoto, scSendBreak,
scDelay, scSetOption, scUpload, scDownload, scChDir, scDelete,
scRun, scExit);
3
4
5
6
7
8
9
event
10
property OnScriptDisplay : TScriptDisplayEvent
TScriptDisplayEvent = procedure(
CP : TObject; const Msg : String) of object;
11
12
The script processor doesnt make any assumptions about how to display the contents of
DISPLAY commands. Instead, it generates an OnScriptDisplay event passing Msg, the string
to be displayed. The application can then display the string in whatever manner necessary.
One exception to this process occurs when the DisplayToTerminal property is True and the
script component finds a TAdTerminal window component on the form. In that case the
contents of the DISPLAY command are shown in the terminal window before
OnScriptDisplay is generated.
13
14
15
16
17
1
1
OnScriptFinish
event
2
3
4
5
6
TScriptFinishEvent = procedure(
CP : TObject; Condition : SmallInt) of object;
7
OnScriptParseVariable
TScriptParseVariableEvent = procedure(
CP : TObject; const Variable : String;
var NewValue : String) of object;
10
11
12
13
14
15
16
17
160 Chapter 5: Script Component
1
1
event
OnScriptUserFunction
event
TScriptUserFunctionEvent = procedure(
CP : TObject; const Command : String;
const Parameter : String) of object;
Refer to the section User functions and variables on page 152 for more information.
method
7
8
procedure PrepareScript;
! Prepares the script command list and checks for syntax errors.
Before a list or file of script commands can be processed, it must first be prepared. This is
similar in concept to compiling a program. Each script command is read, checked for syntax
errors, and written to an internal list of compiled commands. When StartScript is called, it is
this internal list of compiled commands that is executed.
When PrepareScript finds a syntax error it raises an EApxScriptError exception with one of
the following error messages and the offending line number:
9
10
11
12
13
14
15
16
17
TApdScript Component 161
1
1
Protocol
property
2
3
4
5
6
7
property
Note that ScriptCommands are used only when the ScriptFile property is empty. If the
ScriptFile contains a file name, then script commands are read from that file regardless of
the contents of ScriptCommands.
10
11
12
13
14
For convenience, at design time the script component loads the commands from ScriptFile
into ScriptCommands whenever a new ScriptFile property value is set. If the contents of
ScriptCommands are changed the script component automatically writes those changes to
ScriptFile, but only when the script component is destroyed or a new ScriptFile set. If the
contents of ScriptCommands is changed and the project is run without first closing, the
project the changes to ScriptCommands will be lost.
ScriptFile
property
When ScriptFile contains a file name PrepareScript and StartScript always read that file to
build/execute the script, ignoring the current contents ScriptCommands.
16
17
162 Chapter 5: Script Component
1
1
StartScript
method
procedure StartScript;
StartScript checks the internal table of compiled commands. If that table is empty, it calls
PrepareScript to compile the commands in the file specified by ScriptFile. If ScriptFile is
empty, PrepareScript tries to compile the list of commands specified by ScriptCommands. If
that list is also empty, the EApdScriptError exception is raised.
If StartScript finds or creates a list of compiled commands, it begins executing those
commands. It continues executing commands until it encounters a command requiring a
wait (WAIT, WAITMULTI, UPLOAD, DOWNLOAD). It then sets up appropriate triggers
and trigger handlers and exits back to the application. When the triggers occur, the script
engine regains control in the background and continues executing until the next wait
command, when this process is repeated.
Terminal
property
3
4
5
6
7
8
When the script component is created it searches the form for an existing terminal and uses
the first one it finds. If it doesnt find any, it uses the first terminal later dropped onto the
form. Unlike comport and protocol components, the script component never creates a
terminal component.
10
11
12
13
14
15
16
17
TApdScript Component 163
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
164 Chapter 5: Script Component
1
1
1
2
A state machine is simply a device or technique that receives input and acts upon that input
based on the current condition of the device or technique. Async Professional uses state
machines for a variety of tasks; such as managing protocol file transfers, sending and
receiving faxes, collecting data packets, and monitoring the progress of a connection
attempt.
3
4
State machines are one of the fundamental techniques used for asynchronous
communications, where a command is transmitted and the reply is received later in the
session. Consider the simple task of initializing a modem to detect Caller ID information
and answering a call. The first step (after opening the correct serial port) is to send a generic
initialization command (ATZ<CR>), then wait for the modem to return either a success
response (OK) or a failure response (ERROR). The next step is to send the AT
command to enable Caller ID detection and text responses (AT#CID=1<CR>) and wait
for either a success or failure response. Finally, the project waits for the modems ring
indicator (RING), answers the call (ATA<CR>) and waits for the connection response
(CONNECT). Each instance of a command and response can be thought of as a separate
state in a state machine, as Table 6.1 illustrates.
5
6
7
8
State
Output
Input
Next State
Send Init
"ATZ"<CR>
"OK"
Send CID
"ERROR"
Fail
"OK"
"ERROR"
Fail
Send CID
"AT#CID=1"<CR>
"RING"
"RING"
Answer
Answer
"ATA"<CR>
"CONNECT"
Connected
"NO CARRIER"
Fail
Fail
Connected
Continue the
session
10
11
12
13
14
15
16
17
165
1
1
1
2
3
A simple, two or three-state state machine is relatively painless to create. The state machine
is usually driven by TApdDataPacket components monitoring for success or fail conditions.
When TApdDataPackets OnStringPacket event is generated, the state machine progresses
according to the collected data. Once a state machine grows to twenty or thirty states, with
multiple conditions defining the state progression, the project code can get cumbersome,
difficult to maintain, and hard to visualize.
4
5
8
9
10
11
12
13
14
15
16
In order for the Async Professional state machine components to be useful, their design
philosophy should be understood. The TApdStateMachine component contains and
manages the TApdState components. The TApdState components own a TCollection
descendent that determines the conditions required to progress to another TApdState. Each
TApdState component can have either a single or multiple conditions. When the
TApdStateMachine activates a state, the TApdStateMachine creates a list containing
TApdDataPacket components configured according to the properties of each condition.
Once one of those conditions is met, the next state is activated and the TApdStateMachine
awaits further input to satisfy the new states conditions.
The TApdStateMachine is the only state machine component that interfaces with the
TApdComPort or TApdWinsockPort. The TApdState components merely define the
conditions that the TApdStateMachine monitors.
17
166 Chapter 6: State Machine Components
1
1
1
2
3
The multiple-condition capability of the TApdState component does not lend itself very well
to programmatic modification, or modification through the Object Inspector. The
TApdState component installs a state condition editor dialog accessed by right-clicking the
component and selecting the Edit condition... menu item. A dialog box is displayed, as
shown in Figure 6.1, which provides access to add, edit and delete conditions.
4
5
6
7
8
9
10
The grid displays the current values for the installed conditions. To add a new condition to
this TApdState component, click Add; to edit the selected condition click Edit; to delete the
selected condition click Delete. When the modifications are complete, click OK to update
the collection of conditions. To cancel any changes and revert to the original conditions,
click Cancel.
11
12
13
14
15
16
17
1
1
When a condition is added or edited, the Condition editor, shown in Figure 6.2, is displayed.
This dialog box permits editing the fields of the TApdStateCondition being added or edited.
2
3
4
5
6
7
8
9
Figure 6.2: TApdStateCondition property editor.
13
The controls are preinitialized with the current TApdStateCondition values when the
condition is being edited, and preinitialized with default values when the condition is being
added. Most of the controls are self-explanatory, with the exception of the Next state and
Color drop-down combo boxes. The drop-down list for Next state contains the names
of all TApdState components owned by the TApdStateMachine that owns the TApdState
being edited. The Color drop-down list contains the system colors and Delphi color
constants. Hex or RBG representations are not supported. Click OK to accept the changes or
click Cancel to cancel the changes. Note that the changes will not take effect until the
TApdState component editor is terminated.
14
10
11
12
15
16
17
For illustration, we will create a simple state machine that will initialize a modem, initialize
the modem for Caller ID detection, collect the Caller ID information, and answer an
incoming call. This process can be broken up into four states: initialization, Caller ID
initialization, waiting for the ring signals from the modem, and answering the call. As you
will see, the multiple condition capability of the TApdState, and some carefully planned
recursion, will let us wait for the rings and detect the Caller ID information in a single
TApdState.
1
1
Due to the number of properties that are available when defining the state conditions, only
the properties that will be changed will be mentioned, other properties can be left at their
default values.
Create a new project and drop a TApdComPort component and a TApdStateMachine
component onto the new form. Next, drop four TApdState components onto the
TApdStateMachine.
Select ApdState1, change the OutputOnActivate property to ATZ^M. Right-click the
component and select the Edit conditions... menu. Add a new condition with a StartString
of OK and set the NextState to ApdState2. This will tell the TApdState that we want to send
ATZ<CR> when activated and we will wait for an OK before ApdState2 is activated.
Select ApdState2, change the OutputOnActivate property to AT#CID=1^M. Invoke the
conditions property editor and add a new condition with a StartString to OK and the
NextState set to ApdState3. This will tell the ApdState2 that we want to send
AT#CID=1<CR> when the state is activated and wait for an OK.
Select ApdState3, and invoke the conditions property editor. In this state, we will wait for
two RING signals, and the three Caller ID tags. Invoke the conditions property editor and
add a new condition with StartString set to RING. Dont set the NextState yet; it will be set
programmatically so the two RINGs can be captured. Add another condition and set the
StartString to DATE:, EndString to ^M and NextState to ApdState3. Add two more
conditions identical to the last except for a StartString of NAME: and NMBR:. These
conditions will tell ApdState3 that we want to know when RING is received, and when the
Caller ID tags are received. Since we may or may not receive the Caller ID tags, and they may
be in a different order, their NextState properties will point to their own TApdState.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
We will stay in this state until we tell the state that we want to progress to the next state. We
will also want to record the Caller ID information for later processing. To do this, create the
OnStateFinish event handler for ApdState3 and enter the following:
procedure TForm1.ApdState3StateFinish(State: TApdCustomState;
Condition: TApdStateCondition; var NextState: TApdCustomState);
begin
{ decide what to do when we receive "RING"s }
if Condition.StartString = 'RING' then begin
{ it's our RING condition }
State.Tag := State.Tag + 1;
if State.Tag > 1 then
{we've seen at least 2 rings, progress to the next state}
NextState := ApdState4
else
{ we've seen less than 2 rings, wait for more }
NextState := ApdState3;
end else if Condition.StartString = 'DATE:' then
{ it's our Date CID tag }
CIDDate := ApdStateMachine1.DataString
else if Condition.StartString = 'NMBR:' then
{ it's our Number CID tag }
CIDNumber := ApdStateMachine1.DataString
else if Condition.StartString = 'NAME:' then
{ it's our Name CID tag }
CIDName := ApdStateMachine1.DataString;
end;
Select ApdState4 and change the OutputOnActivate property to ATA^M. Invoke the
conditions property editor, add a new condition and change the StartString to
CONNECT.
Next, select the ApdStateMachine1 component on the form, set the StartState property to
ApdState1 and the TerminalState property to ApdState4. Add an OnStateMachineFinish
event handler to provide notification when the state machine is complete and we are
connected. A simple ShowMessage(Connected) will suffice for our purposes here.
Finally, drop the obligatory TButton on the form and create the OnClick event handler. This
event is where we will start the state machine. Add the following code to the OnClick event
handler:
procedure TForm1.Button1Click(Sender: TObject);
begin
ApdStateMachine1.Start;
end;
17
170 Chapter 6: State Machine Components
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
Compile and run the project. Click the button to start the state machine. As the states are
activated they will be highlighted in yellow (change the TApdStateActiveColor property of
the TApdState component to change the default highlight color). The modem will first be
initialized with ATZ, after the OK is received the Caller ID initialization is sent. After OK
is received, ApdState3 will be highlighted waiting for incoming calls. When a call is detected
by the modem, ApdState3 will wait for two RINGs, collecting whatever Caller ID
information is available. After two RINGs, ATA is sent to the modem to answer the call
and we will wait for the CONNECT response from the modem.
14
15
16
17
1
1
TApdStateMachine Component
3
4
5
Hierarchy
TScrollingWinControl (VCL)
! TApdBaseScrollingWinControl (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomStateMachine (AdStMach)
TApdStateMachine (AdStMach)
Properties
8
9
10
11
12
ComPort
DataString
CurrentState
LastErrorCode
Data
StartState
DataSize
StateNames
Methods
Cancel
Events
OnStateChange
13
14
15
16
17
172 Chapter 6: State Machine Components
1
1
Start
OnStateMachineFinish
TerminalState
! Version
Reference Section
Cancel
method
2
procedure Cancel;
Call the Cancel method to cancel the TApdStateMachine. The current state will be
deactivated, and the OnStateMachineFinish event will be generated. All resources allocated
by the TApdStateMachine to manage the current state will be deallocated.
When the Cancel method is used to terminate the TApdStateMachine, the ErrorCode
parameter of the OnStateMachineFinish event will be ecCancelRequested.
ComPort
property
8
9
10
11
12
13
14
15
16
17
1
1
CurrentState
During the execution of a state machine, different states will be activated and deactivated
depending on the data that is received. CurrentState is the TApdCustomState component
that is currently active.
At run time, the current state will be displayed with a highlighted background.
Data
9
property DataSize : Integer
10
11
12
13
14
15
16
17
1
1
LastErrorCode
When a TApdState is deactivated, the condition whose data requirements were met defines
an ErrorCode value. ErrorCode is intended to provide a numerical result of the condition.
For example, if the TApdState conditions defined a log in sequence, and the failure
condition was met, ErrorCode could be set to TPS_LOGINFAIL (an Async Professional
predefined constant found in AdExcept.pas). This property can be used for status reporting,
or to provide a reason for a state machine failure. The TApdStateMachine ignores this value.
3
4
5
event
TApdStateMachineStateChangeEvent = procedure(
StateMachine : TApdCustomStateMachine;
FromState : TApdCustomState;
var ToState : TApdCustomState) of object;
9
10
11
12
13
14
15
16
17
TApdStateMachine Component 175
1
1
OnStateMachineFinish
event
2
3
4
5
6
7
8
TApdStateMachineFinishEvent = procedure(
StateMachine : TApdCustomStateMachine;
ErrorCode : Integer) of object;
! Defines an event handler that is called when the state machine terminates.
When the TApdCustomState machine terminates, this event is generated to provide
notification of the termination. The TApdCustomStateMachine can terminate due to the
Cancel method, upon activation of the TerminalState TApdState, or when a condition is met
and the NextState property is nil or invalid.
StateMachine is the TApdCustomStateMachine that generated the event. ErrorCode is an
integer defining the reason for the termination. If the TApdCustomStateMachine was
terminated due to the Cancel method, ErrorCode will be ecCancelRequested. For all other
reasons, ErrorCode will be the value assigned to the ErrorCode property of the condition
whose data match parameters were met.
See also: Cancel, LastErrorCode
Start
9
10
11
method
procedure Start;
12
StartState
13
14
15
16
17
176 Chapter 6: State Machine Components
1
1
property
StateNames
! Provides the names of all TApdState components associated with the state machine.
The StateNames property is primarily for internal use, to provide the names of all TApdState
components that are associated with the TApdStateMachine. The Strings value is the Name
of the TApdState component.
TerminalState
property
6
7
8
9
10
11
12
13
14
15
16
17
TApdStateMachine Component 177
1
1
TApdState Component
The TApdState component defines the conditions for which the state machine is monitoring
at a given time during execution of the state machine. The TApdState component does not
interact with the port, it simply contains the data requirements and state progression
elements of the state it is representing.
3
4
5
6
7
8
9
10
11
12
13
The TApdState component maintains a collection of state conditions, which means that a
single TApdState component can define several different conditions at one time. For
example, at the beginning of a ZModem file transfer, the transmitter can begin the transfer
by sending rz<CR>, or a ZInit block (**[18]B00000000000000[0D]??). This can be
represented in a single TApdState component by adding two conditions, with their
NextState properties pointing to the TApdState that responds with the ZRInit packet.
The conditions are contained in the Conditions property of TApdState, which is a
TCollection descendent. This property is a collection of TApdStateCondition classes, which
are descendents of TCollectionItem. The TApdStateCondition defines data match strings
and timeouts similar to the TApdDataPacket, as well as a TApdStateConnectoid which
defines the visual connectoid between the states. The TApdStateConditions,
TApdStateCondition and TApdStateConnectoid classes do not lend themselves well to
programmatic manipulation, they are better suited to changing from the Object Inspector
and property editors.
TApdStateCondition
The TApdState component maintains TApdStateConditions, which define the conditions to
satisfy the state. TApdStateCondition is a TCollectionItem descendent, and has the
properties shown in Table 6.2.
Table 6.2: TApdStateConditions
Name
Type
Description
StartString
String
EndString
String
IgnoreCase
Boolean
PacketSize
Integer
14
15
16
17
178 Chapter 6: State Machine Components
1
1
Name
Type
Description
ErrorCode
Integer
NextState
TApdCustomState
Connectoid
TApdStateConnectoid
StartString, EndString, IgnoreCase and PacketSize are very similar to the TApdDataPacket
properties of the same name. The interface is simplified somewhat with the omission of the
StartCond and EndCond properties. If StartString is an empty string the data collection
mechanism begins immediately once the state is activated. If StartString is not an empty
string the data collection mechanism begins when the StartString has been received. If
PacketSize is 0 the size of the collected data is ignored. If PacketSize is greater than 0 then
condition will be satisfied when PacketSize characters have been received. If EndString is an
empty string the condition is satisfied if either the StartString has been received or
PacketSize characters have been received. If EndString is not an empty string the condition
is satisfied when the EndString has been received after the data collection mechanism
begins.
4
5
6
7
8
9
Hierarchy
10
TGraphicContro l (VCL)
! TApdBaseGraphicControl (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
11
TApdCustomState (AdStMach)
TApdState (AdStMach)
12
13
14
15
16
17
TApdState Component 179
1
1
1
2
3
4
5
Properties
Active
Glyph
ActiveColor
GlyphCells
Conditions
InactiveColor
Methods
Terminate
Events
OnStateActivate
6
7
8
9
10
11
12
13
14
15
16
17
180 Chapter 6: State Machine Components
1
1
OnStateFinish
OutputOnActivate
! Version
Reference Section
Active
1
read-only, run-time property
2
property Active : Boolean
Default: False
5
6
7
8
property
10
Default: clYellow
11
12
13
14
15
16
17
TApdState Component 181
1
1
Conditions
property
2
3
4
5
6
TApdStateConditions = class(TCollection)
public
function Add : TApdStateCondition;
property Items[Index: Integer] : TApdStateCondition;
end;
7
8
9
10
The Glyph can contain multiple cells to display a different image for each stage of the
TApdState component. The GlyphCells property determines the number of cells contained
in Glyph. See GlyphCells for a more detailed description.
11
12
13
14
15
16
17
182 Chapter 6: State Machine Components
1
1
property
GlyphCells
property
Default: 1
0,1
3
4
5
6
For example, if Glyph contained a single cell that should be displayed for the duration of the
state machine, GlyphCells can be either 0 or 1. To display one image when the Active
property is False and another image when Active is True, GlyphCells should be 2 and the
Glyph should contain two images with the same dimensions placed side by side.
7
8
9
When the Glyph cell is rendered, the Caption property will be displayed above the image.
The Active, ActiveColor and InactiveColor properties determine the background color
behind the Caption.
10
11
InactiveColor
property
12
13
Default: clWhite
! Determines the color of the component when the state is not active.
When the TApdState is active, it will be rendered with a background color determined by
the ActiveColor property. When the state is inactive it will be rendered with a background
color determined by the InactiveColor property. If the Glyph property is assigned, that
image will be rendered instead with a background determined in part by GlyphCells.
14
15
16
17
TApdState Component 183
1
1
OnStateActivate
event
2
3
4
5
6
TApdStateNotifyEvent = procedure(
State : TApdCustomState) of object;
7
OnStateFinish
TApdStateFinishEvent = procedure(
State : TApdCustomState; Condition : TApdStateCondition;
var NextState : TApdCustomState) of object;
10
11
12
13
14
! Defines an event that is generated when the states conditions are satisfied.
OnStateFinish provides notification when a TApdStates conditions have been met. This
event is generated immediately before this state is deactivated and the Conditions NextState
is activated.
State is the TApdState component that generated the event. Condition is the
TApdStateCondition whose data match conditions were satisfied. NextState is the TApdState
component that will be activated next. NextState can be changed during this event to
provide a mechanism to select the next state based on collected data or other factors. If
NextState is nil the TApdStateMachine will terminate the state machine.
See also: Active, OnStateActivate
15
16
17
184 Chapter 6: State Machine Components
1
1
event
OutputOnActivate
property
4
5
6
7
8
9
method
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
186 Chapter 6: State Machine Components
1
1
1
2
TApdStatusLight is a simple component that displays two bitmaps, or two different colors,
depending on whether the light is lit or unlit. The components Lit property determines
which of the two states is displayed, and its Glyph property determines whether bitmaps or
solid colors are used. This component works hand-in-hand with the TApdSLController
component.
7
8
9
10
11
12
13
14
15
16
17
187
1
1
TApdStatusLight Component
TApdStatusLight is a simple component that displays two bitmaps, or two different colors,
depending on whether the light is lit or unlit. The components Lit property determines
which of the two states is displayed, and its Glyph property determines whether bitmaps or
solid colors are used.
3
4
5
6
This component works hand-in-hand with the TApdSLController component (see page
191). TApdSLController reacts to changes in serial port status and changes the Lit property
of various TApdStatusLight components to reflect the status of the port.
Hierarchy
TGraphicControl (VCL)
TApdCustomStatusLight (AdStatLt)
7
8
9
TApdStatusLight (AdStatLt)
Properties
Glyph
LitColor
Lit
NotLitColor
10
11
12
13
14
15
16
17
188 Chapter 7: Status Light Components
1
1
Reference Section
Glyph
1
property
2
property Glyph : TBitmap
If the Glyph property is not assigned, a lit status light is drawn as a solid red square and an
unlit one as a green square. Each square has shadowed edges to give it a three dimensional
appearance.
Glyph can be used to display custom bitmaps instead. The Glyph bitmap is actually two
bitmaps in one. It should be twice as wide as the components Width property. The bitmap
displayed when the status light is lit is Width pixels wide starting at the left edge of the
bitmap. The bitmap displayed when the status light is not lit is Width pixels wide starting
Width pixels from the left edge of the bitmap.
Lit
property
6
7
8
Default: False
property
10
11
12
Default: clRed
13
14
15
16
17
1
1
NotLitColor
property
Default: clGreen
If the components Glyph property is not set to a valid bitmap, the status light is drawn as a
slightly raised colored square. NotLitColor is the color in which that square is drawn when
the light is not lit.
5
6
7
8
9
10
11
12
13
14
15
16
17
190 Chapter 7: Status Light Components
1
1
TApdSLController Component
TApdSLController is capable of monitoring the ports line signals (DCD, DTR, CTS, and
RI), line breaks and errors, and whether data is currently being received or transmitted.
3
4
6
7
Table 7.1 provides a list of all Lights sub-properties and the port condition they monitor.
Sub-property
Line condition
BREAKLight
CTSLight
DCDLight
DSRLight
ERRORLight
RINGLight
RXDLight
TXDLight
10
11
12
13
14
Using a TApdSLController
To use a TApdSLController, first create a TApdStatusLight component for each line
condition you want the controller to monitor. Next, drop a TApdSLController component
on the form and link it to the TApdComPort component you wish to monitor. Next, link the
controllers light properties to the status light components. Set the controllers Monitoring
property to True at run time when you want to start monitoring.
15
16
17
1
1
Figure 7.1 shows the Object Inspector for a properly created TApdSLController component
that can be used for monitoring the CTS, DCD, and DSR line signals.
2
3
4
5
6
7
8
9
Figure 7.1: Viewing the Object Inspector of a properly created TApdSLController component.
10
When the CTS signal changes, the component named CTSMonitor is changed accordingly.
Similarly, the component named DSRMonitor changes when the DSR signal changes and
the DCDMonitor component changes when the DCD signal changes.
11
Hierarchy
12
TComponent (VCL)
TApdCustomSLController (AdStatLt)
13
14
15
TApdSLController (AdStatLt)
Properties
BreakOffTimeout
Lights
RXDOffTimeout
ComPort
Monitoring
TXDOffTimeout
ErrorOffTimeout
RingOffTimeout
16
17
192 Chapter 7: Status Light Components
1
1
Reference Section
BreakOffTimeout
1
property
2
property BreakOffTimeout : LongInt
Default: 36
Determines the number of ticks the BREAKLight remains lit after a line break is detected.
ComPort
property
property
6
7
8
Default: 36
! Determines the number of ticks the ERRORLight remains lit after a line error is detected.
Lights
property
9
10
11
12
13
14
15
16
17
TApdSLController Component 193
1
1
Monitoring
run-time property
2
3
4
5
RingOffTimeout
property
Default: 8
6
7
! Determines the number of ticks the RINGLight remains lit after a ring is detected.
RXDOffTimeout
property
8
9
Default: 1
! Determines the number of ticks the RXDLight remains lit after a character is received.
TXDOffTimeout
10
11
Default: 1
! Determines the number of ticks the TXDLight remains lit after a character is transmitted.
12
13
14
15
16
17
194 Chapter 7: Status Light Components
1
1
property
1
2
Traditionally, a terminal is a piece of hardware with a screen and keyboard that provides a
method to display information from a host computer and to enter information into the same
computer. Today, more often than not, terminals are personal computers that run a program
that emulates the original terminal; it interprets the same data in the same fashion and
displays it in the same way. Similarly, it emulates the original keyboard and sends the same
kind of information back to the host computer in the same format.
3
4
The data presented by the host computer takes one of two forms. The first form is intended
for display only. The terminal will just send the stream of data directly to the screen without
trying to interpret it in any fashion. What you see is what is sent. This is known as teletype
mode (abbreviated as TTY).
5
6
The other form of data sent to a terminal consists of two types, intermixed: displayable data
and embedded terminal control sequences. The Terminal control sequences cause the
terminal to move the cursor around the screen, to block off certain parts of the display from
being altered, to delete text from areas of the screen, to scroll the display, to switch character
sets, and so on. The terminal has to monitor the data being sent by the host computer, be
able to identify the terminal control sequences in the stream, and then extract and act on
them. All other data would be sent to the screen as usual. We usually refer to this mode as the
terminal emulation mode.
7
8
9
All emulation means is that the PC is pretending to be the terminal in such a fashion that the
host computer is not aware that there is no real terminal present, just a clever program.
Ideally, the PC program emulates the terminal so well that the user cannot tell the difference
between the programs window and the original display. What you see is what was intended.
Unfortunately, the same cannot be said of the keyboard; terminal keyboards generally have
extra keys not available on a PC keyboard, and so the emulation program has to map
available PC keystrokes to the original terminal keyboard keys, and obviously the user has to
be aware of these mappings.
10
11
12
13
There are a variety of standards for terminal control sequences from such companies as
IBM, Digital Corporation (DEC), Wyse, and so on. One of the most widely known is the
DEC VT100 standard, which helped form the basis for the ANSI standard. Async
Professional implements the full VT100 standard, including support for different character
sets, scrolling regions, and keyboard application modes. By definition, this is also a subset of
the ANSI standard. Also, since the vast majority of PCs running Windows have color
monitors, the Async Professional VT100 emulation also supports the terminal control
sequences needed to display text in color.
14
15
16
17
195
1
1
Async Professional provides terminal emulation capabilities with its terminal component,
TAdTerminal and its emulators, all descended from TAdTerminalEmulator. These
components have been designed with two goals in mind: first, to be usable with the
minimum of effort on your part; and, second, to be flexible so that you can extend them to
work with other terminal types.
3
4
5
6
7
8
9
10
11
The former goal is important to those programmers who know that having a terminal that is
compliant with the VT100 standard (or a subset of the ANSI standard) is all that is required
for their application. They do not want to worry about linking this kind of display emulation
with that kind of keyboard emulation to the terminal component, they would rather just
point the emulator at the terminal component and let the components do the rest.
Catering for the latter goal, extensibility, is more difficult. There are many facets to
emulating a terminal. You have to worry about how to store the data from the host; in other
words, the actual displayable characters, the character attributes, the colors (both
foreground and background), the character sets. You have to worry about interpreting the
terminal control sequences being sent by the host and acting upon them. These terminal
control sequences may erase parts of the display, insert extra lines, or scroll the text in
different ways. You have to track these changes in your data.
Once you have those kind of problems nailed down, you then have to consider the keyboard.
Ideally, you would like to emulate the original terminal keyboard completely, but this isnt
generally possible. Apart from the alphabetic part of the keyboard, terminal keyboards have
different keys. You must map some PC keys (maybe normal, Control or Alt shifted) onto
their terminal keyboard equivalents. You have to consider what control sequence the
terminal keyboard would send to the host when a given key was pressed.
12
13
14
15
16
17
196 Chapter 8: The Terminal Components
1
1
After all that, you have to actually draw the terminal display in a normal window on the
screen. With the terminal classes in Async Professional, the attempt has been made to
simplify this entire process (see Figure 8.1).
1
2
SERIAL
DEVICE
3
4
COMPORT
BUFFER
TERMINAL
EMULATOR
KEYBOARD
MAPPING
PARSER
CHARACTER
SET
MAPPING
8
9
10
Terminal buffer
First, there is the TAdTerminalBuffer class. This class provides a non-visual buffer
containing a representation of the data being displayed by the terminal window. The buffer
is organized in the same fashion as the terminal display: a matrix of data organized into rows
and columns. In fact, the buffer maintains a set of such matrices: one for the displayable
characters, one for the attributes (bold, underline, invisible, and so on), one for the color of
the text, one for the color of the background, and finally one for the character set identifiers.
There is a set of methods for performing the standard terminal operations: erasing or
deleting part of the display, inserting rows and characters, scrolling areas of the display,
changing the default colors and attributes, writing new characters to the screen, and so on.
The class also maintains a list of character positions and rectangles on the screen that need
repainting. This class does not of itself understand any terminal control sequences; its
functionality is driven by some controlling terminal emulation component. In writing a new
terminal emulation component, you would generally use this buffer class as is; the only time
you would create your own descendant would be if the terminal you are emulating requires
some transformation of the display not provided by the standard class.
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Terminal parser
Next, there is the TAdTerminalParser class. This class is designed to interpret terminal
control sequences. The TAdTerminalParser class is an ancestor class, it merely defines the
interface through which a parser should work. Async Professional provides a single
descendant, the TAdVT100Parser class, which provides parsing capabilities for the VT100
series of terminals. Studying the code for this class would provide hints on how to write a
specialized parser class descendant for another terminal.
Keyboard-mapping table
Next, there is the keyboard-mapping table. This class stores the information required to
map a PC keystroke (as reported by Windows) into the control sequence that has to be sent
to the terminals host computer. This process takes place in three distinct steps, the
information for each being stored in the same structure (actually, a hash table). First, the
virtual key code reported by Windows is looked up in the table. If found, the name of the
virtual key would be returned. This name, together with the state of the various shift keys
(including Ctrl and Alt), is then looked up in the same table. If found, it will return the name
of the terminal key to which the PC key maps. For example, with the standard VT100
mappings provided with Async Professional, the up arrow key on the PC keyboard, VK_UP,
is mapped to DEC_UP, the name for the up arrow on the VT100 keyboard. Finally, the
terminal key name is looked up in the same table in order to obtain the control sequence that
needs to be sent to the host computer.
This seemingly repetitive triple lookup process exists to enhance comprehension and
extensibility. Consider: the first and last lookups are fully determined by the Windows
operating system and the terminal definition. They should not be altered. Virtual key code
$26 is VK_UP, by definition, and the VT100 up arrow key will send either <Esc>[A or
<Esc>OA depending on the terminal mode, again by definition. Thus, you could specify
that virtual key code $26 will send either <Esc>[A or <Esc>OA, but it wouldnt help with
understanding the mapping later on; whereas a mapping of VK_UP to DEC_UP is
immediately understandable and is easily changed. For example, if you wanted to make F6
the same as the up arrow key, you could just add the mapping of VK_F6 to DEC_UP. You
dont have to manually look up the virtual key code for F6, nor the escape sequence
generated by the VT100 up arrow key to write the mapping.
For convenience, the keyboard-mapping table can be loaded in two ways. First, the
mappings can be read from a simply formatted text file. Second, the mappings can be stored
in a resource linked into your application, from which the class can easily load them. The
latter method has the advantage that no external files are required to define keyboard
mappings. To aid in the generation of the resource file, the class has a method by which a
binary file containing the mappings can be written. This binary file can then be compiled
into a resource and linked into your application.
1
1
Next there is the character set mapping table. This class stores the information required to
actually display a given character on the terminal display. This class simplifies the task of
creating one terminal that uses several different character sets for displaying text. For each
character set, there may be a different glyph for each character. The classic example is that of
the VT100 terminal. This terminal has several character sets, of which two are the most
commonly used: the USASCII character set and the special graphics character set. To take as
an example, the character m is displayed as a lower-case m in the USASCII character set,
but is displayed as a line draw lower left corner (the glyph that looks like an L) in the special
graphics character set.
The character set mapping table is a list of character ranges in character sets and the fonts
and glyphs that should be used to display them. To aid in the display of text on the terminal
keyboardand to make the process more efficientthe character set mapping table will
analyze a string to be displayed in a particular character set, and generate a script of font
changes and the strings to be displayed in those fonts.
For convenience, the character set mapping table can be loaded in two ways. First, the
mappings can be read from a simply formatted text file. Second, the mappings can be stored
in a resource linked into your application, from which the class can easily load them. The
latter method has the advantage that no external files are required to define keyboard
mappings. To aid in the generation of the resource file, the class has a method by which a
binary file containing the mappings can be written. This binary file can then be compiled
into a resource and linked into your application.
2
3
4
6
7
8
9
10
Terminal emulator
The final step in writing your own terminal is possibly the most intricate: writing a terminal
emulator component. This component will have its own buffer instance, it will have a parser
instance and it will use a keyboard-mapping table and a character set mapping table. The
emulator would write to a TAdTerminal window and would be passed incoming data and
keyboard data from that component. The sequence of events for displaying something on
the screen would go something like this:
1. Accept a character from the input data stream.
11
12
13
14
2. Pass the character to the parser. The parser would decide whether the character was
displayable or part of a control sequence (a command) and pass the result back.
3. If the parser indicated that the character was displayable, the component would pass
the character to the buffer (equivalent to writing it to the display).
15
16
17
1
1
1
2
3
4
5
4. If the parser indicated that the character was a command, the terminal component
would act on the command. This may be as simple as sending something back to the
server or as complex as scrolling the display. The latter operation would be passed to
the buffer to do.
5. Every now and then, the terminal component would get a paint message, at which
point it would have to interrogate the buffer to find the parts of the display that need
repainting, and draw them in its client area.
As far as the keyboard goes, the terminal component would convert the virtual key codes
into control sequences in the manner already described and send these sequences to the
server. For the majority of the keys on the keyboard, the letter keys, no translation is
required and the relevant character is sent as is.
6
7
8
9
10
11
12
13
14
15
16
17
200 Chapter 8: The Terminal Components
1
1
TAdTerminalBuffer Component
The TAdTerminalBuffer class defines a data structure for maintaining the data required for a
communications terminal display. Essentially, this consists of:
The character sets from which those character glyphs are drawn.
The color in which the character glyphs will be displayed.
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
assumes that a color is a 4-byte quantity.) The attributes are stored as a set of different
possibilities: bold, underlined, strikethrough, blinking, reverse or invisible.
A word is required here regarding character sets. The VT100 terminal was a 7 bit device. In
theory, characters could have ASCII values from 0 to 127; however, the first 32 characters in
this set were control characters rather than displayable characters. Hence, there were only 96
different characters that could be displayed. Since this was not sufficient, the VT100 had
other sets of 96 characters that could be switched in and out, the most distinctive being the
line-draw characters in the special graphics character set. To display a character at a
particular position on the screen the terminal had to know which character set to take the
displayed glyph from, and also the ASCII value of the character. (A glyph is the visual
representation of an ASCII value in a particular character set.) Thus, on a VT100, the ASCII
value 123 would be displayed as the left curly brace, {, if the standard character set was in
force, or the symbol for pi, , if the special graphics character set was in force.
Another point should to be made about the terminal buffer: it does not parse any data
stream for control sequences. This is the job of the emulator portion of a terminal
component. The emulator should scan the incoming data stream for control sequences (for
example, those beginning with <Esc>[), decode them, and then get the terminal buffer to
update itself according to the operation requested.
Apart from the data to be displayed, a terminal component requires two basic pieces of
information: Has the cursor moved? What needs to be redisplayed? The terminal buffer
maintains a cursor position variable: the row and column number where new characters are
to be written should they arrive. Various methods update the cursor position, the most
obvious ones being the cursor movement methods to move the cursor up, down, left or
right. Again, it should be stressed that there is no visual representation of a cursor in a
terminal buffer object: the cursor is just a pair of row and column values. It is up to the
terminal component displaying the data from the buffer to maintain and show a cursor, for
example, perhaps a blinking underscore or block. (By the way, this can get confusing: with
terminals the blinking point where editing takes place is called a cursor, whereas with
Windows programs, it is known as a caret, the cursor being the mouse pointer.) The
terminal buffer not only maintains a cursor position, it also interfaces a routine that returns
whether the cursor position has changed since the last time the routine was called.
If the terminal component is to have a chance of keeping up with fast data streams, it cannot
continually redisplay the entire terminal screen every now and then. It must have a way of
knowing what has changed on the terminal screen, so that it only needs to update that
particular section. For example, if a character was written to the terminal, the terminal
component needs to know how much of its window it needs to repaint. In the majority of
cases, thats a single character cell; the new character, in other words. In some cases, the
terminal data needs to be scrolled before the character can be written. In this case the
terminal display needs to repaint a lot more of the window to show the effect of writing the
character. The terminal buffer maintains an internal list of invalidated character cells (in
1
1
fact, as cell rectangles) and the terminal component can read these and use the information
to redisplay parts of its window.
The terminal buffer has two views of the data: the scrollback view and the display view. The
scrollback view shows a history of data that have scrolled off the top of the display view. The
display view is essentially the representation of the terminal screen itself. There are typically
more rows in the scrollback view than in the display view (otherwise there wouldnt be
anything to scroll back through). The number of columns in both the scrollback and display
views is however the same.
The user of the terminal buffer will refer to positions on the terminal screen as one-based
values. For example, on a 24 rows x 80 columns terminal, the rows are numbered from 1 to
24 and the columns from 1 to 80. This is different from the usual Windows way of looking at
things, where values are counted from 0 instead. The rows in the scrollback view are negative
numbers or zero. For example, the last row to be scrolled off the display view (i.e., the
terminal itself) will be numbered row 0, the next to last, row 1, and so on. If a 24 row
terminal screen is cleared or erased, the entire scrollback view is scrolled up with the
previous display, and the rows of this previous display would then be numbered 23 to 0.
The terminal buffer also supports the concept of a scrolling region. This is a region of the
terminal screen to which the cursor is restricted. Once a scrolling region is defined and
activated, all cursor movement is restricted to this area and characters can only be written to
this area. When a scrolling region is activated, row and column numbers are no longer
absolute values, counted from the top left character cell of the screen, but are now relative
values, counted from the top left character cell of the scrolling region. For example, suppose
a scrolling region is defined to be within rows 5 and 10 and it is activated. Moving the cursor
to row 1, column 1, results in it being moved to the home position of the scrolling region,
not the home position of the screen. In absolute terms, the cursor ends up at row 5, column
1 instead. The terminal buffer maintains a definition of a scrolling region and also a flag that
states whether the scrolling region is in force or not. If a new scrolling region is defined, the
activation flag is automatically set, in other words, the scrolling region becomes effective
immediately.
Generally, when a data stream is sent to a terminal, the sender does not send coloring or
attribute information with every single character that needs to be displayed. Instead, the
terminal is instructed to use a particular color or attribute from that point forward, until
another color or attribute is requested. Characters written to the terminal in between these
two instructions will automatically be in the requested color or have the requested attribute.
The terminal also has a reset state, with default colors and attributes. The terminal buffer
mimics this behavior by having both current values and default values for the colors,
attribute and character set. If the terminal is reset, the terminal buffer automatically sets the
current values equal to the default values.
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Hierarchy
TObject (VCL)
2
3
4
5
6
7
8
9
10
11
12
13
14
TAdTerminalBuffer (ADTrmBuf)
Properties
BackColor
DefForeColor
SVRowCount
Charset
ForeColor
UseAutoWrap
Col
OriginCol
UseNewLineMode
ColCount
OriginRow
UseScrollRegion
DefBackColor
Row
UseWideChars
DefCharset
RowCount
Methods
ClearAllHorzTabStops
EraseFromBOL
InsertLines
ClearAllVertTabStops
EraseLine
MoveCursorDown
ClearHorzTabStop
EraseScreen
MoveCursorLeft
ClearVertTabStop
EraseToEOL
MoveCursorRight
Create
EraseToEOW
MoveCursorUp
DeleteChars
GetCharAttrs
Reset
DeleteLines
GetDefCharAttrs
SetCharAttrs
DoBackHorzTab
GetInvalidRect
SetCursorPosition
DoBackspace
GetLineAttrPtr
SetDefCharAttrs
DoBackVertTab
GetLineBackColorPtr
SetHorzTabStop
DoCarriageReturn
GetLineCharPtr
SetScrollRegion
DoHorzTab
GetLineCharSetPtr
SetVertTabStop
DoLineFeed
GetLineForeColorPtr
WriteChar
DoVertTab
HasCursorMoved
WriteString
EraseChars
HasDisplayChanged
EraseFromBOW
InsertChars
15
16
17
204 Chapter 8: The Terminal Components
1
1
Reference Section
BackColor
1
property
2
property BackColor : TColor
Default: clBlack
property
6
7
Default: 0
9
10
11
method
procedure ClearAllHorzTabStops;
12
13
14
15
16
17
TAdTerminalBuffer Component 205
1
1
ClearAllVertTabStops
method
procedure ClearAllVertTabStops;
ClearHorzTabStop
method
procedure ClearHorzTabStop;
5
6
ClearVertTabStop
procedure ClearVertTabStop;
method
10
11
Col
property
The Col property refers to the cursor. Reading the Col property returns the column number
of the cursor, and setting it moves the cursor to that column in the current row.
13
The value used for the Col property is one-based; in other words, columns are counted from
1. If there are 80 columns across the terminal screen, the columns will be known as columns
1 to 80. If the column number used is out of the range of the screen or the current scrolling
region, it is forced silently into bounds.
14
15
If a scrolling region is activated, the values for Col will be relative to the home position of the
scrolling region, not the home position of the screen itself.
16
17
206 Chapter 8: The Terminal Components
1
1
ColCount
property
Default: 80
method
3
4
6
7
8
9
10
DefBackColor
11
property
12
Default: clBlack
13
If Reset is called, the current background color is set to the value of DefBackColor.
14
15
16
17
TAdTerminalBuffer Component 207
1
1
DefCharset
property
Default: 0
If Reset is called, the current character set is set to the value of DefCharset.
See also: Charset, Reset
DefForeColor
5
6
7
property
Default: clSilver
8
9
DeleteChars
method
The characters to the right of the deleted ones are moved over to take their place. The area
on the extreme right uncovered by this action is filled with space characters using the
current colors and attributes.
The DeleteChars method is limited to the current scrolling region.
12
13
DeleteLines
method
14
15
The lines underneath the lines being deleted are moved up to take their place. The area at the
bottom uncovered by this action is filled with space characters using the current colors and
attributes. Deleting aCount lines is equivalent to scrolling up aCount lines.
16
17
1
1
DoBackHorzTab
method
procedure DoBackHorzTab;
If there is no previous tab stop, the cursor is moved to the first column of the line. If it
already at this position, it is not moved.
method
procedure DoBackspace;
9
method
10
procedure DoBackVertTab;
11
12
13
method
14
procedure DoCarriageReturn;
15
16
17
TAdTerminalBuffer Component 209
1
1
DoHorzTab
method
procedure DoHorzTab;
2
3
4
5
method
procedure DoLineFeed;
6
7
8
9
10
11
12
DoVertTab
method
procedure DoVertTab;
If there is no next tab stop, the cursor is moved to the last row. If it already at this position, it
is not moved.
14
15
16
17
210 Chapter 8: The Terminal Components
1
1
EraseChars
method
The erasing operation is done by replacing aCount characters with space characters, using
the current colors and attributes. The EraseChars method will automatically wrap and
continue at the end of rows, but it will not cause a scroll if the count requested exceeds the
bottom row. The cursor position is included.
3
4
method
procedure EraseFromBOL;
! Erases characters from the beginning of the row to the current cursor position.
The erasing operation is done by replacing the characters with space characters, using the
current colors and attributes. The cursor position is included.
EraseFromBOW
method
9
procedure EraseFromBOW;
! Erases characters from the beginning of the screen to the current cursor position.
10
The erasing operation is done by replacing the characters with space characters, using the
current colors and attributes. The cursor position is included.
11
This method is not limited to the current scrolling region; it applies to the whole screen.
EraseLine
method
12
13
procedure EraseLine;
14
15
16
17
TAdTerminalBuffer Component 211
1
1
EraseScreen
method
procedure EraseScreen;
2
3
This method is not limited to the current scrolling region; it applies to the whole screen. The
screen is erased by scrolling the entire scrollback view by RowCount rows. This has the effect
of erasing the screen, but also saves the previous version of the screen in the scrollback area.
EraseToEOL
method
procedure EraseToEOL;
! Erases characters from the current cursor position to the end of the row.
The erasing operation is done by replacing the characters with space characters, using the
current colors and attributes. The cursor position is included.
method
9
procedure EraseToEOW;
10
11
! Erases characters from the current cursor position to the end of the screen.
The erasing operation is done by replacing the characters with space characters, using the
current colors and attributes. The cursor position is included.
This method is not limited to the current scrolling region; it applies to the whole screen.
12
13
ForeColor
property
Default: clSilver
14
15
16
17
212 Chapter 8: The Terminal Components
1
1
GetCharAttrs
method
If you wish to add a new attribute to the current set, write code like this:
var
Attrs : TAdTerminalCharAttrs;
begin
...
MyBuffer.GetCharAttrs(Attrs);
Attrs := Attrs + [tcaUnderline];
MyBuffer.SetCharAttrs(Attrs);
7
8
GetDefCharAttrs
method
10
11
12
13
14
15
16
17
TAdTerminalBuffer Component 213
1
1
GetInvalidRect
method
2
3
4
5
6
7
8
9
10
11
GetLineAttrPtr
method
13
This method is not limited to the current scrolling region; it applies to the whole screen.
Thus, the pointer that is returned points to the data for column 1 of the required row.
14
15
16
17
214 Chapter 8: The Terminal Components
1
1
GetLineBackColorPtr
method
3
4
method
This method is not limited to the current scrolling region; it applies to the whole screen.
Thus, the pointer that is returned points to the data for column 1 of the required row.
GetLineCharSetPtr
method
10
11
This method is not limited to the current scrolling region; it applies to the whole screen.
Thus, the pointer that is returned points to the data for column 1 of the required row.
12
GetLineForeColorPtr
method
13
14
15
16
17
1
1
HasCursorMoved
method
2
3
4
5
6
7
8
9
10
11
12
14
15
16
method
17
method
InsertLines
13
method
MoveCursorDown
method
The cursor is moved onto the next row at the same column position. If the aScroll parameter
is False and the cursor is currently on the bottom row, it is not moved. If the aScroll
parameter is True and the cursor is on the bottom row, the screen or scrolling region is
scrolled up one line and the cursor remains in the same position. The new line inserted at
the bottom is initialized to space characters, using the current colors and attributes.
3
4
method
6
7
8
9
10
11
12
method
13
14
The column number of the cursor is incremented, unless the cursor is at the last position
of the row.
If, in fact, the cursor is at the rows last position, the values for aWrap and aScroll come into
play. If aWrap is False, the cursor does not move. If aWrap is True, the cursor moves down
one row, and is positioned at the first column of that next row. If, furthermore, the cursor
was originally at the last column of the bottom row and aScroll was False, the cursor does
15
16
17
1
1
not move. If, on the other hand, aScroll was True, the screen or scrolling region is scrolled up
one row and the cursor then moved to the first column of the bottom row. The new row is
initialized to space characters, using the current colors and attributes.
4
5
6
7
method
8
9
OriginCol
read-only property
If the scrolling region is not in effect, OriginCol is 1, being the left-most column of the
screen. If the scrolling region is activated, OriginCol is the column number of the left-most
column of the scrolling region.
OriginCol is read-only. To set the scrolling region, call SetScrollRegion.
12
13
read-only property
14
15
If the scrolling region is not in effect, OriginRow is 1, being the top row of the screen. If the
scrolling region is activated, OriginRow is the row number of the first row of the scrolling
region.
16
17
218 Chapter 8: The Terminal Components
1
1
Reset
method
procedure Reset;
property
3
4
6
7
If a scrolling region is activated, the values for Row will be relative to the home position of
the scrolling region, not the home position of the screen itself.
RowCount
property
10
property RowCount : Integer
Default: 24
11
12
13
14
15
16
17
TAdTerminalBuffer Component 219
1
1
SetCharAttrs
method
The display attributes define the style of new text. The attributes are bold, underlined,
strikethrough, blink, reverse image (i.e., the text displayed in BackColor, the background in
ForeColor), and invisible.
If you wish to add a new attribute to the current set, write code like this:
6
7
8
9
var
Attrs : TAdTerminalCharAttrs;
begin
...
MyBuffer.GetCharAttrs(Attrs);
Attrs := Attrs + [tcaUnderline];
MyBuffer.SetCharAttrs(Attrs);
10
11
12
13
14
15
16
17
220 Chapter 8: The Terminal Components
1
1
method
SetDefCharAttrs
method
SetHorzTabStop
method
procedure SetHorzTabStop;
If a horizontal tab stop is already set for that column, this method has no effect.
method
10
11
A scrolling region is a range of lines (from aTopRow to aBottomRow) within which writes to
the screen and scrolling are restricted. This is often used for adding status lines that remain
visible on screen while other text in the Terminal is scrolled.
12
13
method
14
15
procedure SetVertTabStop;
16
17
1
1
SVRowCount
property
Default: 200
The SVRowCount property gets or sets the number of rows available in the scrollback
buffer. SVRowCount is being set, and the new value is less than RowCount, RowCount is
also set to the new value of SVRowCount.
See also: RowCount
5
6
UseAutoWrap
property
! Defines what happens when a character is written at the last column of a row
7
8
9
10
UseAutoWrap only has an effect if the cursor is at the last column of a row. If UseAutoWrap
is False, the character is written at the last column of the current row, and the cursor does
not move. If UseAutoWrap is True, the character is written at the last column of the current
row, and then the cursor is moved to the first column of the next row, scrolling if necessary.
(In fact, this last operation is coded as a call to MoveCursorRight with aWrap and aScroll
both True.)
See also: MoveCursorRight
UseNewLineMode
11
12
13
14
15
16
17
222 Chapter 8: The Terminal Components
1
1
property
UseScrollRegion
property
If UseScrollRegion is False, the scrolling region is inactive and writes of text and scrolling
apply to the whole screen. If UseScrollRegion is True, the scrolling region is in force and all
screen changes are limited to the scrolling region.
Calling SetScrollRegion automatically forces this property to True, the new scrolling is
brought into effect immediately.
3
4
6
property UseWideChars : Boolean
! Defines whether UNICODE characters are being stored by the terminal buffer.
The value of UseWideChars is set by a parameter to the Create constructor. In Delphi 1, this
value is always False; it is only an option for 32-bit programs.
method
9
10
11
12
method
13
14
15
16
17
1
1
The purpose of a terminal parser is to identify terminal control sequences in the stream of
data coming into the terminal (these control sequences are also more commonly known as
escape sequences) and return the command specified to the caller. The terminal parser is the
class that embodies the knowledge of the terminals escape sequences; if another terminal is
to be emulated then some of the first code to write is a new parser descendant to encapsulate
the knowledge about the new terminal to be supported.
3
4
5
6
7
8
9
10
To gain a better understanding of these operations, well look at them individually from a
high level.
11
12
1. The parser did not understand the character in the current context, and so it should
be ignored.
2. The character is a displayable character and should be shown on the terminal screen.
13
14
15
16
17
224 Chapter 8: The Terminal Components
1
1
The operation of clearing the parser should reset the parser into a state such that no
sequence is being built up, and hence no knowledge of previous characters is maintained.
(The Clear operation is a virtual method of the class, which should be overridden in
descendants.)
If the character processing method returns a value that signifies that a command has been
identified, the Command property will return the current unprocessed command. This
property is reset to a null command if a sequence is being built up.
1
2
3
The Arguments property is an array property returning the arguments for the current
command. If there is no current command, the values are all zero. Essentially, certain
control sequences will define arguments or parameters for the command being defined, for
example, the command to move the cursor left might have an argument that defines how
many positions to move, whether just the implied 1, or several.
The Sequence property returns the actual escape sequence that has just been parsed. If the
current command is null, this property returns the empty string. This enables you to look at
the sequence, maybe to parse it outside the parsers control, or to log it to a trace file.
<Esc> is the escape character (ASCII $27), [ is the left bracket, the Ps are ASCII characters
in the range of $30 to $3F, the Is are ASCII characters in the range of $20 to $2F, and the final
F is in the range of $40 to $7E. Because of this definition, if the parser does not recognize a
particular command, it can easily discard itthe end of the escape sequence is well defined.
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
With the VT100 terminal in ANSI mode, escape sequences either start with
<Esc>[,<Esc>#, <Esc>(, or <Esc>), or form a two character escape sequence <Esc>x
where x is the command identifier. The <Esc>[ sequences all follow the standard ANSI
format previously mentioned. The other three sequence types are three character sequences
with the final character identifying the command. Hence, the VT100 parser can know when
unknown escape sequences terminate.
With the VT100 parser in VT52 mode, all escape sequences are two character sequences of
the form <Esc>x with the x being the command identifier. The only exception is <Esc>Y
where the two characters following the Y also form part of the sequence (<Esc>Y is cursor
position and the two following characters encode the row and column numbers
respectively). Hence, the VT100 parser working in VT52 mode can know when unknown
sequences terminate.
The VT100 terminal also supports one-byte control characters, characters like tab, carriage
return, line feed and so on. The VT100 parser decodes these as well as escape sequences,
even when the control characters appear in the middle of escape sequences.
Table 8.1 defines the control characters and escape sequences understood by the VT100
parser. The individual characters in the escape sequence have been separated by spaces to
make the parameters stand out more. The values Pn, Ps, Pr, or Pc denote parameters,
meaning a numeric, switch, row or column value. Any one-byte control character not listed
here is ignored: it will not be acted on or displayed.
Table 8.1: VT100 parser control characters and escape sequences
10
11
12
13
14
15
16
Control
Sequence
TerminalMode
Description
ENQ ($05)
VT100/52
BEL ($07)
VT100/52
Sound bell.
BS ($08)
VT100/52
HT ($09)
VT100/52
LF ($0A)
VT100/52
VT ($0B)
VT100/52
Processed as LF.
FF ($0C)
VT100/52
Processed as LF.
CR ($0D)
VT100/52
SO ($0E)
VT100
SI ($0F)
VT100
CAN ($18)
VT100/52
SUB ($1A)
VT100/52
Esc # 3
VT100
17
226 Chapter 8: The Terminal Components
1
1
Table 8.1: VT100 parser control characters and escape sequences (continued)
Control
Sequence
TerminalMode
Description
Esc # 4
VT100
Esc # 5
VT100
Esc # 6
VT100
Esc # 8
VT100
Esc ( A
VT100
Set G0 to UK charset.
Esc ( B
VT100
Set G0 to US charset.
Esc ( 0
VT100
Esc ( 1
VT100
Esc ( 2
VT100
Esc ) A
VT100
Set G1 to UK charset.
Esc ) B
VT100
Set G1 to US charset.
Esc ) 0
VT100
Esc ) 1
VT100
Esc ) 2
VT100
Esc 7
VT100
Esc 8
VT100
Esc <
VT100
Esc =
VT100
Esc >
VT100
Esc D
VT100
Index.
Esc E
VT100
Next line.
Esc H
VT100
Esc M
VT100
Reverse Index.
Esc [ Pn @
VT100 enh
Esc [ Pn A
VT100
Cursor up.
Esc [ Pn B
VT100
Cursor down.
Esc [ Pn C
VT100
Cursor right.
Esc [ Pn D
VT100
Cursor left.
Esc [ Pr; Pc H
VT100
Cursor position.
Esc [ Ps J
VT100
Esc [ Ps K
VT100
Esc [ Pn L
VT100 enh
Insert lines.
Esc [ Pn M
VT100 enh
Delete lines.
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Table 8.1: VT100 parser control characters and escape sequences (continued)
Control
Sequence
TerminalMode
Description
Esc [ Pn P
VT100 enh
Esc [ Pn X
VT100 enh
Esc [ Ps c
VT100
Esc [ Pr; Pc f
VT100
Cursor position.
Esc [ Ps g
VT100
Esc [ Ps h
VT100
Set mode.
Esc [ Ps l
VT100
Reset mode.
VT100
Esc [ Ps n
VT100
VT100
Set LEDs.
Esc [ Pt; Pb r
VT100
Esc [ 2; Ps y
VT100
Esc c
VT100
Reset.
Esc A
VT52
Cursor up.
Esc B
VT52
Cursor down.
Esc C
VT52
Cursor right.
Esc D
VT52
Cursor left.
Esc F
VT52
Esc G
VT52
Esc H
VT52
Cursor to home.
Esc I
VT52
Esc J
VT52
Esc K
VT52
Esc Y
VT52
Esc Z
VT52
Identify.
Esc <
VT52
Esc =
VT52
Esc >
VT52
Note: Use the escape sequence <Esc>[2l to switch into VT52 mode.
17
228 Chapter 8: The Terminal Components
1
1
TAdTerminalParser Class
The TAdTerminalParser Class is the ancestor class that defines the functionality of a
terminal parser. A terminal parser is a class that knows how to identify and extract terminal
control sequences (also known as escape sequences) and convert them into commands and
arguments. The parser is not responsible for executing the commands; that task is left to the
terminal emulation component that uses the parser.
The methods defined by the TAdTerminalParser class are all virtual in order that they can be
overridden in descendant classes, but they are not defined as abstract. Instead, in this
ancestor class, they are all do nothing methods.
Hierarchy
TObject (VCL)
TAdTerminalParser (AdTrmPsr)
Properties
Argument
Command
ArgumentCount
Sequence
Methods
10
Clear
ProcessChar
Create
ProcessWideChar
11
12
13
14
15
16
17
TAdTerminalParser Class 229
1
1
Reference Section
Argument
2
property Argument[aInx : Integer] : Integer
3
4
5
6
7
8
9
read-only property
10
11
12
13
14
15
16
17
230 Chapter 8: The Terminal Components
1
1
Clear
method
procedure Clear;
By calling Clear, you will reset the parser to a state such that no sequence is being built up
and no command is pending.
Command
read-only property
3
4
6
7
8
9
10
method
11
12
13
15
14
16
17
TAdTerminalParser Class 231
1
1
ProcessChar
virtual method
ProcessChar is the main workhorse of the parser class. It is the method that takes a character
and decides whether that character forms part of a terminal control sequence or is just one
that must be displayed. ProcessChar must maintain the current state of the parser (in other
words, whether the parser is building up a terminal control sequence, has just completed a
sequence, etc.).
ProcessChar can return one of several values. pctNone means that the character passed in
was not understood by the parser. Either the character was a single-byte control character
(in other words, a non-displayable character less than the space character) that would be
ignored by the original terminal, or the character terminated an escape sequence, but that
escape sequence was not known by the parser. The caller of ProcessChar can safely ignore
the problem since there is no recovery action to take because the parser has been left in a
correct state. pctChar means that the input character should be displayed on the terminal.
pctPending means that the input character formed part of an escape sequence that is being
built up, character by character. There is nothing further to do at this point since the escape
sequence has not yet been completed.
The last possible result value is pctComplete. This value indicates that the parser has
captured a complete terminal control sequence. Furthermore it indicates that the parser has
identified the command defined by the escape sequence and has set the Command property.
It will have extracted all of the command arguments or parameters and set both the
Argument and ArgumentCount properties. Finally, it will make sure that the Sequence
property returns the entire escape sequence.
12
13
If ProcessChar is called for a parser that was created to expect wide characters, a parser
exception will be raised.
See also: Argument, ArgumentCount, Command, Create, ProcessWideChar, Sequence
14
15
16
17
232 Chapter 8: The Terminal Components
1
1
ProcessWideChar
method
3
4
read-only property
9
10
11
In this ancestor class, the Sequence property always returns the empty string.
12
13
14
15
16
17
TAdTerminalParser Class 233
1
1
TAdVT100Parser Class
Hierarchy
TObject (VCL)
! TAdTerminalParser (AdTrmPsr) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
TAdVT100Parser (AdTrmPsr)
Properties
! ArgumentCount
Methods
Argument
! Command
InVT52Mode
! Clear
ProcessChar
! Create
! ProcessWideChar
10
11
12
13
14
15
16
17
234 Chapter 8: The Terminal Components
1
1
! Sequence
Reference Section
Argument
1
read-only, array property
2
property Argument[aInx : Integer] : Integer
Please see TAdTerminalParser for a description of how the Argument property works.
Some VT100 escape sequences use default values for certain arguments. For example, the
Cursor Right sequence is <Esc>[C, but it is also possible to specify the number of character
positions to move. In our case the sequence would be <Esc>[2C for two positions. The
VT100 parser in TAdVT100Parser would create a single argument of 1 (the default) for the
first case, and a single argument of 2 (an explicit argument) for the second case. There is no
way to find out if the parser has created an implicit default argument or used an explicit
argument, unless you wish to parse the Sequence property yourself. In general, this would
not matter: the value of an argument is all you need to process the command properly.
In certain cases the parser will be unable to determine the value of the default argument
since it would depend on information it does not have. An example for this is the Set
Scrolling Region command. This command has two arguments: the top row and the bottom
row of the scrolling region. The defaults are the top row and the bottom row of the screen
itself, neither of which are known by the parser. If the parser is unable to work out what the
default value of an argument is, it will set the relevant element of the Argument array
property to 1, meaning default.
There is a set of VT100 escape sequences that use the ? character in the parameter part of
the sequence. An example is <Esc>[?3h to set the VT100 terminal into 132-column mode.
The parser in the TAdVT100Parser class parses this escape sequence as having two
arguments, the ? and the 3. Since the Argument property only returns integers, the ?
character must be replaced by a special integer value, in this case, 2. Hence, in our example,
the command would have two arguments: 2 and 3. (The reason for this slightly eccentric
behavior, versus just ignoring the ? character altogether, is that ? signifies a DEC extension
rather than just a straightforward ANSI escape sequence. The parser needs to return this
information as well.)
6
7
8
9
10
11
12
13
14
15
16
17
1
1
InVT52Mode
read-only property
2
3
4
5
6
7
8
9
10
11
method
12
13
14
15
16
The VT100 terminal (and the ANSI specification) has one peculiarity that is generally not
well implemented by terminal emulators. The VT100 terminal supports several one-byte
control characters: line feed ($10), carriage return ($13), horizontal tab ($09), and so on.
Like the VT100 terminal, the VT100 parser class recognizes these one-byte control
characters, and acts upon them, even in the middle of an escape sequence. For example,
<Esc><CR>7 (where <CR> is the carriage return character) will be interpreted as
<CR><Esc>7; the <CR> being acted upon immediately, rather than being ignored. For this
example, the result values returned by ProcessChar for the three characters would be:
pctPending for the <Esc>; pctComplete for the <CR> (and the Argument,
ArgumentCount, Command and Sequence properties would be set accordingly); and,
finally, pctComplete for the <Esc>7 sequence (again setting the Argument,
17
236 Chapter 8: The Terminal Components
1
1
The ANSI specification details the behavior if an <Esc> character appears in the middle of
an escape sequence: the second <Esc> cancels the original escape sequence and starts a new
one. So, for example, with <Esc[12<Esc>7, the second <Esc> character would cancel the
partial escape sequence that begins <Esc>[12 and start a new one.
Two one-byte control characters that have special significance are CAN ($18) and SUB
($1A). These cancel the current escape sequence (if one is being built up). If ProcessChar is
called with either of these characters, at any time, it will clear the VT100 parser and return
pctNone.
Although the ProcessChar method will successfully parse and decode the standard VT100
escape sequences, in general it will not carry out any of the decoded commands internally.
That job is left to the terminal component itself. However, there is an exception to the rule.
There are two escape sequences that affect the operation of the VT100 parser. The first is the
<Esc>[?2l sequence, which switches the terminal into VT52 mode. The second is the
<Esc>< sequence, which switches it back to ANSI mode. The importance of these two
modes is that the terminal recognizes different escape sequences in each of these modes and,
hence, the parser has to be able to know when to parse the ANSI sequences and when to
parse the VT52 sequences. For example, in ANSI mode the <Esc>D sequence is the same as
move the cursor one line down (the Index operation) whereas in VT52 mode it means
move the cursor one position left. If the parser did not recognize which state the terminal
was in, it may parse this sequence badly. Hence, the VT100 parser class maintains the
InVT52Mode property and this is set internally by the ProcessChar method to reflect the
current ANSI/VT52 mode on receipt of one of these two sequences.
See also: InVT52Mode
6
7
8
9
10
11
12
13
14
15
16
17
1
1
3
4
5
6
7
8
9
10
11
12
13
14
15
16
There are three parts to the keyboard mapping. The first part is merely for convenience: it is
a mapping of the keyboards virtual key codes to the virtual key names. This mapping is
standard and is provided with Microsofts documentation. An example of a single mapping
is to specify that the virtual key code $70 is the F1 key, which is usually known by the name
VK_F1 in Microsofts documentation.
The second part of the keyboard mapping is the definition of the character or control
sequence that is sent by the original keyboard to the host computer when a key is pressed.
For a VT100 terminal, for example, pressing the PF1 key will either send an <Esc>P or an
<Esc>OP sequence to the host, depending on the mode the terminal is in at the time. Again,
this mapping is standard and is provided as part of the terminal manufacturers
documentation.
Whereas the two mappings just described are fixed by standards, the last mapping is where
the creativity and individuality comes in. This set of mappings details which PC keystroke
gets mapped to which terminal keystroke. There are no standards for this (though some
mappings should be fairly obvious: for example, the up arrow key should be mapped to the
terminals up arrow key), and so you can customize to a large extent which keys perform
which action using this third mapping.
The TAdKeyboardMapping class is designed to be used by a terminal emulator. The
terminal component will trap the users keystroke and pass it onto the emulator. The
emulator will lookup the virtual key code in the keyboard mapping table and will retrieve
the virtual key name. It will then prefix this name with the names of the shift keys that are
active, and lookup this combination in the keyboard mapping class. If the lookup succeeds,
the keyboard mapping class returns the name of a terminal key and this, in turn, can be
looked up to find the character or control sequence that should be sent to the host computer.
If at any time a lookup fails, there is no special mapping for the keystroke and so the default
action takes over (for example, for an alphabetic key, the relevant character is sent to the
host computer).
Although it may seem excessive to have three lookups per keystroke to get to the final
sequence to send to the host, in reality the design it provides a balance between fast
conversion of keystrokes and ease of specification of the various mappings. The lookups are
performed using a hash table, which is considered the data structure of choice for this kind
of operation.
17
238 Chapter 8: The Terminal Components
1
1
The TAdKeyboardMapping class is convenient to use when you have to specify a large
number of mappings. There are two methods for loading a set of mappings: first from a
specially, yet simply, formatted text file, and, second, from a resource within the application.
Thus, it is possible to have a default mapping linked into the application, but also to be able
to provide a way of altering the mappings at run time. To help create the resource, the class
also has a method to write its current mapping set to a binary file, which can then be
compiled into a resource file. The following code shows this process:
var
KeyMap : TAdKeyboardMapping;
begin
KeyMap := TAdKeyboardMapping.Create;
try
KeyMap.LoadFromFile('ADKEYVT1.TXT');
KeyMap.StoreToBinFile('VT100.BIN');
finally
KeyMap.Free;
end;
end;
1
2
3
4
6
7
8
9
10
If you name the resource file VT100.RC, the resource compiler will create a file called
VT100.RES. Adding the resource to your application at that point is merely a case of adding
the following line to your project file and recompiling:
{$R VT100.RES}
Now you can call the LoadFromRes method of your TAdKeyboardMapping instance to load
this set of keyboard mappings.
11
12
13
14
15
16
17
1
1
Hierarchy
TObject (VCL)
2
3
TAdKeyboardMapping (ADTrmKey)
Properties
Count
Methods
5
Add
Get
LoadFromRes
Clear
LoadFromFile
StoreToBinFile
6
7
8
9
10
11
12
13
14
15
16
17
240 Chapter 8: The Terminal Components
1
1
Reference Section
Add
1
method
2
function Add(const aKey : TAdKeyString;
const aValue : TAdKeyString) : Boolean;
TAdKeyString = string[63];
The aKey string is the lookup value (the key string) and aValue is the string associated with
it. Add does not validate these two strings to be in any particular format, so it is possible to
fill the instance with nonsensical strings that would never be looked up.
If the key string and its value were successfully added, Add returns True. If the key string is
already present, Add will return False and leave the existing mapping as is.
Please see LoadFromFile for a discussion on how to define the key strings and their values.
6
7
method
procedure Clear;
10
11
12
13
14
15
16
17
1
1
Get
method
TAdKeyString = string[63];
aKey is the key string to lookup. If it was found, the return value will be the string with
which it is associated. If it was not found, the return value is the empty string. No exception
is raised if the key string was not found.
See also: Add
5
6
LoadFromFile
method
The file is a text file in a particular format. LoadFromFile will follow these rules when
reading the file.
9
10
11
12
13
14
The words in a detail line have some formatting associated with them. The emulator
imposes this formatting so that it can generate the correct key strings when the user presses
a key. The LoadFromFile method does not validate these formats in any way.
\e in a word means the Escape character
15
16
If you want to specify shift keys with virtual key names, use the mnemonics shift, ctrl,
and alt. Combine them with the virtual key name using the + sign. If you want to specify
more than one shifted key, make sure that they are in the order shift, ctrl, alt.
17
242 Chapter 8: The Terminal Components
1
1
An example of a virtual key code to virtual key name mapping would be:
3
4
An example of mapping Alt+F1 so that it acts like the PF1 key on a VT100 is:
* Map Alt+F1 to PF1
alt+VK_F1 DEC_PF1
Lets follow how the emulator would use these mappings. The user presses Alt+F1. The
emulator would convert the virtual key code returned by Windows (an integer equal to 70
hex) into a string (\x70). It would then lookup this string in the keyboard mapping object
and get the value VK_F1 back. It then prefixes the alt keyword to this value to give
alt+VK_F1 and looks this up. This returns the value DEC_PF1. This is in turn looked
up to return the value \eOP. The emulator then interprets this string as <Esc>OP in order
to send the correct sequence to the host. If a lookup fails at any stage, the keystroke is
assumed to be unmapped. If the emulator cannot interpret the final control sequence string,
it will just send it as is.
Please see ADKEYVT1.TXT for a complete set of mappings that define one way of mapping
the VT100 keys onto the PC keyboard.
The only errors than can occur with LoadFromFile are file I/O errors. Internally
LoadFromFile uses a string list (TStringList) to read the entire file into memory and so any
exceptions raised will be those raised by this class.
6
7
8
9
10
11
method
procedure LoadFromRes(
aInstance : THandle; const aResName : string);
12
13
14
The name of the resource is given by aResName, and the resource is to be found in the
module instance given by hInstance. The resource must be in the binary format created by
the StoreToBinFile method. If any error occurs during the load process, for example the
resource cannot be found or the resource is not in the correct format, the mappings are
cleared. No exception is raised.
15
16
17
1
1
StoreToBinFile
method
The name of the file is given by aFileName. The binary file so created can be compiled into a
resource that can be read by LoadFromRes.
The only errors than can occur are file I/O errors. Internally StoreToBinFile uses a file
stream (TFileStream) and so any exceptions raised will be those raised by this class.
5
6
7
8
9
10
11
12
13
14
15
16
17
244 Chapter 8: The Terminal Components
1
1
The TAdCharSetMapping class provides a method to emulate the different character sets
used by terminals by using glyphs from different fonts.
One of the problems of emulating a terminal with a Windows program is that terminals,
especially the older ones, use specialized glyphs that are not available in the normal
Windows fonts. The character set mapping class attempts to work around this problem by
enabling the emulator to obtain the glyphs for different character sets from different fonts.
Before proceeding with the character set mapping class, we should define a few terms. A
character is a binary value, usually byte-sized. The way we usually think of a character is
both as its binary value and as its visual form. Hence, when we think of the character a, for
example, we think of its value ($61) and of its visual form (a drawing of a lowercase letter a,
like the one you just read just now). However, the link between the character a and the
visual form of the character is not fixed. Different fonts may display the character a in
different ways, and some visual representations (what are known as glyphs) may look
nothing like a lowercase a. An example is the Symbol font where the character a is drawn as
a Greek lowercase . With terminals, there may be several character sets that are available at
once, and these character sets function in the same way as fonts. On the VT100, for example,
there are two main character sets: the standard one and the special graphics one, which
displays the line draw characters. In the first, the character a is drawn as a lowercase a. In
the second it is drawn as a checkerboard glyph.
The character set mapping class is designed to be used by a terminal emulator. When the
terminal display needs to be painted, the emulator will use a character set mapping class to
identify which glyphs need to be painted on the terminal window. For this it will pass a
string of characters to the mapping class, together with the character set to be used. The
TAdCharSetMapping object will return a script to the emulator. This script will consist of a
series of text drawing commands all of the form: using font X, draw string Y. Usually the
script will consist of just one command, since the characters will generally all come from the
standard ASCII set and hence can be drawn using just one font.
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
The TAdCharSetMapping class gets its mapping data from one of two sources: a specially
formatted text file, or a resource linked into the application. Thus it is possible to have a
default mapping linked to the application, but, also, to be able to provide a way of altering
the mappings at run time (maybe to suit the fonts on the users machine). To help create the
resource the character set mapping class has a method to write its current mapping set to a
binary file, which can then be compiled into a resource file. The following code shows this
process:
var
CharSetMap : TAdCharSetMapping;
begin
CharSetMap := TAdCharSetMapping.Create;
try
CharSetMap.LoadFromFile('ADCHSVT1.TXT');
CharSetMap.StoreToBinFile('VT100.BIN');
finally
CharSetMap.Free;
end;
end;
11
12
13
If you name the resource file VT100.RC, the resource compiler will create a file called
VT100.RES. Adding the resource to your application at that point is merely a case of adding
the following line to your project file and recompiling:
{$R VT100.RES}
Now you can call the LoadFromRes method of your TAdCharSetMapping instance to load
this set of character set mappings.
14
15
16
17
246 Chapter 8: The Terminal Components
1
1
Hierarchy
TObject (VCL)
TAdCharSetMapping (ADTrmMap)
Properties
Count
Methods
Add
GetNextDrawCommand
Clear
LoadFromFile
GenerateDrawScript
LoadFromRes
StoreToBinFile
6
7
8
9
10
11
12
13
14
15
16
17
The TAdCharSetMapping Class 247
1
1
Reference Section
Add
method
2
3
4
5
6
7
8
9
10
11
12
13
14
This tries to add a mapping for all of the characters between space and ~ in the MyCharSet
character set to that same characters (i.e., glyphs) from the Courier New font.
15
16
17
248 Chapter 8: The Terminal Components
1
1
Clear
method
procedure Clear;
LoadFromFile and LoadFromRes automatically call Clear prior to loading a set of mappings.
If you wanted to load a set of mappings from another source, you would have to call Clear
first, and then Add for every mapping in your set.
Count
The Count property will return the number of different mappings contained in the class. It
does not differentiate between the different character sets or ranges. It is of use primarily for
writing out the mappings to a file or other object.
GenerateDrawScript
method
procedure GenerateDrawScript(
const aCharSet : TAdKeyString; const aText : string);
9
10
11
12
13
14
15
16
17
The TAdCharSetMapping Class 249
1
1
1
2
3
4
5
6
7
8
9
GetNextDrawCommand
method
function GetNextDrawCommand(
var aFont : TAdKeyString; var aText : string) : Boolean;
method
10
11
The file is a text file in a particular format. LoadFromFile will follow these rules when
reading the file.
12
13
14
15
16
17
250 Chapter 8: The Terminal Components
1
1
The five words, in order, are the same as the five parameters to the Add method. They
denote the following:
1
2
To help in designing portable character set mappings, there is one special value that can be
used for the font name. If the name is <Default>, then the emulator will use the currently
defined font for the terminal component to display text.
An example of defining a character set mapping for the standard ASCII characters would be
This would be read as: the character set name is MyCharSet; the range of characters is
from the space character to the ~ character, inclusive; the font name is Courier New; and
the starting glyph is that for the space character.
10
Please see ADCHSVT1.TXT for a complete set of mappings that define one way of mapping
the VT100 character sets keys onto standard Windows fonts.
11
The only errors than can occur with LoadFromFile are file I/O errors. Internally
LoadFromFile uses a string list (TStringList) to read the entire file into memory and so any
exceptions raised will be those raised by this class.
12
13
14
15
16
17
The TAdCharSetMapping Class 251
1
1
1
2
3
4
5
6
LoadFromRes
procedure LoadFromRes(
aInstance : THandle; const aResName
method
: string);
method
The name of the file is given by aFileName. The binary file so created can be compiled into a
resource that can be read by LoadFromRes.
The only errors than can occur are file I/O errors. Internally StoreToBinFile uses a file
stream (TFileStream) and so any exceptions raised will be those raised by this class.
9
10
11
12
13
14
15
16
17
252 Chapter 8: The Terminal Components
1
1
The TAdTerminalEmulator class is the base class for all terminal emulators. An emulator is
designed to work hand-in-hand with a terminal component to provide the look and feel of a
particular terminal. The emulator does all the hard work: it interprets the input data stream,
looking for terminal control sequences and ordinary text characters and processing them; it
accepts all keystrokes from the terminal component, identifies them and converts them to
output the correct terminal sequence. It also maintains the buffer that describes what the
terminal display looks like, the text characters, colors, attributes and character sets. It has a
character set mapping object that enables it to identify which fonts are used for which glyphs
for display. Finally, and possibly the most important, it uses the terminal components
canvas object to draw a representation of the current view of the terminal.
The second emulator provided by Async Professional is the VT100 terminal emulator,
TAdVT100Emulator. This emulator provides a complete implementation of a standard
VT100 terminal. Features provided by this emulation include:
3
4
7
8
9
10
11
12
The ability to switch character sets to use the line draw characters.
Applying the scrolling region.
13
14
15
16
17
1
1
1
2
The emulator also provides support for the following features that are not part of the
standard VT100 specification, but are nevertheless generally expected to be present in an
emulation. These features are extracted from the ANSI specification and the VT220
specification:
Interlace mode (switching between 240 & 480 scan lines per frame).
6
Smooth scrolling (the emulator performs jump scrolling all the time).
8
9
10
11
12
13
14
15
16
17
254 Chapter 8: The Terminal Components
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TAdTerminalEmulator (ADTrmEmu)
Properties
Buffer
NeedsUpdate
CharSetMapping
Parser
KeyboardMapping
Terminal
! Version
Methods
BlinkPaint
KeyDown
LazyPaint
GetCursorPos
KeyPress
Paint
7
8
9
10
11
12
13
14
15
16
17
1
1
Reference Section
BlinkPaint
virtual method
2
procedure BlinkPaint(aVisible : Boolean); virtual;
3
4
5
6
7
8
9
10
12
The Buffer property is the data structure that holds the elements that go to make up the
visual representation of the terminal. These elements are the text characters, the foreground
and background colors, the attributes of the text (underlined, blinking, and so on), and the
character set ids for the characters.
13
The emulator creates a buffer object in its Create constructor and frees it in the Destroy
destructor. It is not possible to replace the buffer object in between those two times.
11
14
CharSetMapping
15
16
17
1
1
The emulator creates a character set mapping object in its Create constructor and frees it in
the Destroy destructor. It is not possible to replace the character set mapping object in
between those two times. However, it is possible to replace the set of mappings for the
character set mapping object: just call its LoadFromFile or LoadFromRes methods. This will
have the effect of changing the functionality of the emulator.
Note that some emulators will not have a character set mapping object; reading
CharSetMapping will return nil. This is because the emulation concernedfor example, the
TTY emulatordoes not require any character set mapping services.
GetCursorPos
1
2
3
4
virtual method
6
7
Using terminal terminology, the cursor means the keyboard edit point. It is the place
where new text data will be written to the screen. In Windows terminology however, this is
known as the caret, the cursor being the mouse pointer.
KeyboardMapping
10
11
12
13
14
15
16
17
1
1
KeyDown
virtual method
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
258 Chapter 8: The Terminal Components
1
1
virtual method
LazyPaint
virtual method
2
3
There are two types of painting to be done. The first is painting because the new data that
has come from the serial device needs to be shown (this could be triggered by the lazy
display processing of the terminal, for example). The second is painting due to all or part of
the terminal components client window being invalidated and Windows has issued a
WM_PAINT message.
The LazyPaint method is called in the former case. The emulator has been parsing the
incoming data stream and altering the buffer to reflect the new text and other changes
embedded in the stream. The terminal component has determined that the new changes
need to be shown on the client window. There are three ways the terminal can make that
determination. The first is when the emulator sets its NeedsUpdate property to True to
denote that the terminal display has changed and the new data needs to be shown. The
second is when the terminal component is in lazy display mode (its UseLazyDisplay
property is True), and a certain number of bytes (given by the TAdTerminal.LazyByteDelay
property) has been processed. The third is again when the terminal component is in lazy
display mode and the required amount of time, given by the LazyTimeDelay property, has
elapsed.
6
7
8
9
10
The emulator needs to interrogate its terminal buffer object to find out the changed
character cells in the terminal display and to display them on the terminal components
canvas.
11
12
NeedsUpdate
13
14
15
16
17
1
1
Paint
virtual method
2
3
4
5
6
The Paint method of the emulator is called by the Paint method of the terminal component,
the standard VCL virtual method for TWinControl descendants.
run-time property
9
property Parser : TAdTerminalParser
10
11
12
13
14
15
16
17
260 Chapter 8: The Terminal Components
1
1
It is possible to replace the parser at run time. This will have the effect of altering the
behavior of the emulator component. The class will dispose of the old parser and start using
the new one. Be aware that it is possible to switch parsers while the old parser is in the
middle of processing a terminal control sequence. In that case, the partially received control
sequence is lost. It is best to replace the parser just after calling the old parsers ProcessChar
method, if it does not return pctPending.
Terminal
1
2
3
property
6
7
8
9
10
11
12
13
14
15
16
17
The TAdTerminalEmulator Class 261
1
1
The TAdTTYEmulator class emulates a teletype terminal, one that doesnt support any
terminal control sequences and one that merely displays every character received. Similarly
there is no conversion of keystrokes either: if a key for a displayable characters is pressed,
that character is sent to the host without interpretation.
3
4
5
6
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
" TAdTerminalEmulator (ADTrmEmu). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
8
9
10
11
TAdTTYEmulator (ADTrmEmu)
Properties
" Buffer
" NeedsUpdate
" CharSetMapping
" Parser
" KeyboardMapping
" Terminal
! Version
Methods
12
13
" BlinkPaint
" KeyDown
" LazyPaint
" GetCursorPos
" KeyPress
" Paint
14
15
16
17
262 Chapter 8: The Terminal Components
1
1
The TAdVT100Emulator class provides support for the standard VT100 terminal modes.
These are as follows:
3
4
Line feed/newline: whether the line feed character inserts a new line or merely
advances the cursor to the next line with a possible scroll.
Cursor key mode: whether the cursor movement keys send application mode
sequences or cursor mode sequences.
ANSI/VT52 mode: whether the terminal interprets ANSI escape sequences or the
restricted VT52 sequences.
6
7
8
Scrolling mode: whether the terminal jump scrolls or smooth scrolls. Although the
VT100 emulator maintains this setting, all scrolling is performed with jump scrolls.
Wraparound mode: whether the terminal wraps the cursor to column 1 of the next
line when a character is displayed in the final column.
Graphic processor option: whether the terminal uses its GPO. Although the VT100
emulator maintains this setting, it does not perform any action when it changes.
10
11
12
13
14
15
Keypad mode: whether keys on the numeric keypad send numeric characters or
16
escape sequences.
17
The TAdVT100Emulator Class 263
1
1
1
2
3
4
There are several escape sequences sent by the host computer to which the VT100 terminal
must respond. The VT100 emulator sends the responses shown in Table 8.2.
Table 8.2: VT100 emulator escape sequence responses
Request
Response
Status report
Terminal OK (<Esc>[0n).
Hierarchy
6
7
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
" TAdTerminalEmulator (ADTrmEmu). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
8
9
TAdVT100Emulator (ADTrmEmu)
Properties
ANSIMode
10
AppKeyMode
AppKeyPadMode
11
12
13
14
15
" KeyboardMapping
LEDs
" NeedsUpdate
AutoRepeat
" Buffer
NewLineMode
" Parser
" GetCursorPos
" KeyDown
RelOriginMode
" KeyPress
Col132Mode
RevScreenMode
" LazyPaint
SmoothScrollMode
" Paint
GPOMode
Interlace
" Terminal
Methods
" BlinkPaint
" KeyDown
" LazyPaint
" GetCursorPos
" KeyPress
" Paint
17
264 Chapter 8: The Terminal Components
WrapAround
" BlinkPaint
" CharSetMapping
16
! Version
Reference Section
ANSIMode
run-time property
2
property ANSIMode : Boolean
The VT100 terminal can act on two different and separate sets of terminal control
sequences. If ANSIMode is True, the parser will only interpret ANSI escape sequences, and
VT52 sequences are ignored. If False, the parser only understands the restricted VT52
command sequence set and all ANSI escape sequences are ignored.
It is the host computer that determines this mode. Although you can change this property it
is inadvisable to do so: bizarre displays may result.
6
AppKeyMode
run-time property
! Determines which sequences are sent for the cursor movement keys.
The VT100 terminal can send two different escape sequences for the cursor movement keys
(the arrow keys). DEC documentation calls them application mode and cursor key mode.
It is the host computer that determines this mode. Although you can change this property it
is inadvisable to do so: it may result in the host computer not understanding keystrokes.
AppKeypadMode
run-time property
8
9
10
11
12
13
14
15
16
17
1
1
AutoRepeat
run-time property
2
3
4
5
Col132Mode
run-time property
The VT100 terminal can support two display widths: 80 characters or 132 characters across.
If Col132Mode is True, the terminal is displaying at 132-column resolution. If False, the
norm, the terminal is displaying at 80-column resolution.
It is the host computer that determines this mode. Although you can change this property it
is inadvisable to do so: it may result in bizarre displays since the host is assuming something
that is no longer true.
GPOMode
10
11
12
13
14
15
17
266 Chapter 8: The Terminal Components
run-time property
16
run-time property
LEDs
The VT100 keyboard has a set of four LEDs embedded in the face of the keyboard. The host
computer can set them on or off if required. The LEDs property returns an integer value as a
binary representation of the current state of the LEDs: if the first LED is on, bit 0 is set in the
property value; if the second LED is on, bit 1 is set and so on.
3
4
The LEDs are only visual, they do not affect the use of the keyboard or functionality of the
terminal at all. Indeed, the host computer cannot even read their state.
NewLineMode
run-time property
7
8
If this property is True, the cursor is advanced one row down, moving to the first column,
scrolling the display up if necessary. The Enter key sends a pair of characters: <CR><LF>.
It is the host computer that determines this mode. Although you can change this property it
is inadvisable to do so: it may result in bizarre displays since the host is assuming something
that is no longer true.
10
RelOriginMode
run-time property
11
12
13
14
15
16
17
1
1
1
2
If this property is True, the cursor home position is at the top left corner of the scrolling
region. Rows and columns are counted from this origin (this can be viewed as relative
position modepositions are relative to the scrolling region). Rows and columns are always
counted from 1. Cursor position commands only act inside the active scrolling region.
It is the host computer that determines this mode. You can change this property to write text
outside of the scrolling region, but it is advisable to change it back immediately; otherwise, it
may result in bizarre displays since the host is assuming something that is no longer true.
RevScreenMode
run-time property
If this property is False, normal text is shown as white on black. If True, normal text is shown
in reversed: as black on white.
On the VT100 the user most often sets this mode, not the host computer, although the host
can change the mode if it wishes.
SmoothScrollMode
run-time property
10
The VT100 terminal can scroll the display in two modes: a smooth scroll, or a jump scroll.
Although maintained, the VT100 emulator does nothing with this property.
11
WrapAround
run-time property
12
13
If this property is False, text received when the cursor is at the right hand side does not cause
the cursor to be moved to the first column of the next row.
14
If this property is True, text received when the cursor is at the right hand side will cause the
cursor to be moved to the first column of the next row to display all the text.
15
It is the host computer that determines this mode. It is inadvisable to change this mode,
otherwise it may result in bizarre displays since the host is assuming something that is no
longer true.
16
17
268 Chapter 8: The Terminal Components
1
1
The TAdTerminal component represents the visual part of a terminal. It is the only visual
component in the Async Professional family of terminal classes. It is responsible for
maintaining the window handle and for performing the low-level processing to get all the
possible keystrokes available on a PC keyboard.
Apart from this, it performs next to no work itself, handing off most of the display and other
capabilities to an emulator component (a descendant of TAdTerminalEmulator). Essentially,
the terminal component acts as a conduit between the PC screen and keyboard and the
other classes that perform all of the work.
3
4
The main behaviors of the terminal component and its associated objects are as follows:
Receives characters from the serial device and passes them onto the emulator for
Traps all keystrokes and passes them onto the emulator for conversion into their
terminal equivalents.
The emulator maintains a buffer of several matrices, one for each of text, background
color, text color, attributes, and character sets. This buffer stores the information
needed to show the visual representation of the terminal.
The terminal has the capability of maintaining a scrollback buffer to enable the user
8
9
to scroll back through old data that has scrolled off the display. The terminal will
automatically show scrollbars in that case.
10
The terminal will automatically display scrollbars if the client window is smaller than
11
If the terminal component is dropped onto a form and there is no existing emulator
component on that form, the terminal will create an internal instance of a TTY
(teletype) emulator. This means that the terminal component can be used as is for
simple tasks.
In order for the terminals window to show data, there are two objects that must be
connected to it: the COM port (a TApdComPort component), and an emulator (a
TAdTerminalEmulator descendant component). To use a terminal component, you would
drop a terminal, a COM port, and a terminal emulator onto the form and connect them up
by setting the ComPort and Emulator properties of the terminal. Once they are connected
up in this fashion, you can set the terminals Active property to True and start using the
terminal.
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
The COM port provides the terminal with incoming bytes from a serial communications
device, such as a serial port or Winsock layer. The terminal, in turn, provides the data that
must be output to the serial device. In and of itself, the terminal component doesnt know
what to do with the incoming data; it has no built in knowledge of terminal control
sequences and how to separate the text from them. Hence, it passes the incoming data
stream directly to the terminal emulator component. This component in turn would use a
parser object to identify terminal control commands, a buffer object to store the displayable
data, and so on. The terminal would also pass all keyboard input to the emulator as well, so
that the emulator can process the keystrokes and determine what to pass back to the host (it
would use a keyboard mapping object to do this). The emulator will use the COM port of
the terminal component to pass back data through the serial device to the host computer.
As for display, the emulator would assume control over the window handle of the terminal
component and draw directly onto its canvas.
The reason for this more complex designrather than rolling the emulator and terminal
components into oneis flexibility. With this design it is possible to switch emulators on the
fly without having to destroy the window handle used by the terminal and thus avoiding
flicker. Hence, you can easily start off with a TTY emulator for the terminal, and switch to a
VT100 emulator later on. The terminal component thus stores generic information about a
terminal (e.g., the number of characters across and down), whereas the emulator
component holds specific information about a specific terminal (e.g., whether to accept
VT52 or ANSI sequences for a VT100 terminal).
10
11
12
13
14
15
16
17
270 Chapter 8: The Terminal Components
1
1
Figure 8.2 shows the interrelationship between the client window, the terminal display and
the scrollback buffer.
1
2
Columns
ROW
SCROLLBACK
BUFFER
ScrollbackRows
ClientOrigin
6
7
-1
0
1
2
TERMINAL
DISPLAY
8
9
ClientCols
ClientRows
10
Rows
11
TERMINAL
CLIENT
WINDOW
12
Figure 8.2: Interrelationship between the client window, the terminal display, and the scrollback buffer.
The client window acts as a viewport on the terminal display. In general, you would make
sure that the client window was large enough to display all of the data in the terminal display.
If that is so, no scroll bars are shown. Should the client window be smaller vertically, or
horizontally, or both, than the terminal display, the relevant scrollbars are automatically
shown to enable the user to scroll though and view the entire terminal display.
13
14
15
16
17
1
1
1
2
3
4
5
If scrollback mode is activated, the client window acts as a viewport on the entire scrollback
buffer, not just on the terminal display. Scrollbars would automatically be shown, if
required, to enable the user to scroll through the entire buffer. In scrollback mode, the
terminal component no longer processes any data from the serial device nor does it trap
keyboard messages and pass them on to the emulator.
The terminal component also supports a lazy write mode. In this mode, incoming data is
processed but not displayed until one of two conditions occurs: either a certain number of
bytes is received, or a certain amount of time has elapsed. Once the required time has gone
by or the number of bytes has been received, the terminal component will force its display to
be updated, and the process starts all over again. Fine tuning of these two properties will
result in a terminal that is more responsive, and has more efficient and smoother behavior.
Font handling
6
7
8
9
10
11
12
13
The issue of fonts becomes complex when dealing with a terminal that should support
displaying non-standard glyphs for characters. For example, when emulating the VT100
terminal, the standard Windows fixed pitch fonts do not have every single glyph. The
CharSet mapping class attempts to ameliorate the situation by providing a mapping from a
character in a character set to a glyph in a Windows font. Apart from the simple TTY
emulation, there will unfortunately be several fonts in action for the usual terminal
emulations. The ability to switch fonts easily as with simple components cannot apply in the
case of the terminal. The terminals situation is entirely more complex: text displayed may
contain glyphs from several unrelated fonts.
What the terminal component and its associated classes attempt to do is to make the
displayed glyphs the same point size. The point size of the fonts used by the terminal is taken
to be the same as the Size property of its Font property. Hence, to change the size of the text
displayed by the terminal, you would need to change the Font.Size property. For certain
emulations, the terminals Font property will in fact determine the font with which the text is
displayedin other words, there is no CharSet mapping required.
The terminal classes will allow the use of proportional fonts. However, it should be noted
that text displayed using these proportional fonts will be shown in fixed size character cells,
and proportional fonts displayed in fixed pitch can look awkward and clunky. Our advice is
to try and stick to fixed pitch fonts wherever possible.
14
15
16
17
272 Chapter 8: The Terminal Components
1
1
Capturing data
The terminal component has a built-in facility to capture data, that is, to write all data
received by the serial port to a capture file. The capture file can be used for later review of an
on-line session.
The data is written to the capture file before the emulator has an opportunity to see the data
stream and to parse out the terminal control sequences. Hence, the capture file is not a
simple text file, it could consist of numerous control characters and escape sequences as well
as normal text.
1
2
3
4
Characters typed at the keyboard are not saved in the capture file. However, such characters
usually end up in the capture file anyway, since the host computer echoes them back to the
terminal.
6
7
8
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
You can copy the marked block to the clipboard by calling the terminal window routine
CopyToClipboard.
" Caution: Although the CopyToClipboard method will copy the marked text to the
clipboard, you should be aware that what you see may not be what you get. The terminal
classes in Async Professional support the notion of different character sets. In other words,
with certain emulations, the glyphs that are displayed on the terminal display may seem to
have no connection with the characters that are actually there. For example, with a VT100
terminal, when using the USASCII character set the character m will be displayed as a
lowercase m. However, when using the special graphics character set, the character m is
rendered as the lower left corner of the line draw set (the glyph that looks like an L). The
problem is that, when you copy the marked text to the clipboard, you will lose the character
set definition for each character. Hence, you will just get the character m in the clipboard
and not know whether it really was shown as an m or some other glyph.
6
7
8
9
10
11
12
13
14
15
16
17
274 Chapter 8: The Terminal Components
1
1
Hierarchy
TWinControl (VCL)
! TApdBaseWinControl (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TAdTerminal (ADTrmEmu)
2
3
Properties
Active
CharWidth
Line
Attributes
Columns
Rows
BackColor
ComPort
ScrollbackRows
BlinkTime
Emulator
Scrollback
Capture
ForeColor
CaptureFile
HalfDuplex
CharHeight
LazyByteDelay
CharSet
LazyTimeDelay
UseLazyDisplay
! Version
WantAllKeys
7
8
Methods
Clear
CreateWnd
DestroyWnd
ClearAll
Create
WriteChar
CopyToClipboard
Destroy
WriteString
Events
9
10
11
OnCursorMoved
12
13
14
15
16
17
The TAdTerminal Component 275
1
1
Reference Section
Active
property
2
property Active : Boolean
Default: True
Setting Active to True causes the terminal to start processing serial and keyboard data and to
display this information in the terminal window. At run time, if an attempt is made to set
Active True without a serial port component being assigned to the ComPort property, or
without an emulator component being assigned to the Emulator property, the attempt is
ignored. It is acceptable to set Active to True at design time; this causes the terminal to start
processing events automatically when the form is created at run time.
You must set Active to False if the terminal is being used in combination with another
component, such as a file transfer component, that needs exclusive access to some or all of
the data stream. During a file transfer, set Active to False for the duration of the transfer and
True when the transfer is over and data should appear in the terminal window again.
The following example sets Active to False as it starts receiving a file to prevent the terminal
from displaying the received data. An OnProtocolFinish event re-enables the terminal
window once the protocol informs the application that the transfer is complete.
AdTerminal1.Active := false;
ApdProtocol1.StartReceive;
...
procedure TMyForm.ProtocolFinish(
CP : TObject; ErrorCode : Integer);
begin
AdTerminal1.SetFocus;
AdTerminal1.Active := true;
end;
14
15
16
17
276 Chapter 8: The Terminal Components
1
1
Attributes
6
7
8
9
10
11
12
13
14
15
16
17
1
1
BackColor
2
3
4
5
6
7
8
9
10
11
12
Default: 500
13
14
property
property
Default: cmOff
15
16
17
278 Chapter 8: The Terminal Components
1
1
It has three possible values on writing: cmOn, cmOff, or cmAppend. If the value written is
cmAppend and the current value is cmOff, the capture file is opened in non-sharing mode
for appending data and the value of the Capture property is then set to cmOn. Note that if
the file doesnt exist at the time the property is set, it will be created. If the value written is
cmAppend and the current value is cmOn, the assignment is ignored and nothing happens.
1
2
If the value written is cmOn and the current value is cmOff, the file is created. If it existed
prior to the assignment, it will be overwritten.
The name of the file where captured data is written is given by the CaptureFile property.
All data coming into the terminal is written to the file without any effort being made to parse
it or identify terminal control sequences. Thus for a complex terminal emulation the data in
the capture file will consist of intermingled text and terminal control sequences.
If the CaptureFile property has not been set to the name of a file (i.e., it is the empty string),
setting Capture to cmOn or cmAppend will have no effect. The attempt will be ignored and
no exception will be raised. If the CaptureFile property has been set, an attempt is made to
create or open the file so named. This operation can of course fail for any of a number of
different reasons. Internally, the terminal uses a file streamTFileStreamto access the
file, so any I/O exceptions raised will be those used by the standard Delphi class.
6
7
8
property
9
10
Default: APRO.CAP
! Defines the name of the file where the terminal writes captured data.
It is possible to change the name of the file where captured data is sent while data is being
captured. Internally, the terminal component sets the Capture property to cmOff, changes
the value of the CaptureFile property to the new filename, and then sets the Capture
property to cmOn again. This does mean that the file named by the new value of CaptureFile
is created afresh: the old file, if it exists, is overwritten. If you wish to append to the file with
the new name, you will need to manually set Capture to cmOff, set the value of CaptureFile
to the new filename, and then set Capture to cmAppend.
11
12
13
14
15
16
17
The TAdTerminal Component 279
1
1
CharHeight
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
280 Chapter 8: The Terminal Components
1
1
CharWidth
The terminal display can be viewed as a matrix of fixed-sized character cells. There are Rows
cells vertically and Columns cells horizontally. The size of these character cells is calculated
as the maximum required to display all of the possible characters in all of the possible
character sets. Since different characters in different character sets could be displayed using
different Windows fonts, the character cell size can be viewed as a function of the different
possible Windows fonts used by the emulator. The value of CharWidth is the maximum
needed to display any glyph.
The overall size of the characters displayed by the terminal is given by the Size property of
the Font property of the terminal component. The Font property is used as the default font
for those terminal emulations that dont support character sets. For terminals that do
support character sets, the size of the glyphs is given by the Font.Size value.
See also: CharHeight
Clear
method
procedure Clear;
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
ClearAll
method
procedure ClearAll;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Default: 80
" Caution: Because of the structure of the buffer class, in Delphi 1, the product of Columns
and ScrollbackRows cannot exceed 16,383. For an 80 column display, that means the
number of scrollback rows cannot exceed 204. There is no such limitation with 32-bit
compilers.
16
17
282 Chapter 8: The Terminal Components
1
1
property
ComPort
property
3
4
Note that setting the value of ComPort may not be enough to get the terminal to display
data. You must also activate the terminal by ensuring that Active is set to True, and you must
also supply a terminal emulator component by setting the Emulator property to process the
incoming data stream.
CopyToClipboard
method
procedure CopyToClipboard;
10
Please read the caution within the section entitled Using the clipboard on page 273 in the
introduction to the TAdTerminal component. This discusses why, after calling this method,
the clipboard may not contain what you see on the display.
11
Create
constructor
12
13
14
15
16
17
The TAdTerminal Component 283
1
1
CreateWnd
method
2
3
4
5
Destroy
destructor
The destructor will free all memory and resources allocated by the instance. Of particular
note is that if data is being captured when Destroy is called, the capture file is closed
properly first.
See also: Create
8
9
DestroyWnd
method
If a keyboard hook was properly installed by the CreateWnd procedure, DestroyWnd will
remove it before destroying the window handle associated with the terminal component.
11
12
Emulator
property
13
14
15
16
17
284 Chapter 8: The Terminal Components
1
1
The emulator processes the input data stream looking for terminal control sequences. It will
then use the terminal components window handle to paint a representation of the terminal
screen. The terminal component also traps keystrokes and passes them to the emulator. The
emulator will then convert these keystrokes into valid messages or sequences for the host
computer and use the terminals ComPort to pass them back.
The Emulator property is usually set automatically at design time to the first
TAdTerminalEmulator descendant component the terminal component finds on the form. If
necessary, use the Object Inspector to select a different TAdTerminalEmulator descendant
component.
Usually, setting the Emulator property at run time is necessary only when switching
between different terminal emulations. The terminal does not clear the display at such
times, it is up to the new terminal emulator to reset its buffer and to display the cleared
screen.
Note that setting the value of Emulator may not be enough to get the terminal to display
data. You must also activate the terminal by ensuring that Active is set to True, and you must
also supply a COM port component by setting the ComPort property to an appropriate
TApdCustomComPort component.
2
3
4
6
7
8
10
11
12
13
14
15
16
17
The TAdTerminal Component 285
1
1
HalfDuplex
property
Default: False
If HalfDuplex is False (the default), data entered at the local keyboard is displayed only if the
remote host computer echoes it back.
If HalfDuplex is True, data entered at the local keyboard is automatically displayed in the
terminal window. If the host computer is echoing the input data back as well, each character
is displayed twice.
LazyByteDelay
6
7
property
Default: 128
! Determines the number of bytes received before the display is forcibly repainted.
8
9
10
11
The TAdTerminal supports a lazy writing mode. When this mode is active, rather than
update the display every time a new character appears from the serial device, the terminal
and its associated classes will only display new data after a certain amount of time, or after a
certain number of bytes have been received, or both. This gives the terminal a more efficient
and smoother feel. The value of LazyByteDelay defines how many bytes must be received
before the terminal window is updated. The default value is a compromise between
efficiently handling the display and providing timely visual feedback to the user.
See also: LazyTimeDelay, UseLazyWrite
LazyTimeDelay
12
13
property
Default: 250
! Determines the number of elapsed milliseconds before the display is forcibly repainted.
14
15
16
17
The TAdTerminal supports a lazy writing mode. When this mode is active, rather than
update the display every time a new character appears from the serial device, the terminal
and its associated classes will only display new data after a certain amount of time, or after a
certain number of bytes have been received, or both. This gives the terminal a more efficient
and smoother feel. The value of LazyTimeDelay defines how many milliseconds must pass
before the terminal window is updated. The default value is a compromise between
efficiently handling the display and providing timely visual feedback to the user.
See also: LazyByteDelay, UseLazyWrite
1
1
Line
Line returns and sets the characters that make up a row in the terminal. It enables the direct
manipulation of the text displayed by the terminal. Line is an array property indexed by the
row number (aRow). aRow is one-based: the home position of the terminal display is at row
1 column 1. Note, however, that if you have a scrollback buffer that aRow can take on
negative values, as well, to identify non-visible rows in the scrollback buffer.
3
4
" Caution: Line returns the character values that make up a row. For some terminals, the
glyph you see on the terminal for a particular character value is not only based on the
character value itself, but also on the character set that is being used to display that character.
For example, on a VT100 terminal, if the character m is displayed using the USASCII
character set, you will see the usual lower case m glyph on the display. However, if the same
character m is displayed using the Special Characters character set, you will see the lower
left corner linedraw glyph (the one that looks like an L). All the Line property will return is
the m character value at that particular column position.
6
7
8
9
property
10
Default: 24
11
12
13
14
15
16
17
1
1
1
2
3
4
Notice that Rows is the number of rows on the original terminal, not the number of rows in
the scrollback buffer. The terminal display will consist of Rows lines, with Columns
characters in each.
Altering the value of Rows may cause the underlying buffer to be resized. The terminal will
attempt to save as much of the original data as possible during the resize operation. The data
will be preserved from the bottom of the terminal upwards. In other words, if you reduce the
number of rows from 20 to 15, say, you will see the bottom 15 rows of the original display
after the operation completes, not the top 15.
Setting the value of Rows to less than that supported by the original terminal itself is liable to
produce funny looking displays, since the host computer will assume that the terminal is the
correct size and position text accordingly.
The rows in the terminal display are counted from 1, with the top row of the terminal being
row 1.
Scrollback
property
Default: False
If Scrollback is set True, the terminal is placed into scrollback mode. In this mode,
keystrokes are no longer translated into their terminal equivalents and instead serve to
navigate through the scrollback buffer. Hence, in scrollback mode, the Page Up/Page Down
keys will move the user through the scrollback buffer, as will the standard arrow keys.
If scrollback mode is activated, the terminal will also no longer receive data from the serial
device. It is recommended that you impose flow control on the COM port when you switch
into scrollback mode (either send an XOFF character or drop a hardware flow control
signal), to help avoid the dispatchers input buffer overflowing. The terminal does not do
this itself. Imposing flow control helps keep the terminal data stable to allow the user to
navigate though the scrollback buffer in a profitable manner. Obviously, when you leave
scrollback mode, you would end the flow control condition to allow more data to come
through and be processed.
See also: ScrollbackRows
15
16
17
288 Chapter 8: The Terminal Components
1
1
ScrollbackRows
property
Default: 200
3
4
6
7
8
9
10
property
11
Default: True
! Defines whether the terminal immediately displays new incoming data or not.
12
The TAdTerminal supports a lazy writing mode. When this mode is active, rather than
update the display every time a new character appears from the serial device, the terminal
and its associated classes will only display new data after a certain amount of time, or after a
certain number of bytes have been received, or both. This gives the terminal a more efficient
and smoother feel.
13
If UseLazyDisplay is False, the terminal will display every incoming character as and when it
arrives. If UseLazyDisplay is True, the terminal will display the new data on the screen after
LazyByteDelay bytes have been received since it last updated the window, or after
LazyTimeDelay milliseconds have elapsed.
15
14
16
17
1
1
1
2
3
The lazy writing mode only applied to data written to the terminal, either from the serial
device, or from the keyboard in half duplex mode, or from data explicitly written from
calling WriteChar or WriteString. If the terminal components window is invalidated due to
another window covering it and then being moved, or from the application being
minimized and then restored, the terminal display is immediately repainted.
See also: LazyByteDelay, LazyTimeDelay
WantAllKeys
property
4
property WantAllKeys : Boolean
Default: True
! Defines whether the terminal component hooks and retrieves all keystrokes.
6
7
8
9
10
11
12
13
Part of the job of a terminal component is the ability to map the PC keyboard onto a
terminal keyboard. This latter keyboard might be a completely different layout than the PC
keyboard and, apart from the alphabetic key section, have different keys for different host
functions. The keyboard mapping should attempt to match PC keys (whether they are altshifted, ctrl-shifted, or whatever) onto appropriate terminal keys.
A problem that will occur is that keys like F1, F10, Enter, Tab, and so on, have a well-defined
meaning in the Windows world. Normally, controls on a form would ignore these keys since
they have dialog-specific or application-wide meanings. However, for a terminal component
it often makes sense to have these keys perform a terminal related function and to suppress
the standard Windows meaning. If WantAllKeys is True, the terminal component will
attempt to hook and trap all keystrokes generated while it has focus. Hence, for example, F1
will not bring up the help system (it will not cause a WM_HELP message to be sent to the
control), F10 will not activate the main menu of the application, and so on.
If WantAllKeys is False, the terminal component will not perform anything special with
regard to the keyboard. It will just trap WM_KEYDOWN and WM_SYSKEYDOWN
messages and pass them on to the emulator for processing. Standard Windows keys will
perform their usual functions.
14
15
16
17
290 Chapter 8: The Terminal Components
1
1
WriteChar
method
The character written to the terminal will go through the same steps that a character that
had arrived from the serial device would go through. In other words, the character is first
passed to the emulator, which decides what to do with it. If the emulator decides that the
character is part of a terminal control sequence, it would appear as if the character had not
been acceptedit would not appear on the displaywhen in reality it had.
The terminal will accept a character written with WriteChar at any time, even when it is
actively receiving data from the serial device. Be aware that under these circumstances, the
character written with WriteChar will intermingle with data from the serial device and may
cause some bizarre behavior and displays.
3
4
Note also that the lazy write mode still applies to text written to the terminal with WriteChar.
If UseLazyDisplay is True, the text will appear at the appropriate time. You can force the new
data to be displayed in this case by calling the Update method.
WriteString
method
10
The terminal will accept a string written with WriteString at any time, even when it is
actively receiving data from the serial device. Be aware that under these circumstances, the
characters written with WriteString will intermingle with data from the serial device and
may cause some bizarre behavior and displays.
13
Note also that the lazy write mode still applies to text written to the terminal with
WriteString. If UseLazyDisplay is True, the text will appear at the appropriate time. You can
force the new data to be displayed in this case by calling the Update method.
11
12
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
292 Chapter 8: The Terminal Components
1
1
Chapter 9: IP Telephony
1
2
Async Professional includes components to transmit data over phone lines and networks,
and components to transmit wave recordings through voice modems, APRO also includes a
component to transmit audio and video through the network through IP Telephony.
IP (Internet Protocol) Telephony is a technology where audio and video can be streamed
across a network. As its name implies, IP Telephony uses IP as the transport layer. This
transport layer is provided through TCP/IP. IP Telephony, in APRO, also uses TAPI 3.x,
which is only available for Windows 2000 (future Windows versions should also support this
implementation). TAPI 3.x, in turn, uses H.323 and the Microsoft H.323 TAPI Service
Provider, which is installed by default.
4
5
6
IP Telephony includes the transmission of voice and video over the network. The network
can be a local area network (LAN), wide area network (WAN) or the Internet. This
technology offers the capability of establishing real-time conferencing around the globe
using existing network topology. Using this technology you can hold a real-time conference
(complete with audio and video), telecommuting, distance learning, and video on demand,
to name a few of the possibilities.
7
8
9
10
11
12
13
14
15
16
17
293
1
1
The TApdVoIP component implements IP Telephony (also known as Voice over IP)
through the services of TAPI 3.x. TAPI 3.x is available for Windows 2000. Documentation
on the Microsoft web site confirms that future Windows versions will support the TAPI 3.x
architecture. The TApdVoIP component implements a small subset of TAPI 3.x, limited to
the functionality required for Voice over IP.
3
4
5
6
7
8
9
10
11
12
Since the TApdVoIP component requires TAPI 3.x, and TAPI 3.x is available only on
Windows 2000 and later, the TApdVoIP component requires Windows 2000 or later and the
Microsoft H.323 TAPI Service Provider. An application that contains the TApdVoIP
component can be instantiated on an unsupported Windows version, however all
TApdVoIP methods will raise the EVoIPNotSupported exception. To prevent this exception,
the VoIPAvailable property can be checked, this property will be True if the required TAPI
components are available and False if TAPI does not support it.
H.323
TAPI 3.x implements IP Telephony through the H.323 protocol. This protocol is optimized
for the transmission of voice and video over connectionless networks that do not provide
guaranteed quality of service (such as IP-based networks and the Internet). H.323 is a
comprehensive ITU (International Telecommunications Union) standard for multimedia
communications. This protocol defines call control techniques, multimedia and bandwidth
management, and mandates for standard audio and video codecs. The H.323 protocol is
also platform independent, which means an H.323 instance on a Windows machine can
communicate with an H.323 instance on another operating system.
Detailed discussions, and implementation specifications, are available on the ITU Web site.
Knowledge of H.323 is not required to use the IP Telephony components in Async
Professional. TAPI 3 and APRO will handle all of the details for you.
13
14
15
16
17
294 Chapter 9: IP Telephony
1
1
The TApdVoIP component also automatically selects the H.323 TAPI device. If this device is
not installed (it is installed by default in Windows 2000), the VoIPAvailable property is set to
False when the component is created, and the TApdVoIP methods will raise the
EVoIPNotSupported exception when called.
The audio and video streaming in VoIP are provided through H.323 media services (also
installed by default in Windows 2000). These media services support selection of the audio
input, audio output, video input and video output devices. When the TApdVoIP component
is created, the media services are queried for supported media terminals. As the terminals
are being queried, their capabilities are also queried. All of the supported media terminals
are stored in the AvailableTerminalDevices property. This property is a TStrings instance,
the Strings value is the name of the terminal; the Objects value is a TApdVoIPTerminal
object. See the TApdVoIPTerminal description later in this chapter for details.
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
These properties can also be set through the property editor. This property editor is also
available at run time through the ShowMediaSelectDialog method. The property editor for
these properties contains a combo box for each property as shown in Figure 9.1.
2
3
4
5
Figure 9.1: Media device property editor.
Each combo box contains the terminal types associated with the given property. The Audio
input control contains only those devices that support audio input; the Audio output
control contains only those devices that support audio output; the Video input control
contains only those devices that support video input. When OK is clicked, the
AudioInDevice, AudioOutDevice and VideoInDevice properties are updated to reflect the
changes. If Cancel is clicked, the changes are disregarded.
10
11
12
When originating a call, the TApdVoIP component initializes the underlying TAPI and
H.323 layers, and then attempts to connect to a VoIP implementation elsewhere on the
network. The Connect method of the TApdVoIP component begins the connection attempt.
The destination address is determined by the DestAddr string parameter of the Connect
method. VoIP addresses can be dotted quad Internet addresses or machine names. For
example, the following snippets will connect to a specified IP address and a specified
machine:
ApdVoIP1.Connect('192.168.12.131');
13
14
ApdVoIP1.Connect('john_work.turbopower.com');
15
16
17
296 Chapter 9: IP Telephony
1
1
When receiving a call, the TApdVoIP component initializes the underlying TAPI and H.323
layers and waits for the incoming call. The Connect method of the TApdVoIP component
begins the answering process. When that method is called with a DestAddr of (empty
string), the TAPI and H.323 layers are activated and configured to provide status
notifications. When an incoming call is detected, the OnIncomingCall event is generated. If
the Accept parameter of that event is set to True (the default), the call is answered and the
OnConnect event is generated. The following example shows how to receive a VoIP call:
2
3
4
...
ApdVoIP1.Connect('');
...
procedure TForm1.ApdVoIP1IncomingCall(VoIP : TApdCustomVoIP;
CallerAddr: string; var Accept : Boolean);
begin
Accept := MessageDlg('Accept incoming call from ' +
CallerAddr, mtConfirmation, [mbYes, mbNo], 0) = mrOK;
end;
6
7
8
9
10
11
12
13
14
15
16
17
1
1
TApdVoIPTerminal Class
2
3
The TApdVoIPTerminal class defines a media terminal. This class is used in the TApdVoIP
components AvailableTerminalDevices property. The AvailableTerminalDevices property is
a TStrings type. Each Strings value is the name of a media terminal, each Objects value is a
TApdVoIPTerminal class that defines the capabilities of the given terminal.
Hierarchy
TStrings (VCL)
5
6
7
TApdVoIPTerminal (AdVoIP)
Properties
DeviceClass
DeviceName
DeviceInUse
MediaDirection
8
9
10
11
12
13
14
15
16
17
298 Chapter 9: IP Telephony
1
1
MediaType
Reference Section
DeviceClass
2
property DeviceClass : TApdTerminalDeviceClass
TApdTerminalDeviceClass = (
dcHandsetTerminal, dcHeadsetTerminal, dcMediaStreamTerminal,
dcMicrophoneTerminal, dcSpeakerphoneTerminal, dcSpeakersTerminal,
dcVideoInputTerminal, dcVideoWindowTerm)
3
4
DeviceClass
AudioInDevice
dcHandsetTerminal
6
7
dcHeadsetTerminal
dcMicrophoneTerminal
dcSpeakerphoneTerminal
AudioOutDevice
dcHandsetTerminal
dcHeadsetTerminal
10
dcSpeakerphoneTerminal
dcSpeakersTerminal
VideoInDevice
11
dcVideoInput
12
13
property DeviceInUse : Boolean
14
This property is True if the terminal is being used by another process, and False if the
terminal is available.
15
16
17
1
1
DeviceName
This property reflects the name of the media terminal as defined by the media installer. This
property is used to define the Strings value associated with this Object when added to the
AvailableTerminalDevices property.
MediaDirection
6
7
8
Description
mdCapture
mdRender
mdBidirectional
9
10
11
MediaType
12
13
14
15
16
17
300 Chapter 9: IP Telephony
1
1
TApdVoIP Component
The TApdVoIP component implements Voice over IP (IP Telephony) through the TAPI 3.x
and H.323 interfaces. This component is compatible with Windows 2000, although later
Windows versions will most likely support TAPI 3.x to some extent.
2
3
Hierarchy
4
TOleServer (VCL)
! TApdBaseOleServer (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomVoIP (AdVoIP)
TApdVoIP (AdVoIP)
Properties
AudioInDevice
AudioOutDevice
Connected
! Version
AvailableTerminalDevices
VideoInDevice
CallInfo
VideoOutDevice
VoIPAvailable
WaitingForCall
7
8
9
Methods
CancelCall
Connect
ShowMediaSelectDialog
10
11
Events
OnConnect
OnFail
OnDisconnect
OnIncomingCall
12
13
14
15
16
17
TApdVoIP Component 301
1
1
Reference Section
AudioInDevice
property
2
property AudioInDevice : string
This property is the DeviceName of the TApdVoIPTerminal object that will be used to
provide audio input. Audio input is usually provided through a microphone connected to
the mic jack of a sound card.
This property supports the Media options property editor, which filters media terminals
by type. See Audio and video device selection on page 295 for details.
7
8
9
10
11
12
13
14
15
16
property
17
302 Chapter 9: IP Telephony
1
1
CallInfo
The TApdVoIP component contains properties for basic call information. TAPI maintains
much more information about the call. Although this information may be of limited use,
CallInfo is provided for projects that may require the extended information.
CallInfo is allocated immediately after the Connect method is called, is updated periodically
by TAPI, and is valid for the duration of the call.
CancelCall
3
4
method
procedure CancelCall;
7
8
9
10
11
12
13
14
15
16
17
1
1
Connect
method
2
3
4
5
6
7
When originating or receiving a call, the OnConnect event is generated when the VoIP call is
connected.
10
11
property Connected
12
This property is set to True when a connection is established (when the OnConnect event is
generated) and False when the connection is terminated (when the OnDisconnect event is
generated). This property can be used to determine whether a call is in progress or not.
13
14
15
event
The Connect method begins a background process that can take some time before actually
establishing a connection. The OnConnect event is generated when a VoIP call is actually
connected.
1
1
When a VoIP call is originated, the OnConnect event is generated after the called station
accepts the call and the H.323 negotiations are complete. When Connect is called to answer
calls, the OnConnect event is generated after the OnIncomingCall event is generated and the
Accept parameter is set to True.
1
2
event
6
7
8
event
10
11
12
VoIP is the TApdCustomVoIP component that generated the event. ErrorCode is a non-zero
value indicating the type of failure.
14
15
13
16
17
TApdVoIP Component 305
1
1
OnIncomingCall
event
2
3
4
5
6
7
8
9
TApdVoIPIncomingCallEvent = procedure(
VoIP : TApdCustomVoIP; CallerAddr: string; var Accept : Boolean);
10
11
ShowMediaSelectDialog
method
! Displays a dialog where the audio and video devices can be selected.
12
13
14
The ShowMediaSelectDialog method displays the Media options dialog discussed in the
Audio and video device selection on page 295. This dialog box allows the user to select the
media terminals for the AudioInDevice, AudioOutDevice, and VideoInDevice properties.
If OK is clicked, the AudioInDevice, AudioOutDevice and VideoInDevice properties are
updated to reflect the new media terminals and the return value of ShowMediaSelectDialog
is True. If Cancel is clicked, the properties are not changed and this method returns False.
15
The dialog displayed from the ShowMediaSelectDialog method is the same dialog used for
the AudioInDevice, AudioOutDevice and VideoInDevice property editors.
16
17
306 Chapter 9: IP Telephony
1
1
VideoInDevice
property
This property is the DeviceName of the TApdVoIPTerminal object that will be used to
provide video input. Video input is usually provided through a digital camera or web
camera installed on the system.
This property supports the Media options property editor, which filters media terminals by
type. See Audio and video device selection on page 295 for details.
3
4
property
6
property VideoOutDevice : TWinControl
This property is a TWinControl descendent where the received video stream is displayed. To
display the received video stream, assign the name of a TWinControl descendent, such as a
TPanel, to the VideoOutDevice property.
VoIPAvailable
10
property VoIPAvailable : Boolean
11
The TApdVoIP component implements Voice over IP (IP Telephony) using TAPI 3.x and the
H.323 TAPI service provider. TAPI 3.x is available for Windows 2000 and later, it is not
available for earlier versions of Windows. When the TApdVoIP component is created, the
TAPI version and H.323 TSP are verified, if these TAPI components are not available the
VoIPAvailable property is set to False; if these TAPI components are available the
VoIPAvailable property is set to True.
12
13
If VoIPAvailable is False, calling the Connect method will raise the EVoIPNotSupported
exception.
14
15
16
17
TApdVoIP Component 307
1
1
WaitingForCall
! Indicates whether the TApdVoIP component is waiting for incoming calls or not.
When the Connect method is called with an empty string, the TApdVoIP component will
begin monitoring for incoming calls. WaitingForCall indicates whether the TApdVoIP
component is waiting for incoming calls or not.
5
6
7
8
9
10
11
12
13
14
15
16
17
308 Chapter 9: IP Telephony
1
1
1
2
The SAPI (Speech API) components in Async Professional provide an easy means to
incorporate speech synthesis and recognition into your programs. The components act as
an interface between the Microsoft SAPI 4 and Delphi and C++ Builder.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
309
1
1
SAPI Overview
Async Professional provides speech synthesis, speech recognition and voice telephony
capabilities. These aspects will be explored in further in the following sections.
Speech synthesis
Speech synthesis will take plain ASCII text and convert it to into digital audio. There are
three primary ways this is done as described in Table 10.1.
Scheme
Description
Concatenated Word
Subword Concatenation
Synthesis
7
8
9
10
11
12
13
14
15
16
17
1
1
You can verify if an engine supports IPA by checking if tfIPAUnicode is in the features set of
the engine. This can be found in the Features subproperty of the SSVoices property of the
TApdSapiEngine component.
1
2
Speech recognition
Speech recognition converts a spoken audio data stream into ASCII text. In Async
Professional, generic speech recognition is provided through the TApdSapiEngine
component.
Speech recognition requires an object known as a grammar (a list of known words and
possibly how they relate to each other). In Async Professional, the grammar is handled
automatically. Either a list of expected words can be provided in the WordList property, or
the Dictation property can be set to True. In the latter case, the speech synthesis engine will
be provided with a dictation grammar. Most speech recognition engines will then use a
much larger list of known words. Additional words can be specified via the WordList
property.
Using a specific word list is generally faster and more accurate than using the full dictation
grammar.
As words and phrases are recognized the OnPhraseHypothesis and OnPhraseFinish events
will fire to let the application know what words were spoken.
The Microsoft SAPI SDK documentation provides a full list of supported phonemes.
3
4
6
7
8
9
10
Voice telephony
Voice telephony support is provided via the TApdSapiPhone component. This component
allows for speech synthesis and recognition to take place over a voice call. The component is
a descendent of the TApdCustomTAPIDevice and provides all the functionality of a TAPI
based voice call with the capabilities of the TApdCustomSapiEngine.
The voice telephony component has several methods for asking the user for information and
then returning that information in a usable format. For example, the AskForDate method
will prompt the user for a date and then return that date as a TDateTime parameter. Other
methods exist for asking for phone numbers, times, items from a list, extensions and yes or
no replies.
11
12
13
14
15
16
17
1
1
A 486/33 (DX or SX) or better CPU is the bare minimum required. A Pentium is
recommended.
Speech synthesis will require an additional 1Mb of RAM to that which your program
already needs. Speech recognition will require an additional 8Mb.
4
5
6
7
8
9
10
11
12
A sound card is needed for both speech synthesis and recognition. For speech
recognition, a microphone is required. Headset microphones are less susceptible to
background noise and are preferable to desktop microphones.
For voice telephony, you will need TAPI, a voice capable modem and speech synthesis
and recognition engines that have been optimized for telephony applications.
13
14
Feedback between sound cards output and the microphone can dramatically reduce the
quality of the spoken text.
16
Background noise will also affect the speech recognition. Background conversations, a
radio, door slams or other ambient noise can be picked up by the speech recognition engine
and interpreted in unexpected ways. The use of a higher quality microphone can reduce the
problems, but will not completely eliminate them.
17
Speech recognition is not perfect. Words will be misinterpreted, or not interpreted at all.,
and background noise will be interpreted as words.
15
1
1
There are numerous things that should be taken into account when developing voiceenabled applications. Here are a few items to keep in mind:
Speech recognition does make mistakes. If you are using speech recognition to handle
commands to your application, you will want confirmation before doing anything
that may be harmful.
Speech synthesis should be used for short phrases. Computer generated voices can
In voice telephony, other options should be provided for when speech recognition
fails. DTMF is usually a good backup option.
Mixing prerecorded text with synthesized speech generally sounds bad. As a rule,
either prerecord everything or nothing.
6
7
8
Visual feedback should be provided for both speech recognition and synthesis.
9
10
11
12
13
14
15
16
17
SAPI Overview 313
1
1
TApdAudioOutDevice Class
3
4
5
6
The properties of this class are laid out as arrays in which each speech recognition engine is
accessed by its index in the array. The CurrentEngine property is used to set the speech
recognition engine. Setting this property to the index of a speech recognition engine will
activate that engine.
Hierarchy
TObject (VCL)
TApdAudioOutDevice (AdSapiEn)
Properties
8
9
10
11
12
Age
Features
ModeName
Count
Gender
ProductName
CurrentVoice
Interfaces
Speaker
Dialect
LanguageID
Style
EngineFeatures
MfgName
EngineID
ModeID
Methods
Find
13
14
15
16
17
314 Chapter 10: SAPI Components
1
1
Reference Section
Age
1
read-only, run-time property
2
property Age[x : Integer] : TApdTTSAge
TApdTTSAge = (tsBaby, tsToddler, tsChild,
tsAdolescent, tsAdult, tsElderly, tsUnknown);
The Age property indicates the age of the voice currently specified . The following table
indicates values for Age:
Value
Approximate Age
tsBaby
tsToddler
tsChild
tsAdolescent
14
tsAdult
20 - 60
tsElderly
Over 60
tsUnknown
Unknown
6
7
8
9
The index of the array indicates the voice that the property refers to. To get the Age property
for the currently active voice, use the CurrentVoice property as the index.
See also: CurrentVoice
Count
10
11
12
13
14
15
16
17
1
1
CurrentVoice
run-time property
property CurrentVoice
This property is used to activate a specific voice for use in speech synthesis. This value
should be set between 0 and Count 1. This property should not be modified while text is
being spoken.
Dialect
6
7
The index of the array indicates the voice that the property refers to. To get the Dialect
property for the currently active voice, use the CurrentVoice property as the index.
10
EngineFeatures
11
! Indicates speech synthesis engine specific features for the specified voice.
12
This property specifies features specific to the speech synthesis engine. The meaning of the
value of this property will depend on the speech synthesis engine.
13
The index of the array indicates the voice that the property refers to. To get the
EngineFeatures property for the currently active voice, use the CurrentVoice property as the
index.
14
15
16
17
316 Chapter 10: SAPI Components
1
1
EngineID
This property identifies the GUID for the speech synthesis engine. This GUID may be used
for multiple voices and languages.
The index of the array indicates the voice that the property refers to. To get the EngineID
property for the currently active voice, use the CurrentVoice property as the index.
7
8
Feature
Description
tfAnyWord
10
tfFixedAudio
11
tfIPATextData
tfIPAUnicode
tfPCOptimized
13
tfPhoneOptimized
14
tfPitch
15
tfSAPI4
tfSingleInstance
12
16
17
1
1
Feature
Description
tfSpeed
tfTagged
tfThreadSafe
tfTransplanted
tfVisual
tfVolume
tfWordPosition
The index of the array indicates the voice that the property refers to. To get the Features
property for the currently active voice, use the CurrentVoice property as the index.
Find
method
10
! Finds the speech synthesis engine and voice that is the closest match for the input criteria.
11
This method is used to find the best matched speech engine and voice for the requested
features. The format of the Criteria parameter is:
<field>=<value>;<field=value>
12
13
Value
Age
Dialect
String
EngineFeatures
Integer
EngineId
String
14
15
16
17
1
1
Field
Value
Features
Gender
Interfaces
LanguageID
Integer
MfgName
String
ModeID
String
ModeName
String
ProductName
String
Speaker
String
Style
String
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
The index of the array indicates the speech synthesis voice that the property refers to. To get
the Interfaces property for the currently active speech synthesis voice, use the CurrentVoice
property as the index.
See also: CurrentVoice
14
15
16
17
320 Chapter 10: SAPI Components
1
1
LanguageID
Bits 0 through 9 indicate the primary language. Bits 10-15 indicate a sublanguage (or locale).
More information on this can be found in the Windows SDK help under the
MAKELANGID topic.
The index of the array indicates the speech synthesis voice that the property refers to. To get
the LanguageID property for the currently active speech synthesis voice, use the
CurrentVoice property as the index.
3
4
6
7
8
9
10
11
12
The index of the array indicates the speech synthesis voice that the property refers to. To get
the ModeID property for the currently active speech synthesis voice, use the CurrentVoice
property as the index.
13
14
15
16
17
TApdAudioOutDevice Class 321
1
1
ModeName
2
3
The index of the array indicates the speech synthesis mode that the property refers to. To get
the ModeName property for the currently active speech synthesis mode, use the
CurrentVoice property as the index.
6
property ProductName[x : Integer] : string
The index of the array indicates the speech synthesis voice that the property refers to. To get
the ProductName property for the currently active speech synthesis voice, use the
CurrentVoice property as the index.
10
property Speaker[x : Integer] : string
11
12
13
The index of the array indicates the speech synthesis voice that the property refers to. To get
the Speaker property for the currently active speech synthesis voice, use the CurrentVoice
property as the index.
14
15
16
17
322 Chapter 10: SAPI Components
1
1
Style
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdAudioOutDevice Class 323
1
1
TApdAudioInDevice Class
3
4
5
6
The properties of this are laid out as arrays in which each speech synthesis engine is accessed
by its index in the array. The CurrentVoice property is used to set the speech synthesis
engine. Setting this property to the index of a speech synthesis engine will activate that
engine.
Hierarchy
TObject (VCL)
7
8
9
10
11
TApdAudioInDevice (AdSapiEn)
Properties
Count
Grammars
ModeID
CurrentEngine
Interfaces
ModeName
Dialect
LanguageID
ProductName
EngineFeatures
MaxWordsState
Sequencing
EngineID
MaxWordsVocab
Features
MfgName
12
13
14
15
16
17
324 Chapter 10: SAPI Components
1
1
Reference Section
Count
1
read-only, run-time property
2
property Count : Integer
The engines are numbered from 0 to Count 1. The properties of the speech recognition
engines are accessed as an array where the index indicates the engine in question.
The active speech recognition engine can be activated by setting the CurrentEngine
property.
See also: CurrentEngine
CurrentEngine
run-time property
6
7
Dialect
10
! Indicates the dialect of the specified language used by the speech recognition engine.
Examples of dialects are Texas or New York City. The allowed dialects vary from engine
to engine.
11
12
13
14
15
16
17
TApdAudioInDevice Class 325
1
1
EngineFeatures
! Indicates speech recognition engine specific features for the specified engine.
The meaning of the value of this property will depend on the speech recognition engine.
3
4
The index of the array indicates the speech recognition engine that the property refers to. To
get the EngineFeatures property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
See also: CurrentEngine
5
6
EngineID
This property identifies the GUID for the speech recognition engine. This GUID may be
used for multiple voices and languages.
The index of the array indicates the speech recognition engine to which the property refers.
To get the EngineID property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
See also: CurrentEngine
10
11
12
13
Features
1
1
The following table details the meanings of the more common engine features:
Feature
Description
sfAnyWord
sfFixedAudio
sfGramLink
sfGramList
sfGramRecursive
sfIndepMicrophone
sfIndepSpeaker
sfIPAUnicode
sfMultiLingual
sfPCOptimized
sfPhoneOptimized
sfSAPI4
11
sfSingleInstance
12
sfThreadSafe
sfTrainPhonetic
sfTrainWord
sfWildcard
10
13
14
15
16
17
1
1
The index of the array indicates the speech recognition engine that the property refers to. To
get the Features property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
Grammars
4
5
6
7
8
Description
sgCFG
Context-free grammar
sgDictation
Dictation grammar
sgLimitedDomain
Limited-domain grammar
9
10
The index of the array indicates the speech recognition engine that the property refers to. To
get the Grammars property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
See also: CurrentEngine
11
12
13
14
15
16
17
328 Chapter 10: SAPI Components
1
1
Interfaces
2
3
4
LanguageID
! Specifies the language identifier for the specified speech recognition engine.
Bits 0 through 9 indicate the primary language. Bits 10-15 indicate a sublanguage (or locale).
More information on this can be found in the Windows SDK help under the
MAKELANGID topic.
The index of the array indicates the speech recognition engine that the property refers to. To
get the LanguageID property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
10
11
12
13
14
! Indicates the maximum number of words in any grammar state for the specified engine.
The index of the array indicates the speech recognition engine that the property refers to. To
get the MaxWordsState property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
15
16
17
TApdAudioInDevice Class 329
1
1
MaxWordsVocab
! Indicates the maximum number of words in a grammar for the specified speech recognition
engine.
3
4
The index of the array indicates the speech recognition engine that the property refers to. To
get the MaxWordsVocab property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
See also: CurrentEngine
5
6
7
8
9
10
MfgName
property MfgName[x : Integer] : string
! Indicates the name of the manufacturer of the specified speech recognition engine.
The index of the array indicates the speech recognition engine that the property refers to. To
get the MfgName property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
See also: CurrentEngine
ModeID
property ModeID[x : Integer] : string
12
The index of the array indicates the speech recognition engine that the property refers to. To
get the ModeID property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
See also: CurrentEngine
14
15
16
17
330 Chapter 10: SAPI Components
11
13
ModeName
This is the default property of the TApdAudioInDevice class. Specifying an array index
without any further field specifications will return this property.
The index of the array indicates the speech recognition engine that the property refers to. To
get the ModeName property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
3
4
6
property ProductName[x : Integer] : string
The index of the array indicates the speech recognition engine that the property refers to. To
get the ProductName property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
Sequencing
10
property Sequencing[x : Integer] : TApdSRSequences
TApdSRSequences = (ssDiscrete, ssContinuous, ssWordSpot,
ssContCFGDiscDict, ssUnknown);
11
12
13
14
15
16
17
1
1
The supported speech recognition schemes are detailed in the following table:
Scheme
Meaning
ssContCFGDiscDict
ssContinuous
ssDiscrete
ssWordSpot
5
6
The index of the array indicates the speech recognition engine that the property refers to. To
get the Sequencing property for the currently active speech recognition engine, use the
CurrentEngine property as the index.
8
9
10
11
12
13
14
15
16
17
332 Chapter 10: SAPI Components
1
1
TApdCustomSapiEngine Component
The speech recognition and synthesis engines are automatically initialized at the time of
creation.
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdCustomSapiEngine Component 333
1
1
Some speech synthesis engines support tags that allow for the changing of characteristics of
the spoken text while it is being spoken.
All tags begin and end with a backslash. Tags are case insensitive, but white space is
significant. To include a backslash in the text, use a double backslash.
The text This is a would be spoken using the Business character and the word test would
be spoken in a monotone.
The tags for the speech synthesis engine are defined in Table 10.2.
7
8
Meaning
Chr
Com
Ctx
Dem
Emp
9
10
11
12
13
14
15
16
17
334 Chapter 10: SAPI Components
1
1
Tag
Meaning
Enq
Mrk
Pau
Pit
2
3
4
Pra
Prn
Pro
Prt
RmS
RmW
9
10
11
12
13
14
15
16
17
1
1
Meaning
RPit
RPrn
RSpd
Rst
Spd
Vce
Vol
8
9
10
11
12
Hierarchy
13
14
TWinControl (VCL)
TApdBaseWinControl (OoMisc). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomSapiEngine (AdSapiEn)
15
16
17
336 Chapter 10: SAPI Components
1
1
TApdSapiEngine Component
2
3
Hierarchy
4
TWinControl (VCL)
! TApdBaseWinControl (OoMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdSapiEngine (AdSapiEn)
Properties
CharSet
SRAutoGain
Dictation
SREngines
SRAmplitude
SSVoices
TTSOptions
! Version
WordList
Methods
Listen
ShowGeneralDlg
SpeakFileToFile
PauseListening
ShowLexiconDlg
SpeakStream
PauseSpeaking
ShowTrainGeneralDlg
SpeakToFile
ResumeListening
ShowTrainMicDlg
StopListening
ResumeSpeaking
Speak
StopSpeaking
ShowAboutDlg
SpeakFile
10
11
12
13
Events
OnInterference
OnSpeakStop
OnSSError
OnPhraseFinish
OnSRError
OnSSWarning
OnPhraseHypothesis
OnSRWarning
OnTrainingRequested
OnSpeakStart
OnSSAttributeChanged
OnVUMeter
14
15
16
17
1
1
Reference Section
CharSet
property
2
property CharSet : TApdCharacterSet
csText indicates ASCII text, csIPAPhonetic indicates the International Phonetic Alphabet
and csEnginePhonetic indicates an engine specific phonetic alphabet.
Dictation
property
property Dictation
When dictation mode is on (provided the engine supports it), a larger set of words is used as
the base grammar. When it is off, only the words in the WordList property will be
recognized. Dictation mode may slow down speech recognition.
See Also: WordList
9
10
11
12
Listen
procedure Listen;
13
14
15
16
17
338 Chapter 10: SAPI Components
1
1
method
OnInterference
event
This event will fire when the audio input to the speech recognition less than optimal. The
InterferenceType parameter indicates how the input stream was damaged.
The possible values for OnInterference are shown in the following table:
Value
Meaning
itAudioStarted
itAudioStopped
itDeviceOpened
itDeviceClosed
itNoise
itTooLoud
itTooQuiet
itUnknown
9
10
11
12
13
14
15
16
17
1
1
OnPhraseFinish
event
2
3
4
TApdSRPhraseFinishEvent = procedure(
Sender : TObject; const Phrase : WideString) of object;
5
6
7
8
9
OnPhraseHypothesis
event
! Indicates when the user has finished speaking a phrase, but the speech recognition engine is
not positive on what was spoken.
The best guesss of what the user said will be indicated in the Phrase parameter. Multiple
words may be in this value.
See also: OnPhraseFinish
10
11
OnSpeakStart
event
12
13
14
event
15
! Defines an event handler for when the speech synthesis stops speaking.
16
This event will fire when the speech synthesis engine stops speaking to the default audio
device or finishes creating an audio file.
17
340 Chapter 10: SAPI Components
1
1
OnSRError
event
TApdOnSapiError = procedure(
Sender : TObject; Error : LongWord;
const Details : string; const Message : string) of object;
! Defines an event handler that is called when a speech recognition error occurs.
An error message was generated at some point during speed recognition. Error indicates the
error code generated by the speech recognition engine. Details provides additional details
about the error and Message provides the error messages as text.
OnSRWarning
event
TApdOnSapiError = procedure(
Sender : TObject; Error : LongWord;
const Details : string; const Message : string) of object;
! Defines an event handler that is called when a speech recognition warning occurs.
A warning message was generated at some point during speed recognition. Error indicates
the error code generated by the speech recognition engine. Details provides additional
details about the warning and Message provides the error messages as text.
OnSSAttributeChanged
event
9
10
11
12
13
14
15
16
17
1
1
OnSSError
event
2
3
4
TApdOnSapiError = procedure(
Sender : TObject; Error : LongWord; const Details : string;
const Message : string) of object;
! Defines an event handler that is called when a speech synthesis error occurs.
An error message was generated at some point during the speech synthesis. Error indicates
the error code generated by the speech synthesis. Details provides additional details about
the error and Message provides the error messages as text.
5
OnSSWarning
TApdOnSapiError = procedure(
Sender : TObject; Error : LongWord; const Details : string;
const Message : string) of object;
8
9
10
11
12
13
14
15
! Defines an event handler that is called when a speech synthesis warning occurs.
A warning message was generated at some point during the speech synthesis. Error indicates
the error code generated by the speech synthesis. Details provides additional details about
the warning and Message provides the error messages as text.
OnTrainingRequested
TApdSRTrainingRequestedEvent = procedure(
Sender : TObject; Training : TApdSRTrainingType) of object;
TApdSRTrainingType = set of (
ttCurrentMic, ttCurrentGrammar, ttGeneral);
17
342 Chapter 10: SAPI Components
event
16
event
OnVUMeter
event
TApdSRVUMeterEvent = procedure(
Sender : TObject; Level : Integer) of object;
This event provides a rough indicator of the volume of the spoken data heard by the speech
recognition engine. While the speech recognition engine is listening, this event will fire
approximately 8 times a second.
method
procedure PauseListening;
8
9
method
procedure PauseSpeaking;
10
11
! Pauses speaking.
12
13
ResumeListening
method
14
procedure ResumeListening;
15
16
17
TApdSapiEngine Component 343
1
1
ResumeSpeaking
method
procedure ResumeSpeaking;
ShowAboutDlg
method
5
6
7
8
9
10
11
12
13
15
16
17
344 Chapter 10: SAPI Components
method
14
method
ShowTrainGeneralDlg
method
This method will display the general training dialog box. This dialog allows the user to train
the speech recognition engine using a preselected set of words. The speech recognition
engine may request this dialog to be displayed via the OnTrainingRequested event.
method
7
8
9
Note: Not all speech recognition events will support this dialog.
10
method
11
12
13
If toTagged is specified in the TTSOptions property, the Text parameter can contain
embedded tags to control the behavior of the speech synthesis engine.
14
15
16
17
1
1
1
2
3
4
Normally, the speech synthesis engine will start speaking the text as soon as it passed into
one of the Speak methods (Speak, SpeakFile, SpeakFileToFile, SpeakStream, or
SpeakToFile). However, if PauseSpeaking has been called before one of the Speak methods,
the speaking will not occur until ResumeSpeaking is called.
StopSpeaking can be called at any time to halt the flow of speech. When StopSpeaking is
called, the text that is spoken and any text that is queued will not be spoken. Text that is
queued by using one of the Speak methods after the call to StopSpeaking will be spoken in
the usual fashion.
See also: CharSet, PauseSpeaking, ResumeSpeaking, SpeakFile, SpeakFileToFile,
SpeakStream, SpeakToFile, StopSpeaking, TTSOptions
5
SpeakFile
6
7
8
9
10
11
12
13
14
15
! Speaks the contents of the specified file to the default audio device.
Calling this method will cause the contents of the specified file to be read over the default
audio device.
Note: Reading binary files may cause unexpected behavior.
If toTagged is specified in the TTSOptions property, the Text parameter can contain
embedded tags to control the behavior of the speech synthesis engine.
The format of the Text parameter is controlled by the CharSet property.
The speech synthesis engine will store the text in a series of buffers. Since each buffer is
spoken independently, complete sentences should be passed to the speech synthesis engine.
Normally, the speech synthesis engine will start speaking the text as soon as it passed into
one of the Speak methods (Speak, SpeakFile, SpeakFileToFile, SpeakStream, or
SpeakToFile). However, if PauseSpeaking has been called before one of the Speak methods,
the speaking will not occur until ResumeSpeaking is called.
StopSpeaking can be called at any time to halt the flow of speech. When StopSpeaking is
called, the text that is spoken and any text that is queued will not be spoken. Text that is
queued by using one of the Speak methods after the call to StopSpeaking will be spoken in
the usual fashion.
See also: CharSet, PauseSpeaking, ResumeSpeaking, Speak, SpeakFileToFile, SpeakStream,
SpeakToFile, StopSpeaking, TTSOptions
16
17
346 Chapter 10: SAPI Components
1
1
method
SpeakFileToFile
method
This method will create an audio file named by the OutFile parameter containing the spoken
contents of the InFile parameter. The output file is formatted as xxxxxx.
6
7
8
9
10
11
SpeakStream
method
12
13
14
If toTagged is specified in the TTSOptions property, the Text parameter can contain
embedded tags to control the behavior of the speech synthesis engine.
15
16
17
1
1
1
2
3
4
Normally, the speech synthesis engine will start speaking the text as soon as it passed into
one of the Speak methods (Speak, SpeakFile, SpeakFileToFile, SpeakStream, or
SpeakToFile). However, if PauseSpeaking has been called before one of the Speak methods,
the speaking will not occur until ResumeSpeaking is called.
StopSpeaking can be called at any time to halt the flow of speech. When StopSpeaking is
called, the text that is spoken and any text that is queued will not be spoken. Text that is
queued by using one of the Speak methods after the call to StopSpeaking will be spoken in
the usual fashion.
See also: CharSet, PauseSpeaking, ResumeSpeaking, Speak, SpeakFile, SpeakFileToFile,
SpeakToFile, StopSpeaking, TTSOptions
5
SpeakToFile
6
7
8
9
10
11
12
13
14
15
16
17
348 Chapter 10: SAPI Components
1
1
method
SREngines
run-time property
! Lists the available text to speech engines and specifies the current engine.
SSVoices
run-time property
! Lists the available speech recognition engines and specifies the current engine.
StopListening
4
method
procedure StopListening;
This method will halt the speech recognition engine. If you call this method before calling
Listen, an error will be generated.
8
9
10
11
property
12
13
14
15
16
17
1
1
StopSpeaking
method
procedure StopSpeaking;
2
3
! Stops speaking.
StopSpeaking halts the flow of speech being generated by the speech synthesis engine. This
will also cancel any queued speech requests.
See also: Speak, PauseSpeaking, ResumeSpeaking
4
5
TTSOptions
property
6
7
8
property
9
10
11
12
13
14
15
16
17
350 Chapter 10: SAPI Components
1
1
TApdSapiPhonePrompts
Hierarchy
TPersistent (VCL)
TApdSapiPhonePrompts (AsSapiPh)
Properties
AskAreaCode
Help2
TooManyDigits
AskLastFour
Main
Unrecognized
AskNextThree
Main2
Where
Help
TooFewDigits
Where2
7
8
9
10
11
12
13
14
15
16
17
TApdSapiPhonePrompts 351
1
1
Reference Section
AskAreaCode
property
2
property AskAreaCode : string
3
4
5
6
7
8
AskLastFour
property
! Prompt for user to enter the last four digits of the phone number.
9
10
11
12
AskLastFour specifies the spoken prompt used to ask the user for the last four digits of their
phone number. AskForPhoneNumber and AskForPhoneNumberEx use this when the
speech recognition engine is unable to understand the full phone number. If the speech
recognition engine fails to recognize the full phone number, the user will first be prompted
for their area code using the AskAreaCode property, followed by the middle three digits of
the phone number using the AskNextThree property and finally the last four digits using the
prompt in the AskLastFour property.
See also: AskAreaCode, AskNextThree
13
14
15
16
17
352 Chapter 10: SAPI Components
1
1
AskNextThree
property
! Prompt for user to enter the middle three digits of the phone number.
AskNextThree specifies the spoken prompt used to ask the user for middle three digits of
their phone number. AskForPhoneNumber and AskForPhoneNumberEx use this when the
speech recognition engine is unable to understand the full phone number. If the speech
recognition engine fails to recognize the full phone number, the user will first be prompted
for an area code using the AskAreaCode property, followed by the middle three digits of the
phone number using the AskNextThree property and finally the last four digits using the
prompt in the AskLastFour property.
3
4
property
6
7
! Specifies help text that will be spoken if the user asks for help.
If the user asks for help during a call, first the text in the Help property will be spoken. If the
user asks for help a second time, the text in Help2 will be spoken.
Help2
property
10
! Specifies help text that will be spoken if the user asks for help a second time.
If the user asks for help during a call, first the text in the Help property will be spoken. If the
user asks for help a second time, the text in Help2 will be spoken.
See also: Help
11
12
13
14
15
16
17
TApdSapiPhonePrompts 353
1
1
Main
property
2
3
4
5
6
7
8
9
10
11
Main2
property Main2 : string
! Specifies the main prompt spoken to the user if the main prompt needs to be repeated.
Main2 is alternative and generally shorter text spoken if the main prompt should need to be
repeated. The contents of this property should reflect what the user is being asked for. If the
main prompt is repeated, the value in Main2 will be spoken instead of Main.
See also: Main
TooFewDigits
! Prompt spoken to the user if too few digits were specified for an extension.
See also: TooManyDigits
TooManyDigits
property TooManyDigits : string
! Prompt spoken to the user if too many digits were specified for an extension.
See also: TooFewDigits
14
15
16
17
354 Chapter 10: SAPI Components
1
1
property
12
13
property
property
Unrecognized
property
! Prompt spoken to the user to indicate the speech recognition engine did not understand
property
3
4
! Help text spoken to the user if they ask where they are.
The Where prompt is spoken in response when the user asks, Where Am I? If the user asks
where they are again, the text in Where2 will be spoken.
See also: Where2
Where2
6
property
! Help text spoken to the user if they ask where they are a second time.
If the user asks where they are again for a second time, the text in Where2 will be spoken.
10
11
12
13
14
15
16
17
TApdSapiPhonePrompts 355
1
1
TApdCustomSapiPhone Component
3
4
For this to work you will need a voice capable modem and speech synthesis and recognition
engines that have been optimized for telephone usage.
Note: Speech recognition may lag behind what is actually spoken. Setting the Dictation
property of the TApdCustomSapiEngine component to False helps with this, but the
operating system, modem type, amount of memory and other factors influence the speech
recognition lag.
" Caution: When dialing a voice call, the standard TAPI Service Provider will return that it is
7
8
9
10
11
12
13
14
connected as soon as it has dialed. This is a known problem in the standard TAPI Service
Provider provided with Windows.
Most SAPI calls consist of a series of questions for the user. These are handled by several
methods: AskForDate, AskForTime, AskForPhoneNumber and related methods. These
methods will prompt the user for some information and then collect the voice reply and
interpret the reply into a usable value.
The return code for the AskFor methods lets you know what the state of the call is. The reply
codes are detailed in Table 10.3. Several of these values are controlled by the Options
property.
Table 10.3: AskFor methods return codes
Return code
Description
prOk
prAbort
prNoResponse
prOperator
prHangUp
prBack
15
16
17
356 Chapter 10: SAPI Components
1
1
Return code
Description
prWhere
prHelp
prRepeat
prSpeakFaster
prSpeakSlower
prCheck
prError
prUnknown
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Hierarchy
TComponent
2
3
TApdBaseComponent (OoMisc). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomTapiDevice (AdTapi)
TApdCustomSapiPhone (AdSapiPh)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
358 Chapter 10: SAPI Components
1
1
TApdSapiPhone Component
2
3
Hierarchy
4
TComponent
! TApdBaseComponent (OoMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomTapiDevice (AdTapi)
TApdCustomSapiPhone (AdSapiPh)
TApdSapiPhone (AdSapiPh)
Properties
NoAnswerMax
Options
NoAnswerTime
Prompts
NumDigits
SapiEngine
! Version
8
9
Methods
10
AskForDate
AskForListEx
AskForTime
AskForDateEx
AskForPhoneNumber
AskForTimeEx
AskForExtension
AskForPhoneNumberEx
AskForYesNo
AskForExtensionEx
AskForSpelling
AskForYesNoEx
AskForList
AskForSpellngEx
Speak
11
12
13
14
15
16
17
1
1
Reference Section
AskForDate
method
2
3
4
5
6
7
8
function AskForDate(
var OutDate : TDateTime; var ParsedText : string;
NewPrompt1 : string) : TApdSapiPhoneReply;
TApdSapiPhoneReply = (prOk, prAbort, prNoResponse,
prOperator, prHangUp, prBack, prWhere, prHelp, prRepeat,
prSpeakFaster, prSpeakSlower, prCheck, prError, prUnknown);
9
AskForDateEx
10
11
12
13
14
15
16
17
360 Chapter 10: SAPI Components
1
1
method
The user will be prompted for the date using the prompts passed into the method. These
prompts correspond to the values in the Prompts property. If a value is blank, then the value
from the corresponding prompt in the Prompts property will be used. If you only need to
override the main prompt, use the AskForDate method.
1
2
The date is returned in OutDate as a TDateTime. The date returned may be unreliable. If this
is the case, the method will return prCheck and the parsed text spoken by the user will be
returned in ParsedText.
AskForExtension
method
6
7
8
The user will be prompted for the telephone extension with the value in NewPrompt1. If this
value is blank, then the default main prompt in the Prompts property will be used. Other
prompts used in asking for the extension are obtained from the Prompts property. If you
want to override the prompts other than the main prompt, use the AskForExtensionEx
method.
10
The extension is assumed to be a series of digits and is returned as a string in the Extension
parameter.
11
12
13
14
15
16
17
TApdSapiPhone Component 361
1
1
1
2
3
4
5
AskForExtensionEx
Method
The user will be prompted for the telephone extension using the prompts passed into the
method. These prompts correspond to the values in the Prompts property. If a value is
blank, then the value from the corresponding prompt in the Prompts property will be used.
If you only need to override the main prompt, use the AskForExension method.
The extension is assumed to be a series of digits and is returned as a string in the Extension
parameter.
See also: AskForExtension, Prompts
AskForList
10
11
12
13
14
15
16
17
362 Chapter 10: SAPI Components
1
1
method
AskForListEx
method
6
7
8
9
AskForPhoneNumber
method
10
11
12
13
The user will be prompted for the phone number with the value in NewPrompt1. If this
value is blank, then the default main prompt in the Prompts property will be used. Other
prompts used in asking for the phone number are obtained from the Prompts property. If
you want to override the prompts other than the main prompt, use the
AskForPhoneNumberEx method.
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
If AskForPhoneNumber is unable to obtain the phone number, it will ask for the number in
pieces using the AskAreaCode, AskNextThree and AskLastFour prompts.
The phone number is returned as a string in the PhoneNumber property.
See also: AskForPhoneNumberEx, Prompts
AskForPhoneNumberEx
function AskForPhoneNumberEx(var PhoneNumber : string;
NewPrompt1 : string; NewPrompt2 : string;
NewAskAreaCode : string; NewAskNextThree : string;
NewAskLastFour : string; NewHelp1 : string;
NewHelp2 : string; NewWhere1 : string;
NewWhere2 : string) : TApdSapiPhoneReply;
TApdSapiPhoneReply = (prOk, prAbort, prNoResponse,
prOperator, prHangUp, prBack, prWhere, prHelp, prRepeat,
prSpeakFaster, prSpeakSlower, prCheck, prError,
prUnknown);
12
13
14
15
16
17
364 Chapter 10: SAPI Components
1
1
method
AskForSpelling
method
function AskForSpelling(
var SpelledWord : string;
NewPrompt1 : string) : TApdSapiPhoneReply;
3
4
6
7
AskForSpellingEx
method
function AskForSpellingEx(
var SpelledWord : string; NewPrompt1 : string;
NewPrompt2 : string; NewHelp1 : string; NewHelp2 : string;
NewWhere1 : string; NewWhere2 : string) : TApdSapiPhoneReply;
TApdSapiPhoneReply = (prOk, prAbort, prNoResponse,
prOperator, prHangUp, prBack, prWhere, prHelp, prRepeat,
prSpeakFaster, prSpeakSlower, prCheck, prError,
prUnknown);
9
10
11
12
13
15
14
16
17
TApdSapiPhone Component 365
1
1
1
2
3
4
5
6
AskForTime
function AskForTime(
var OutTime : TDateTime; var ParsedText : string;
NewPrompt1 : string) : TApdSapiPhoneReply;
TApdSapiPhoneReply = (prOk, prAbort, prNoResponse,
prOperator, prHangUp, prBack, prWhere, prHelp, prRepeat,
prSpeakFaster, prSpeakSlower, prCheck, prError,
prUnknown);
The date is returned in OutTime as a TDateTime. The date returned may be unreliable. If
this is the case, the method will return prCheck and the parsed text spoken by the user will
be returned in ParsedText.
9
10
11
12
13
14
15
AskForTimeEx
method
function AskForTimeEx(
var OutTime : TDateTime; var ParsedText : string;
NewPrompt1 : string; NewPrompt2 : string; NewHelp1 : string;
NewHelp2 : string; NewWhere1 : string;
NewWhere2 : string) : TApdSapiPhoneReply;
TApdSapiPhoneReply = (prOk, prAbort, prNoResponse,
prOperator, prHangUp, prBack, prWhere, prHelp, prRepeat,
prSpeakFaster, prSpeakSlower, prCheck, prError,
prUnknown);
16
The date is returned in OutTime as a TDateTime. The date returned may be unreliable. If
this is the case, the method will return prCheck and the parsed text spoken by the user will
be returned in ParsedText.
17
method
AskForYesNo
method
function AskForYesNo(
var Reply : Boolean; NewPrompt1 : string) : TApdSapiPhoneReply;
TApdSapiPhoneReply = (prOk, prAbort, prNoResponse,
prOperator, prHangUp, prBack, prWhere, prHelp, prRepeat,
prSpeakFaster, prSpeakSlower, prCheck, prError,
prUnknown);
2
3
The user will be prompted for a yes or no reply using the value in NewPrompt1. If this value
is blank, then the default main prompt in the Prompts property will be used. Other prompts
used in asking for the yes or no reply are obtained from the Prompts property. If you want to
override the prompts other than the main prompt, use the AskForYesNoEx method.
The date is returned in the Reply parameter as a Boolean. A value of True indicates yes and a
value of False indicates no.
See also: AskForYesNoEx, Prompts
AskForYesNoEx
method
function AskForYesNoEx(
var Reply : Boolean; NewPrompt1 : string;
NewPrompt2 : string; NewHelp1 : string;
NewHelp2 : string; NewWhere1 : string;
NewWhere2 : string) : TApdSapiPhoneReply;
6
7
8
9
10
11
12
13
The date is returned in the Reply parameter as a Boolean. A value of True indicates yes and a
value of False indicates no.
15
16
14
17
TApdSapiPhone Component 367
1
1
NoAnswerMax
property
2
3
! Specifies the number of times the user can not answer a prompt before returning an error.
This is used by the AskFor methods. If there is no answer, these methods will return
prNoResponse.
See also: NoAnswerTime
4
5
NoAnswerTime
property
This is used by the AskFor methods. If the user does not reply in NoAnswerTime seconds
NoAnswerMax times, the prNoResponse error will be returned by the method.
NumDigits
property
! Specifies the number of digits in the extension asked for by AskForExtension and
AskForExtensionEx.
10
Options
11
12
13
14
15
16
17
368 Chapter 10: SAPI Components
1
1
property
Various options can be enabled for a SAPI call. These are detailed in the following table:
Option
Meaning
psVerify
psCanGoBack
psDisableSpeedChange
psEnableOperator
psEnableAskHangup
psFullDuplex
Prompts
property
6
7
8
9
! Specifies the default spoken prompts used in getting information from the user.
SapiEngine
property
10
11
12
method
13
14
15
16
17
TApdSapiPhone Component 369
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
370 Chapter 10: SAPI Components
1
1
1
2
Async Professional provides two RAS components that make it easy to add RAS dialing
capability to your application. RAS dialing is performed via the Microsoft RAS API.
The TApdRasDialer provides an easy to use interface to the Microsoft Remote Access
Services API to establish a connection to another computer via Dialup Networking. In
addition, the component also provides a set of standard functions for manipulating
phonebook entries and displaying dial status information.
The TApdRasStatus component provides a dialing status dialog for use on machines whose
RAS DLL does not provide a status display.
Overview
Remote Access Services (RAS) is the Windows service that handles dial-up networking
connections via modem. RAS is installed by default on most Win9x machines. On NT
machines, however, RAS is not installed until you add a modem device to the system
configuration. On Windows 9x/ME, dialup-networking automatically starts when an
application attempts to connect to a remote machine. Under Windows NT, however, this
does not occur and its up to the user to explicitly dial with RAS.
7
8
9
10
11
12
13
14
15
16
17
371
1
1
TApdRasDialer Component
The TApdRasDialer provides an interface to Microsofts Remote Access Service (RAS) API.
The component is used primarily to establish and terminate a connection to a remote
machine using Windows dial-up networking, however it can also be used to manipulate
RAS phonebook entries and enumerate active connections.
3
4
5
6
7
8
9
The TApdRasDialer requires that RAS has been installed on the machine that the
application is to be run. If RAS is not installed, then an exception ecRasLoadFail is raised
whenever a TApdRasDialer function is called.
Dialing is performed by the Dial and DialDlg (WinNT) methods. Both asynchronous and
synchronous dialing options are available with Dial. The Hangup method terminates the
call. Phonebook entries are manipulated by the CreatePhonebookEntry,
EditPhonebookEntry, ListEntries, and PhonebookDlg (WinNT) methods. The dialing
parameters for a particular call can be obtained and by the GetDialParameters, and
SetDialParameters methods. For WinNT machines, a monitor can be displayed by
MonitorDlg to display the status of RAS connections.
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
10
11
TApdCustomRasDialer (AdRas)
TApdRasDialer (AdRas)
12
13
14
15
16
17
372 Chapter 11: Remote Access Service (RAS) Components
1
1
Properties
CallBackNumber
DialOptions
PlatformID
CompressionMode
Domain
SpeakerMode
Connection
EntryName
StatusDisplay
ConnectState
HangupOnDestroy
UserName
DeviceName
Password
DeviceType
Phonebook
DialMode
PhoneNumber
! Version
2
3
4
Methods
CreatePhonebookEntry
GetDialParameters
ListEntries
DeletePhonebookEntry
GetErrorText
MonitorDlg
Dial
GetStatusText
PhonebookDlg
DialDlg
Hangup
SetDialParamters
EditPhonebookEntry
ListConnections
6
7
8
Events
OnConnected
OnDialStatus
OnDialError
OnDisconnected
9
10
11
12
13
14
15
16
17
TApdRasDialer Component 373
1
1
Reference
CallBackNumber
property
2
property CallBackNumber : string
An empty string indicates that callback should not be used. This string is ignored unless the
user has Set By Caller callback permission on the RAS server. An asterisk indicates that
the number stored in the phonebook should be used for callback.
CompressionMode
property
6
7
8
TApdRasCompressionMode = (
cmDefault, cmCompressionOn, cmCompressionOff);
9
10
! Contains the RAS connection handle for the current phonebook entry.
This property is available if needed, but will probably not be of use to the user.
11
ConnectState
12
13
14
15
16
17
374 Chapter 11: Remote Access Service (RAS) Components
1
1
property
CreatePhonebookEntry
method
A dialog box is displayed in which the user enters the information for the new entry.
A return value other than ecOK indicates that an error occurred and the return value is the
error code. This value can then be passed to GetErrorText to obtain a description of the
error.
3
4
method
7
8
9
10
11
12
DeviceName contains the name of the current device, if available. This could be the name of
the modem, the name of the PAD, or the name of a switch device.
13
14
15
16
17
TApdRasDialer Component 375
1
1
DeviceType
! Contains the device type name for the current active connection.
DeviceType contains a string that identifies the type of the current device, if available.
Common device types supported by RAS remote access service are modem, pad,
switch, ison, or null.
Dial
method
6
7
8
9
10
11
12
13
14
15
16
17
376 Chapter 11: Remote Access Service (RAS) Components
1
1
DialDlg
method
If the application is not running under Windows NT, DialDlg will return a
ecFunctionNotSupported error.
DialDlg commences synchronous dialing and displays dialog boxes during the connection
operation to provide feedback to the user about the progress of the operation. The dialog
boxes also provide a Cancel button for the user to terminate the connection.
DialDlg returns when the connection is established, or when the user cancels the operation.
No progress events are fired so the function return value must be examined to determine the
status of the connection. A return value other than ecOK indicates that an error occurred
and the return value is the error code. This value can then be passed to GetErrorText to
obtain a description of the error. If a connection error occurs, the connection is
automatically hung-up.
6
7
Connection status information is also available via the ConnectState property until the
application calls HangUp to terminate the connection. An application must eventually call
HangUp after a connection has been successfully established.
DialMode
property
10
11
Default: dmAsync
12
13
14
15
16
17
TApdRasDialer Component 377
1
1
DialOptions
property
2
3
4
5
6
Domain
property Domain : string
An empty string specifies the domain in which the remote access server is a member. An
asterisk specifies the domain stored in the phonebook for the entry.
EditPhonebookEntry
11
A return value other than ecOK indicates that an error occurred and the return value is the
error code. This value can then be passed to GetErrorText to obtain a description of the
error.
See also: CreatePhonebookEntry, DeletePhonebookEntry, EntryName, GetErrorText
13
EntryName
14
15
property
16
17
378 Chapter 11: Remote Access Service (RAS) Components
method
10
12
property
GetDialParameters
method
The connection information saved by the last successful call to Dial or SetDialParameters
for the current phonebook entry is retrieved.
A return value other than ecOK indicates that an error occurred and the return value is the
error code. This value can then be passed to GetErrorText to obtain a description of the
error.
3
4
method
6
function GetErrorText(Error : Integer) : string;
Example:
with ApdRasDialer1 do
ShowMessage(GetErrorText(DialDlg));
10
method
11
12
! Returns the text string for the specified RAS connection state.
Use GetStatusText to obtain the text for a given RAS connection state.
13
Example:
14
with ApdRasDialer1 do
ShowMessage(GetStatusText(ConnectState));
15
16
17
TApdRasDialer Component 379
1
1
Hangup
method
procedure Hangup;
Hangup releases all RASAPI32.DLL resources associated with the connection. Hangup
must be called eventually if a connection has been made by calling either the Dial or DialDlg
methods. It is safe to call Hangup at any time during dialing.
HangupOnDestroy
property
Default: True
destroyed.
If an active RAS connection has been established by calling either Dial or DialDlg, a
connection handle is maintained for the duration of the call and must be used to hangup the
call. By default, when the dialing application terminates, it will disconnect an active
connection since the connection handle is not saved. By setting HangupOnDestroy to True,
you can override this behavior and allow the connection to remain open when the
application closes.
ListConnections
method
Use ListConnections to obtain a string list of all active RAS connections. The List argument
must be created before calling the function. Upon return, the List.Strings property contains
the entry names of the active connections. If List has not been created, an exception is
raised.
Example:
...
ComboBox1.Clear;
ApdRasDialer1.ListConnections(ComboBox1.Items);
A return value other than ecOK indicates that an error occurred and the return value is the
error code. This value can then be passed to GetErrorText to obtain a description of the
error.
17
380 Chapter 11: Remote Access Service (RAS) Components
1
1
ListEntries
method
Use ListEntries to obtain a string list of all entries in the current RAS phonebook. The List
argument must be created before calling the function. Upon return, the List.Strings
property contains the entry names contained in the phonebook. If List has not been created,
an exception is raised.
3
4
Example:
...
ComboBox1.Clear;
ApdRasDialer1.ListEntries(ComboBox1.Items);
...
ApdRasDialer1.EntryName :=
ComboBox1.Items[ComboBox1.ItemIndex];
...
6
7
A return value other than ecOK indicates that an error occurred and the return value is the
error code. This value can then be passed to GetErrorText to obtain a description of the
error.
MonitorDlg
method
10
! Displays the status of a connection using the Ras status dialog (WinNT).
Use MonitorDlg to display a a dialog showing the status of a connection. This is the same
dialog box you see if you right-click the Dial-Up Networking Monitor application in NTs
system tray.
A return value other than ecOK indicates that an error occurred and the return value is the
error code. This value can then be passed to GetErrorText to obtain a description of the
error.
11
12
13
14
15
16
17
TApdRasDialer Component 381
1
1
OnConnected
event
! Defines an event handler that is called when a RAS connection has been established.
3
4
During synchronous dialing (DialMode = dmSync), this event is not used and the
ConnectState property should be read to determine if a connection has been established.
See also: ConnectState, Dial, DialDlg, DialMode
6
7
8
OnDialError
event
! Defines an event handler that is called when an error occurs during dialing.
9
10
11
12
13
14
15
16
17
382 Chapter 11: Remote Access Service (RAS) Components
1
1
OnDialStatus
event
TApdRasStatusEvent = procedure(
Sender : TObject; State : TRasConnState) of object;
The State parameter may be passed to GetStatusText to obtain the corresponding text string.
Connection state constants are defined in ADRASUTL.PAS
event
7
8
9
10
property
11
12
Password is used to authenticate the users access to the remote access server.
13
14
15
16
17
TApdRasDialer Component 383
1
1
Phonebook
property
For applications running under Windows NT, Phonebook can be an empty string, and
typically is, in which case the default phonebook file RASPHONE.PBK is used.
For applications running under Windows 95/98, Phonebook is ignored. Dial-up networking
stores phonebook entries in the registry rather than in a phonebook file.
PhonebookDlg
method
6
7
8
9
10
11
12
An empty string indicates that the phonebook entrys phone number should be used. If
EntryName contains an empty string, PhoneNumber must contain a phone number to dial.
13
14
15
16
17
384 Chapter 11: Remote Access Service (RAS) Components
1
1
property
PlatformID
Operating System
VER_PLATFORM_WIN32_WINDOWS
Windows 95/98/ME
VER_PLATFORM_WIN32_NT
Windows NT
3
4
SetDialParameters
method
7
8
9
property
10
11
! Specifies the modem speaker setting for the current phonebook entry.
For applications not running under Windows NT, this property is ignored.
12
13
14
15
16
17
1
1
StatusDisplay
property
UserName
property UserName : string
8
9
10
11
12
13
14
15
16
17
386 Chapter 11: Remote Access Service (RAS) Components
1
1
property
TApdRasStatus Component
The TApdRasStatus provides a standard RAS dialing status dialog with a Cancel button to
abort dialing at any time. To use it, just create an instance and assign it to the StatusDisplay
property of your TApdRasDialer component.
TApdRasStatus has no methods that you must call or properties that you must adjust. You
might want to change the settings of the Ctl3D and Position properties to modify the
appearance and placement of the window.
3
4
Figure 11.1 shows the display that is associated with a TApdRasStatus component.
6
7
Figure 11.1: TApdRasStatus component display.
Hierarchy
TComponent (VCL)
TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
10
TApdCustomRasStatus (AdRas)
TApdRasStatus (AdRStat)
11
12
13
14
15
16
17
TApdRasStatus Component 387
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
388 Chapter 11: Remote Access Service (RAS) Components
1
1
1
2
3
4
TAPI also provides a smaller, though much more visible, service in managing modems as
system devices. This is a tremendous boon to communications programmers. No longer do
communications applications need to search serial ports for modems, try to identify
modems, burden the user with questions about their modem, or try any of the other
traditional approaches to supporting modems. Under TAPI, that task is handled by the
operating system. Programs make a few simple TAPI calls to determine what modems are
available.
5
6
7
Another advantage of TAPI is that applications can share serial ports. For example, assume
that an application opens a TAPI device to accept incoming fax or data calls. A second
application, if it also uses TAPI, can safely open the same TAPI device for an outgoing call.
When the outgoing call is over, TAPI resumes monitoring incoming calls without any
further action required by either application.
8
9
The TAPI components do have some drawbacks. TAPI may not be installed, or properly
configured, on all operating systems. TAPI relies upon several device drivers and INF files to
properly configure the modems. If these supporting files are not present, or if they are not
adequate, TAPI operations may fail or behave erratically. Consider making a data
connection through TAPI; if the wrong modem driver is selected for an installed modem,
TAPI could configure the modem to a state where it is incompatible with the remote device.
The modem driver may also be written poorly, most notably by not requiring responses to
modem commands.
10
11
12
13
The second major disadvantage of TAPI is that it doesnt provide the level of visibility or
control that is provided by TAdModem. TAdModem provides more detailed status
information and more control over failures such as no dialtone and called number busy
conditions. It is also much easier to customize TAdModem to provide unique
configurations.
14
15
The third major disadvantage of TAPI is that TAPI doesnt provide support for direct,
modemless connections. TAPI applications usually must still include logic for the direct
opening of serial ports.
16
17
389
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
The fourth major disadvantage of TAPI is the difficulty of assuring proper modem
configuration. TAPI modems are detected and installed by Windows during the installation
process. If a new modem is added later, the instructions provided with the modem usually
direct the user to run one of the Control Panel applets Add New Hardware or Modems.
The Add New Hardware applet found in Windows scans all available serial ports for
attached modems. When it finds a modem, it sends a variety of commands to the modem
and compares the responses against a large database of known modems, usually resulting in
an unambiguous choice. The Modems applet (or a setup program provided by the
modem vendor), can skip this detection process if the modem type is already known.
No matter how the modem is installed, the end result is that TAPI now knows everything it
needs to about that modem (serial port, baud rate, and the specific configuration
commands/responses). Property sheets are available to the user for changing the
configuration of the modem. For example, the user can turn the speaker on or off, change
the attached serial port, enable/disable flow control, and so on.
The default property values for the modem chosen by Microsoft or the modem vendor are
the values that provide the best results in the widest variety of situations. These properties,
however, are available to the user via the Modem applets modem property sheets. If the user
changes a critical value (say, the serial port number or perhaps flow control) its likely that
your application wont operate properly when using that modem. Unfortunately, there isnt
much you can do to protect against this. The responsibility for assuring the modem is
properly configured is in the users hands, not the application.
The final major disadvantage of TAPI is that resources often do not get properly released
following an abnormal termination of an application using TAPI. To counter this problem,
TApdTapiDevice includes a TAPI crash recovery mechanism which will automatically detect
this situation and release TAPI resources.
All of these issues are likely to improve over time, making TAPI the choice for current and
future communications programs. The best recommendation at this point is to use TAPI for
applications targeted for Windows.
Async Professional provides components that make use of TAPI modem management.
These components provide an alternate to TAdModem for configuring modems and dialing
and answering calls. Async Professional negotiates for TAPI 1.4 in Windows applications.
Async Professional also supports TAPI 1.3 functions in 16-bit applications for Windows 3.1
and Windows for Workgroups, but those environments lack a general purpose modem
service provider, which renders most of the TAPI functions useless for serial
communications programs.
16
17
390 Chapter 12: TAPI Components
1
1
The Async Professional TAPI components provide all the services necessary for selecting
TAPI devices, dialing and answering calls, and receiving status information about TAPI calls
in progress. The TAPI system itself provides even more services. For more information
about TAPI, see the following sources:
1
2
TAPI Reference Manual, included with the TAPI SDK and with the Windows 95/98
4
SDK.
Create Communications Programs for Windows 95 with the Win32 Comm API,
Microsoft Systems Journal, 1994 #12 (December).
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Without TAPI, the TApdComPort component opens the physical serial port directly using
the appropriate Windows API call, which returns a handle to that port. The TApdComPort
then uses the handle to send and receive data and otherwise control the serial port.
Configuring, dialing or answering the modem requires sending explicit ATXxx commands
to the modem, interpreting the responses, and dealing with the myriad of differences among
currently available modems.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
With TAPI, a TApdComPort is still required, but it is not initially involved in establishing
the modem connectiona TApdTapiDevice is used for that purpose. The application calls
Dial to place an outgoing call or calls AutoAnswer to wait for an incoming call. TAPI sends
the appropriate ATXxx commands, interprets the responses, and establishes the modem
connection.
Once the connection is established, TAPIs role is essentially over. TAPI remains in charge of
the call until the modem connection is broken, but the TApdTapiDevice is not used again.
From this point on you use the TApdComPort to control the port and send/receive data, just
as if TAPI is not involved. The TApdComPort is automatically opened by the
TApdTapiDevice when the modem connection is established. Several TApdComPort
properties are updated with appropriate information from the TAPI device, notably Baud
and ComNumber.
When the modem connection is broken, TApdTapiDevice automatically closes the
associated TApdComPort. The TApdComPort cannot be used for input/output unless the
modem connection is re-established by the TAPI device or unless the program bypasses
TAPI and opens and uses the TApdComPort directly.
The TApdComPort property TapiMode determines whether the port is in charge of the
physical serial port or whether TAPI is in charge of the port:
TapiMode : TTapiMode;
TTapiMode = (tmNone, tmAuto, tmOn, tmOff);
17
392 Chapter 12: TAPI Components
1
1
TAPI events
TAPI dials outgoing calls and waits for incoming calls in the background. Applications are
informed of progress through a callback procedure. TApdTapiDevice installs a hidden
callback and translates these progress callbacks into the following VCL events:
OnTapiStatus
procedure(
CP : TObject; First, Last : Boolean; Device, Message,
Param1, Param2, Param3 : DWORD) of object;
Generated at various intervals while dialing an outgoing call or answering an incoming call.
The parameters mirror the parameters passed directly to the TAPI callback. You will usually
need to reference only the Message and Param1 fields. The other fields are supplied for
applications that extend the services provided by TApdTapiDevice. See the OnTapiStatus
event on page 425. Also see TAPI status processing on page 394.
OnTapiLog
6
7
Generated at the start and finish of each TAPI call (either outgoing or incoming) and at
various points during the call. See the OnTapiLog event on page 424. Also see TAPI
logging on page 397.
OnTapiPortOpen
procedure(CP : TObject) of object;
Generated immediately after TAPI has established a connection and has the serial port
handle available for handoff to the TApdComPort component. See the OnTapiPortOpen
event on page 425.
OnTapiPortClose
8
9
10
11
12
Generated immediately after TAPI closes the serial port due to a broken connection. See the
OnTapiPortClose event on page 424.
13
OnTapiConnect
14
Generated immediately after TAPI establishes a connection. See the OnTapiConnect event
on page 393.
15
16
17
1
1
OnTapiFail
procedure(CP : TObject) of object;
Generated immediately after TAPI tries but fails to establish a connection. See the
OnTapiFail event on page 394.
TAPI handles the details of controlling, dialing, and answering the modem. The
OnTapiStatus event is provided to let you know whats happening as the connection
progresses.
5
6
7
8
9
10
11
12
13
14
15
16
17
TAPI actually uses a callback procedure to inform an application program of its progress.
TApdTapiDevice installs a hidden callback and translates all calls into OnTapiStatus events
for easier processing. The format of the event handler is identical to the internal TAPI
callback. The following illustrates the format and use of OnTapiStatus:
...
ApdTapiDevice1: TApdTapiDevice;
Msg: TLabel;
Num: TLabel;
...
procedure ApdTapiDevice1TapiStatus(
CP : TObject; First, Last : Boolean; Device, Message, Param1,
Param2, Param3 : LongInt);
end;
procedure TForm1.ApdTapiDevice1TapiStatus(
CP : TObject; First, Last : Boolean; Device, Message,
Param1, Param2, Param3 : LongInt);
begin
if First then
...do setup stuff
else if Last then
...do cleanup stuff
else begin
{Update status}
Msg.Caption := ApdTapiDevice1.TapiStatusMsg(Message, Param2);
Num.Caption := ApdTapiDevice1.Number;
end;
end;
1
1
The remaining parameters mirror the parameters that TAPI sends to the hidden callback
procedure. Only Message and Param1 are used by TApdTapiDevice. The other parameters
are provided in case you extend TApdTapiDevice beyond making and answering calls.
Async Professional contains resource strings for all of the values of Message and Param1 that
TApdTapiDevice can generate. Most applications can simply pass those parameters to
TapiStatusMsg to return the appropriate string, as shown in the code above. If returning an
appropriate string is sufficient for your purposes, you can skip the following discussion of
the parameters. Only Message and Param1 are described in detail; the rest are mentioned
only briefly.
1
2
3
4
Message is a constant that describes the class of change since the previous OnTapiStatus
event. The possible values are shown in Table 12.1.
Table 12.1: Possible TAPI messages
TAPI Message
Value
Explanation
Line_CallState
Line_LineDevState
Line_Reply
12
Line_APDSpecific
32
The first three values are a subset of the possible TAPI messages. These are the only values
that dialing and answering generate. The final value, Line_APDSpecific isnt really a TAPI
status message. Its a pseudo state change that TApdTapiDevice generates to provide more
information about the progress of a call.
Line_CallState indicates that the progress of the call, what TAPI calls the state of the call,
changed. For example, the line was idle, but now it is dialing or the line was dialing but now
it is proceeding (the TAPI term for waiting for the connection).
7
8
9
10
11
12
Line_LineDevState indicates that the state of the device (modem, phone, or whatever)
changed. TApdTapiDevice dial/answer actions generate this message only to indicate that
the modem is ringing.
13
Line_Reply indicates that TAPI has accepted, but not necessarily completed, the requested
background. For example, it is generated just after a request to dial a number.
14
Line_APDSpecific is generated during periods when TAPI does not generate events, such as
after dialing and waiting for a connection, or when answering and waiting for a connection.
The primary purpose of Line_APDSpecific is to give the status event an opportunity to
update a timer.
15
16
17
1
1
1
2
3
Param1 provides additional information about Message. For example, when Message is
Line_CallState, Param1 contains a constant describing the change in state. Table 12.2 shows
the values of Param1 that are generated by TApdTapiDevice for each value of Message.
Table 12.2: Corresponding Param1 values to Message values
Param1 Value
Explanation
4
5
6
7
8
LineCallState_Idle
No call in progress.
LineCallState_Offering
Call starting.
LineCallState_Accepted
LineCallState_DialTone
Dialtone detected.
LineCallState_Dialing
LineCallState_Proceeding
LineCallState_RingBack
LineCallState_Busy
LineCallState_Connected
LineCallState_Disconnected
9
For Message = Line_DevState
10
LineDevState_Ringing
11
12
13
14
15
16
APDSpecific_RetryWait
APDSpecific_TAPIChange
These are only subsets of the possible values of Param1 for each of the Message states, but
they are the only values generated for the dial/answer actions performed by
TApdTapiDevice.
17
396 Chapter 12: TAPI Components
1
1
Other TApdTapiDevice properties can also be used in OnTapiStatus. Some examples are
Number, which contains the number just dialed, and SelectedDevice, which contains the
name of the TAPI device.
Async Professional includes a mechanism for providing automatic TAPI status display
without programming, through the StatusDisplay property of TApdTapiDevice:
The TApdAbstractTapiStatus class is described in more detail on page 440. For each
OnTapiStatus event, TApdTapiDevice checks whether StatusDisplay is assigned. If it is, the
UpdateDisplay method of StatusDisplay is called to update the display. TApdTapiDevice
then calls the OnTapiStatus event, if one is implemented.
When a TApdTapiDevice component is created, either dynamically or when dropped on a
form, it searches the form for a TApdAbstractTapiStatus instance and updates the
StatusDisplay property with the first one it finds. StatusDisplay is also filled in if a
TApdAbstractTapiStatus component is added to the form later. You can also change
StatusDisplay at design time or run time to point to a different TApdAbstractStatusDisplay
component.
TAPI logging
6
7
8
9
Dialing and answering calls is often an automated process. For example, an application
might automatically dial a list of numbers every night to upload or download the days
transaction files. Or, an application might serve a BBS-like role where customers dial in to
get the latest updated files or information.
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
The TApdTapiDevice provides an event that is ideal for logging automated dial or answer
applications. The OnTapiLog event provides an opportunity to log information about each
call. The information that is logged includes the time the call starts, the time it ends, and
additional information about events during the call (connected, busy/retry, and so on). This
example that handles the OnTapiLog event:
procedure TForm1.ApdTapiDevice1TapiLog(
CP : TObject; Log : TTapiLogCode);
var
HisFile : Text;
begin
...open HisFile
{Write the log entry}
with TapiDevice do begin
case Log of
ltapiNone : ;
ltapiCallStart :
WriteLn(HisFile, DateTimeToStr(Now), ' : call started');
ltapiCallFinish :
WriteLn(HisFile, DateTimeToStr(Now), ' :
call finished'^M^J);
ltapiDial :
WriteLn(
HisFile, DateTimeToStr(Now), ' : dialing ', Number);
ltapiAnswer :
WriteLn(HisFile, DateTimeToStr(Now), ' : answering');
ltapiConnect :
WriteLn(HisFile, DateTimeToStr(Now), ' : connected');
ltapiCancel :
WriteLn(HisFile, DateTimeToStr(Now), ' : cancelled');
ltapiDrop :
WriteLn(HisFile, DateTimeToStr(Now), ' : dropped');
ltapiBusy:
WriteLn(HisFile, DateTimeToStr(Now), ' : busy');
ltapiDialFail :
WriteLn(HisFile, DateTimeToStr(Now), ' : dial failed');
end;
end;
...close HisFile
end;
16
17
398 Chapter 12: TAPI Components
1
1
This example shows every possible logging value. The meanings of the various logging
conditions are described in Table 12.3.
Table 12.3: TAPI logging conditions
1
2
Logging Condition
Explanation
ltapiAccept
ltapiAnswer
ltapiBusy
ltapiCallFinish
ltapiCallStart
ltapiCancel
ltapiConnect
ltapiDial
ltapiDialFail
ltapiDrop
ltapiReceivedDigit
A call is always started with an ltapiCallStart event and finished with an ltapiCallFinish
event. There may be one or more other events in between. A typical dial operation might
generate the following sequence of log events:
ltapiCallStart
ltapiDial
ltapiBusy
ltapiDial
ltapiConnect
ltapiDrop
ltapiCallFinish
call started
number dialed
called number was busy
number re-dialed
a connection was established
the connection was dropped
the call is finished
3
4
10
11
12
13
14
15
16
17
1
1
1
2
3
4
The TApdTapiLog class is described in more detail on page 445. For each OnTapiLog event,
TApdTapiDevice checks whether TapiLog is assigned. If it is, the UpdateLog method of
TapiLog is called to update the log. TApdTapiDevice then calls the OnTapiLog event, if one
is implemented.
Making calls
TApdTapiDevice provides a method for placing outgoing calls. When Dial is called, TAPI
sends the appropriate modem configuration commands to the modem, then dials the
number passed to the Dial method.
9
10
11
12
13
14
15
16
The number passed to Dial should not contain any modem commands. It should contain
the telephone number to dial, exactly as it would be dialed from a telephone handset.
TApdTapiDevice generates OnTapiStatus events during the dialing process. If a connection
is not established, an OnTapiFail event is generated. If a connection is established, an
OnTapiConnect event is generated, the associated TApdComPort is opened, and the
OnTapiPortOpen event is generated.
Once the connection is established, the TApdTapiDevice is no longer directly used. All
subsequent port control and input/output operations use the TApdComPort. The exception
to this occurs when the call is terminated. The application should not simply close the
TApdComPort because that would not disconnect the modem connection. Instead, the
application must direct TAPI to close the connection by calling the CancelCall method of
TApdTapiDevice. The TApdTapiDevice then breaks the connection, closes the associated
TApdComPort, and generates the OnTapiPortClose event.
If a dial attempt fails due to a busy signal or other error, TApdTapiDevice can try the call
again. This is controlled by the MaxAttempts property, which determines how many times
Dial tries the call, and RetryWait, which determines how long (in seconds) Dial waits before
retrying a failed call.
17
400 Chapter 12: TAPI Components
1
1
Dialing example
This example demonstrates how to construct and use the TApdTapiDevice to dial a number.
This example includes a terminal window and emulator so that you can dial and log on to a
BBS or information service.
Create a new project, add the following components, and set the property values as
indicated in Table 12.4.
Component
Property
TApdComPort
TAdEmulator
TAdTerminal
TApdTapiDevice
SelectedDevice
TApdTapiStatus
TApdTapiLog
TButton
Name
Double-click on the Dial buttons OnClick event handler within the Object Inspector and
modify the generated method to match this:
procedure TForm1.DialClick(Sender : TObject);
begin
ApdTapiDevice1.Dial('1-847-262-6000');
end;
The phone number passed to Dial is the number of the U.S. Robotics BBS. Modify it if you
want to dial a different BBS or service. This method tells TAPI to initialize the modem and
dial the number.
Next, double-click on the Hangup buttons OnClick event handler within the Object
Inspector and modify the generated method to match this:
procedure TForm1.HangupClick(Sender : TObject);
begin
ApdTapiDevice1.CancelCall;
end;
This method cancels the dial operation, or hangs up the phone after the connection is
established.
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
Finally, double-click on the OnTapiPortOpen event handler within the Object Inspector and
modify the generated method to match this:
procedure TForm1.ApdTapiDevice1TapiPortOpen(Sender : TObject);
begin
ApdTerminal1.SetFocus;
end;
This event handler gives the focus to the terminal window as soon as TAPI establishes a
connection with the BBS.
This example is in the EXTAPID project in the \ASYNCPRO\EXAMPLES directory.
Answering calls
The process of answering the modem is very similar to dialing. The TApdTapiDevice
component generates the same events as it does when dialing.
7
8
9
10
11
12
The TApdTapiDevice waits for incoming calls in the background. No events are generated
while waiting for calls. When an incoming call is detected, TApdTapiDevice begins
generating OnTapiStatus events at regular intervals. If a connection is not established, an
OnTapiFail event is generated. If a connection is established, an OnTapiConnect event is
generated, the associated TApdComPort is opened, and the OnTapiPortOpen event is
generated.
Once the connection is established, the TApdTapiDevice is no longer directly used. All
subsequent port control and input/output operations use the TApdComPort. The exception
to this occurs when the call is terminated. The application should not simply close the
TApdComPort because that would not disconnect the modem connection. Instead, the
application must direct TAPI to close the connection by calling the CancelCall method of
TApdTapiDevice. The TApdTapiDevice then breaks the connection, closes the associated
TApdComPort, and generates the OnTapiPortClose event.
Answering example
13
The following example demonstrates how to construct and use the TApdTapiDevice to
answer an incoming call.
14
15
16
17
402 Chapter 12: TAPI Components
1
1
Create a new project, add the following components, and set the property values as
indicated in the Table 12.5.
Table 12.5: Example components and property values
Component
Property
1
2
Value
TApdComPort
TAdEmulator
TAdTerminal
TApdTapiDevice
SelectedDevice
TButton
Name
Answer
TButton
Name
Hangup
TApdTapiStatus
TApdTapiLog
6
7
Double-click on the Answer buttons OnClick event handler within the Object Inspector and
modify the generated method to match this:
procedure TForm1.AnswerClick(Sender : TObject);
begin
ApdTapiDevice1.AutoAnswer;
end;
AutoAnswer instructs TAPI to listen for incoming calls. It does not immediately begin
answering an incoming call. In fact, if an incoming call is ringing before you call
AutoAnswer, AutoAnswer will most likely not pick up that call. This happens because TAPI
alerts applications of an incoming call on the first ring of that call. If no applications are
listening at that point, TAPI does not attempt to answer the call.
Next, double-click on the Hangup buttons OnClick event handler within the Object
Inspector and modify the generated method to match this:
procedure TForm1.HangupClick(Sender : TObject);
begin
ApdTapiDevice1.CancelCall;
end;
This method tells TAPI to stop listening for incoming calls. If a call is in the process of being
answered, it is aborted immediately. If a connection was already established, it is
disconnected.
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
Finally, double-click on the OnTapiPortOpen event handler within the Object Inspector and
modify the generated method to match this:
procedure TForm1.ApdTapiDevice1TapiPortOpen(Sender : TObject);
begin
ApdTerminal1.SetFocus;
end;
This event handler gives the focus to the terminal window as soon as TAPI establishes a
connection.
This example is in the EXTAPIA project in the \ASYNCPRO\EXAMPLES directory.
TAPI itself doesnt implement any of the features necessary for controlling serial ports and
telephony devices. The TAPI architecture dictates that the low-level, physical services are
provided by a TAPI Service Provider (TSP).
7
8
9
10
11
12
13
14
15
Even if TAPI is properly installed, it will not function unless a service provider is also
installed. TSP modules are typically provided by telephony vendors along with their
telephony hardware. Windows 95/98 and Windows NT 4.0 install a general-purpose service
provider named UNIMDM.TSP, which provides basic dial and answer support for modems.
It is this service provider that makes TAPI available to communications programs in
Windows.
Since UNIMDM.TSP is the service provider that your application is most likely to
encounter, its worth noting a few of its limitations here:
UNIMDM does not provide support for caller identification (caller ID). The CallerID
property of TApdTapiDevice always returns an empty string when using UNIMDM.
UNIMDM does not support no dialtone detection. TAPI will attempt to dial
whether a dialtone is detected or not.
Microsoft has released an extension for Unimodem called UNIMODEM/V.
UNIMODEM/V provides additional TAPI services (including support for caller ID and no
dialtone detection). As of this writing UNIMODEM/V is only for Windows 95/98.
UNIMODEM/V for Windows NT 4.0 is not available yet. See the README.TXT file for
updated news on UNIMDM supported services. You can also view the UNIMODEM/V
README.TXT file at http://support.microsoft.com/support/kb/articles/q140/3/23.asp.
" Caution: You cannot assume UNIMODEM/V is installed on your users machines since it
16
17
404 Chapter 12: TAPI Components
1
1
Although UNIMDM.TSP provides basic dial and answer services it does not provide all of
the modem services an application might need. UNIMDM.TSP cannot be used to place a
faxmodem in fax answer mode or in adaptive answer mode (in which both incoming fax
and incoming data calls are accepted).
However, TAPI (along with UNIMDM and modem information files) contains a wealth of
configuration information and it is worthwhile to use TAPI to configure the modem and
control the call, even if TAPI doesnt dial or answer the modem. This is provided by a feature
called passthrough mode. In passthrough mode, TAPI immediately enters the
connected state and opens the associated serial port.
Although in passthrough mode, TAPI doesnt send any modem initialization commands,
TApdTapiDevice uses a two-step process to enter passthrough mode, which forces TAPI to
send its modem initialization commands. When the ConfigAndOpen method is called,
TApdTapiDevice first initializes TAPI in answer mode, which forces TAPI to send its
initialization commands. TApdTapiDevice then immediately closes the port and reopens it
in passthrough mode.
After calling ConfigAndOpen, TAPI is in control of the call, just as though it had dialed or
answered the modem. No OnTapiStatus or OnTapiLog events are generated, but
OnTapiPortOpen is generated. To close the call, use CancelCall. If TAPI ever aborts or closes
the call itself, the TApdTapiDevice generates the OnTapiPortClose event.
You should use TAPI passthrough mode if you need to support TAPI, but require modem
operations that UNIMDM.TSP doesnt provide. An example of this arises in Async
Professional when a TAPI-based program needs to send or receive faxes. See EXTAPIF for
an example of a TAPI-based fax program.
6
7
8
9
10
11
12
The TApdTapiDevice class now includes the ability to play and record wave files through a
TAPI device (over the phone line). This feature, along with the new DTMF feature, allows
you to created an automated voice answering system with Async Professional. To play and
record wave files through the TAPI device, you must have the following:
13
14
UNIMODEM/V or UNIMODEM/5.
15
A wave file.
17
TAPI Device Control from an Application 405
1
1
1
2
3
4
5
6
7
8
9
10
UNIMODEM/V is a set of DLLs that provides voice support for voice modems under
Windows 95/98. Voice support includes DTMF tone detection and generation, and wave file
playback and recording. UNIMODEM/V is currently available only for Windows
95/98/ME. You can get UNIMODEM/V for Windows 95 from the Microsoft web site.
To use the voice extensions provided by UNIMODEM/V, you must have a voice modem. For
wave support, it is important that you have the wave driver for the modem installed. Consult
your modem documentation to install the wave device properly.
The TApdTapiDevice component allows you to set the wave file format used for playback
and recording. The default wave format is PCM, 8KHz, 16 bit, mono. This format was
chosen because it is supported by the majority of voice modems. Some voice modems
support other wave file formats.
Wave files used for playback with Async Professional can be created with the Microsoft
Sound Recorder program. Wave files for use with TAPI which will be played over general
telephone lines (POTS) must be recorded in a PCM format compatible with your voice
modem (here again, the attributes 8,000 Hz (8Khz), 16 Bit, mono are a good bet). Sound
Recorder also allows for the conversion of existing wave files. TAPI requires a call handle for
recording. For this reason, you cannot use the TApdTapiDevice for recording messages
unless you call your modem from another phone.
Recording options include the ability to detect silence on the line and take action when
silence is detected (such as hanging up the call). This is desirable because TAPI does not
have the ability to detect a hangup for a voice call. This option allows you to save disk space
by saving only the portion of the call which contains data.
Dual Tone Multiple Frequency (DTMF) tones are generated by a telephone touch pad over
telephone lines. With compatible drivers and modems, Async Professional can detect
(receive) and generate these tones. Async Professional notifies an application when it
receives a tone by generating an OnTapiDTMF event. Tones are generated using the
SendTone method. See TAPI Voice Support in the Developers Guide for information
about supported operating systems.
14
15
16
17
406 Chapter 12: TAPI Components
1
1
TApdTapiDevice Component
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomTapiDevice (AdTapi)
TApdTapiDevice (AdTapi)
Properties
AnswerOnRing
EnableVoice
ShowTapiDevices
ApiVersion
FailureCode
StatusDisplay
Attempt
FilterUnsupportedDevice
TapiLog
AvgWaveInAmplitude
FilterUnsupportedDevices
TapiState
BPSRate
InterruptWave
TrimSeconds
CallerID
MaxAttempts
SilenceThreshold
CallerIDName
MaxMessageLength
ComPort
Number
Cancelled
RetryWait
WaveFileName
DeviceCount
SelectedDevice
WaveState
Dialing
ShowPorts
UseSoundCard
7
8
9
10
! Version
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
Methods
AutoAnswer
GetDevConfig
ShowConfigDialog
AutomatedVoiceToComms
PlayWaveFile
ShowConfigDialogEdit
CancelCall
SaveWaveFile
StartWaveRecord
ConfigAndOpen
SelectDevice
StopWaveFile
CopyCallInfo
SendTone
StopWaveRecord
Dial
SetDevConfig
TapiStatusMsg
FailureCodeMsg
SetRecordingParams
TranslateAddress
OnTapiCallerID
OnTapiLog
OnTapiWaveNotify
OnTapiConnect
OnTapiPortClose
OnTapiWaveSilence
OnTapiDTMF
OnTapiPortOpen
OnTapiFail
OnTapiStatus
Events
8
9
10
11
12
13
14
15
16
17
408 Chapter 12: TAPI Components
1
1
Reference Section
AnswerOnRing
property
2
property AnswerOnRing : Byte
Default: 2
The number of times the TAPI device should allow the incoming call to ring before
answering it.
The default for AnswerOnRing is two rings because problems can occur with caller-ID
enabled modems if the call is answered before the first ring.
ApiVersion
When an application initializes TAPI, it negotiates for a supported version of TAPI. Features
and behaviors differ among the versions. An application requests the highest level of TAPI
for which it was designed. The built-in TAPI services, even if they support a higher release
level, will behave as the requested version behaves.
The TApdTapiDevice always attempts to negotiate for version 1.4, but can use 1.3 if that is all
that is available. With operating systems supporting TAPI 2.0 or greater, TApdTapiDevice
will continue to operate at the 1.4 release level. See the README.TXT file for TAPI version
information.
Attempt
8
9
10
11
12
Indicates the number of times the current number has been dialed.
If the dialed number is busy, TAPI waits briefly and calls the number again. It tries up to
MaxAttempts times. The Attempt property returns the number of the current attempt.
Attempt is incremented immediately upon encountering a busy line. Attempt is primarily
for use in OnTapiStatus event handlers.
13
15
14
16
17
TApdTapiDevice Component 409
1
1
AvgWaveInAmplitude
2
3
4
5
6
7
8
9
10
11
12
13
procedure AutoAnswer;
14
15
16
17
410 Chapter 12: TAPI Components
1
1
method
AutomatedVoiceToComms
method
procedure AutomatedVoiceToComms;
communications.
Call AutomatedVoiceToComms when switching from an automated voice mode (DTMF
tone detection, wave recording/playing) to a fax send/receive mode.
The OnTapiPortOpen event will be generated once TAPI successfully switches media modes
(from AutomatedVoice to DataModem). Note that Windows 2000 does not allow switching
media modes on an active call, so this method will fail under this operating system.
6
7
The following example shows an OnTapiConnect event handler that updates a TLabel on the
current form with the negotiated bps rate:
TForm1 = class(TForm)
...
ApdTapiDevice1 : TApdTapiDevice;
Connect
: TLabel;
...
end;
10
11
12
13
14
15
16
17
1
1
CallerID
2
3
The following example shows an OnTapiConnect event handler that updates a TLabel on the
current form with the caller ID information:
7
8
9
10
11
TForm1 = class(TForm)
...
ApdTapiDevice1 : TApdTapiDevice;
CallerID
: TLabel;
...
end;
procedure TForm1.ApdTapiDevice1TapiConnect(Sender : TObject);
begin
CallerID.Caption := 'Caller: ' + ApdTapiDevice1.CallerID;
...
end;
CallerIDName
12
13
The name information is not available everywhere that caller ID is available. Some localities
only provide the caller ID phone number.
14
15
16
17
412 Chapter 12: TAPI Components
1
1
CancelCall
method
procedure CancelCall;
CancelCall is the TApdTapiDevice universal method for terminating the current call. It can
be used while waiting for incoming call, answering an incoming call, dialing a call, or during
an established connection. TAPI aborts the current process, assures that the modems have
disconnected, and places the modem into an idle state (not waiting for calls).
CancelCall is usually a background operation. It instructs TAPI to cancel the call and TAPI
performs the work of canceling and cleaning up. OnTapiPortclose will fire when TAPI closes
the port (assuming the port was open). OnTapiFail will always be generated when
CancelCall completes. To determine whether the OnTapiFail was generated due to
CancelCall, use the Cancelled property.
3
4
7
8
9
10
property
11
12
13
ComPort is usually set automatically at design time to the first TApdComPort component
the TApdTapiDevice finds on the form. If needed, use the Object Inspector to select a
different TApdComPort component.
14
Setting the ComPort property at run time is necessary only when using a dynamically
created TApdComPort or when selecting among several TApdComPort components.
15
16
17
1
1
ConfigAndOpen
method
procedure ConfigAndOpen;
2
3
4
! Configures the modem and leaves the port open in passthrough mode.
ConfigAndOpen takes advantage of the TAPI modem configuration facilities, even though
TAPI isnt used for dialing or answering a call. ConfigAndOpen does, however, require a
short period of background processing before the associated TApdComPort component is
open.
You could not, for example, use the following logic:
5
6
7
8
9
10
11
12
13
14
15
16
var
ApdComPort1
: TApdComPort;
ApdTapiDevice : TApdTapiDevice;
...
ApdTapiDevice1.ConfigAndOpen;
ApdComPort1.Output := 'ready';
...more port I/O
ApdComPort1.Open := False;
This is incorrect. After the call to ConfigAndOpen you must wait for TAPI to open the
TApdComPort, just as when TAPI is dialing or answering a call. When TAPI is ready,
(usually just a second or two) it generates the OnTapiPortOpen event which automatically
opens the associated TApdComPort.
The following example shows the proper way to use ConfigAndOpen:
procedure TForm1.OpenTheLine;
begin
ApdTapiDevice1.ConfigAndOpen;
end;
...
procedure TForm1.ApdTapiDevice1TapiPortOpen(Sender : TObject);
begin
ApdComPort1.Output := 'ready';
...more port I/O
end;
...
procedure TForm1.CloseTheLine;
begin
ApdTapiDevice1.CancelCall;
end;
See Using TAPI for configuration only on page 405 for more information.
17
414 Chapter 12: TAPI Components
1
1
CopyCallInfo
method
The TApdTapiDevice contains properties for the basic call information that a typical
dialer program needs about the current call. TAPI, however, maintains much more
information about the call. Although this information is of limited use, CopyCallInfo
provides it for applications that might need it.
3
4
6
7
8
9
10
method
11
12
13
14
15
16
17
1
1
1
2
If a busy signal is detected and MaxAttempts is greater than one, Dial redials the number
after waiting RetryWait seconds. This continues until a connection is established or
MaxAttempts dial attempts fail.
Due to a limitation of the Microsoft supplied TAPI Service Providers, the OnTapiConnect
event is not completely reliable for detecting when the called party answers a voice call.
Unimodem/V and Unimodem/5 do not implement the call progress notification techniques
required to detect when a voice connection is actually established. As a result of this, the
OnTapiConnect event is usually generated immediately after the modem completes dialing,
regardless of whether the remote party answered, their phone was busy, or any other
conditions. With some TSPs, it is also possible to get an OnTapiConnect event followed by
an OnTapiFail event, if the call was busy or no dial tone was detected. The APROFAQ.HLP
file contains several tips and tricks to detect when the remote party actually answers. TSPs
supplied with dedicated voice boards usually provide much more detailed and accurate call
progress notification.
The following example shows how to dial the U.S. Robotics BBS, waiting 5 minutes after a
busy signal and retrying up to 10 times:
3
4
5
8
9
ApdTapiDevice1.RetryWait := 300;
ApdTapiDevice1.MaxAttempts := 10;
ApdTapiDevice1.Dial('1-847-262-6000');
10
11
12
! Determines whether TAPI is placing an outgoing call or listening for an incoming call.
Dialing is True when TAPI is placing an outgoing call, False when TAPI is listening for or
answering incoming calls. Dialing is intended primarily for use in status routines to
distinguish between status events for incoming calls and status events for outgoing calls.
13
14
15
16
17
416 Chapter 12: TAPI Components
1
1
The following example shows an OnTapiStatus event handler that uses Dialing to update a
TLabel on the current form:
TForm1 = class(TForm)
...
ApdTapiDevice1 : TApdTapiDevice;
Direction
: TLabel;
...
end;
1
2
3
procedure TForm1.ApdTapiDevice1TapiStatus(
CP : TObject; First, Last : Boolean; Device, Message, Param1,
Param2, Param3 : LongInt);
const
DirectionStr : array[Boolean] of string = (
'Incoming', 'Outgoing');
begin
...
Direction.Caption := DirectionStr[ApdTapiDevice1.Dialing];
...
end;
6
7
8
property
10
Default: False
11
12
13
14
15
16
17
TApdTapiDevice Component 417
1
1
FailureCode
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FailureCodeMsg
17
418 Chapter 12: TAPI Components
1
1
method
FilterUnsupportedDevices
property
Default: True
! Determines whether unsupported devices are displayed in the TAPI device selection dialog
3
box.
The TApdTapiDevice support TAPI line devices, with the DataModem and AutomatedVoice
media modes. Some TAPI devices, notably the IP telephony devices in Windows 2000, are
not supported by the TApdTapiDevice. If this property is True (the default) these devices
will not be displayed in the TAPI device selection dialog. If this property is False, these
devices will be displayed in the dialog.
See also: SelectDevice
GetDevConfig
6
method
8
9
10
11
TTapiConfigRec = record
DataSize : Cardinal;
Data : array[0..1023] of Byte;
end;
12
13
14
15
16
17
TApdTapiDevice Component 419
1
1
InterruptWave
run-time property
Default: True
! Indicates whether the current wave file should stop when a DTMF tone is detected.
3
4
5
6
7
8
9
10
If InterruptWave is True, the currently playing wave file will stop when a DTMF tone is
detected. This allows you to have an automated phone answering system in which user is
allowed to interrupt the currently playing wave file with a DTMF selection. If InterruptWave
is False, DTMF tones do not stop the currently playing wave file. If you want the caller to
hear a wave file in its entirety, set InterruptWave to False before you start playing it.
See also: OnTapiDTMF, PlayWaveFile, StopWaveFile
MaxAttempts
property MaxAttempts : Word
Default: 3
11
12
property
run-time property
Default: 60
! The maximum allowed message length, in seconds, for messages recorded over the TAPI
13
14
Use this parameter to specify the maximum length of recorded messages. A 60-second
message will require about 950K of disk space given the default recording parameters. When
the specified length of time passes, the OnTapiWaveNotify event will be generated with a
Msg parameter of waDataReady. You could then save the wave file and terminate the call.
15
16
If the TrimSeconds property is set to a non-zero value then wave recording may terminate
before MaxMessageLength is reached.
17
420 Chapter 12: TAPI Components
1
1
Number
Number is intended primarily for use in status routines, to display the last number dialed.
Number is updated each time Dial is called.
The following example shows an OnTapiStatus event handler that displays the last number
dialed.
TForm1 = class(TForm)
...
ApdTapiDevice1 : TApdTapiDevice;
NumberDialed : TLabel;
...
end;
procedure TForm1.ApdTapiDevice1TapiStatus(
CP : TObject; First, Last : Boolean; Device, Message, Param1,
Param2, Param3 : LongInt);
begin
...
if Dialing then
NumberDialed.Caption := ApdTapiDevice1.Number
else
NumberDialed.Caption := '';
...
end;
...
ApdTapiDevice1.Dial('1-847-262-6000');
7
8
9
10
11
12
13
14
15
16
17
1
1
OnTapiCallerID
event
2
3
4
5
6
7
8
TTapiCallerIDEvent = procedure(
CP : TObject; ID, IDName : String) of object;
! Defines an event handler that is called after a connection is made and both a Caller ID string
and a Caller ID name string are returned.
The OnTapiCallerID event makes it easy to access Caller ID information without having to
know when it might be available on a call. Caller ID information is available only if it is
supported on the selected device and by the telephone service.
The following example shows how to use the OnTapiCallerID event to get the Caller ID
information and store it to edit controls.
procedure TForm1.ApdTapiDevice1TapiCallerID(
CP : TObject; ID, IDName : string);
begin
CallerId.Text := ID;
CallerIdName.Text := IDName;
end;
9
10
OnTapiConnect
event
Dial and AutoAnswer operations take place in the background. If a connection is established
after a call to Dial or AutoAnswer, the TApdTapiDevice generates the OnTapiConnect event.
No parameters are passed to the OnTapiConnect event. The OnTapiConnect event is most
useful and reliable when used to indicate when a voice connection has been established. For
data connections (EnableVoice = False), the TApdComPort may not have received the serial
port handle from TAPI when this event is generated. When you are establishing data
connections, use the OnTapiPortOpen event instead.
15
16
17
422 Chapter 12: TAPI Components
1
1
OnTapiDTMF
event
TTapiDTMFEvent = procedure(
CP : TObject; Digit : Char; ErrorCode : Longint;) of object;
Digit is a character that represents the phone button that was pressed on the remote phone
device. The possible values are 0 through 9, *, and #. ErrorCode is non-zero if an error
occurs when a TAPI connection is made (in this case the OnTapiDTMF is generated just
before the OnTapiConnect event).
The following example builds a string of up to ten DTMF tones (characters) in the global
variable S.
procedure TForm1.ApdTapiDevice1TapiDTMF(
CP : TObject; Digits : Char; ErrorCode : LongInt);
begin
if Length(S) < 11 then
S := S + Digit;
end;
7
8
event
9
10
11
12
13
14
15
16
17
TApdTapiDevice Component 423
1
1
OnTapiLog
event
TTapiLogEvent = procedure(
CP : TObject; Log : TTapiLogCode) of object;
! Defines an event handler that is called at designated points during a dial or answer attempt.
The primary purpose of this event is to give the application a chance to log auditing
information about telephone calls and whether they succeed or fail. You can also use this
event for start-up and cleanup activities, although OnTapiPortOpen and OnTapiPortClose
might be better.
5
6
CP is the TAPI component that generated the event. Log is a code that indicates the state of
the TAPI connection. The possible states are listed in TAPI logging on page 397. No other
information is passed with this event, but you can use the TApdTapiDevice properties such
as Number and Dialing to get additional information about the TAPI connection.
8
OnTapiPortClose
9
10
! Defines an event handler that is called immediately after TApdTapiDevice closes its
associated TApdComPort.
11
The TApdTapiDevice component is responsible for opening and closing the associated
TApdComPort at the appropriate times (when a connection is established or broken).
12
The serial port handle is invalid once the OnTapiPortClose event is generated, attempts to
access the port will raise the EPortNotOpen exception.
Applications can use this event to perform additional port cleanup activities.
13
14
15
16
17
424 Chapter 12: TAPI Components
1
1
event
OnTapiPortOpen
event
! Defines an event handler that is called immediately after TApdTapiDevice opens its
associated TApdComPort.
The TApdTapiDevice component is responsible for opening and closing the associated
TApdComPort at the appropriate times (when a connection is established or broken).
The serial port associated with the selected TAPI device is valid, and available when this
event is generated, it is safe to access the port properties and transmit characters.
Note that this event is not generated during a voice connection. When a voice connection is
made TAPI retains exclusive access to the serial port. This event will be generated after a call
to AutomatedVoiceToComms, once TAPI hands the TApdTapiDevice a valid serial port
handle.
Applications can use this event to perform additional port setup activities.
event
! Defines an event handler that is called regularly during a TAPI dial or answer attempt.
TAPI performs dial and answer activities in the background, calling a callback routine
whenever the state of the line or call changes. TApdTapiDevice installs a hidden callback
routine and translates all callback calls into OnTapiStatus events.
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
The remaining parameters (Device, Param2, and Param3) are intended for use in
applications that extend the features provided by TApdTapiDevice and might need those
status parameters.
TAPI generates callbacks only when it perceives a change in the state of the line or call. TAPI,
therefore, does not generate callbacks when the modem stays in a single state for an
extended period of time. For example, after dialing a number TAPI reports that the call is in
the proceeding phase. It generates no further status callbacks until the call succeeds or
fails. Since this can take many seconds, as much as 20 or even 30 seconds, the user might
become concerned about the lack of positive feedback (is it still working?).
OnTapiWaveNotify
event
TTapiWaveEvent = procedure(
CP : TObject; Msg : TWaveMessage) of object;
TWaveMessage = (waPlayOpen, waPlayDone, waPlayClose,
waRecordOpen, waDataReady, waRecordClose);
9
10
! Defines an event handler that is called when a wave file status changes.
The possible values for Msg are:
Value
Meaning
11
waPlayDone
12
waPlayOpen
waPlayClose
waRecordOpen
waRecordClose
waDataReady
13
14
15
16
17
1
1
The following example sets the Caption of a label after a wave file has finished playing:
procedure TForm1.ApdTapiDevice1TapiWaveEvent(
CP : TObject; Msg : TWaveMessage);
begin
if Msg = waPlayDone then
Label4.Caption := 'Wave Device Idle...';
end;
2
3
4
OnTapiWaveSilence
event
FOnTapiWaveSilence : TTapiWaveSilence
TTapiWaveSilence = procedure(CP : TObject;
var StopRecording : Boolean; var Hangup : Boolean) of object;
! Defines an event handler that is called when silence is detected while recording a wave file.
StopRecording is a var Boolean parameter that determines whether wave recording should
stop. This parameter is True by default. Hangup is a var Boolean parameter that determines
whether the call should be terminated. The parameter is also True by default.
This event works in conjunction with the TrimSeconds property. If TrimSeconds is 0 then
OnTapiWaveSilence will not be generated. If you do not respond to this event then recording
will stop and the call will be terminated when silence is detected. This is probably the
desired behavior in most applications, so you may not use this event very often.
See also: StartWaveRecord, StopWaveRecord, TrimSeconds
PlayWaveFile
method
7
8
9
10
11
12
13
14
15
The following example plays a wave file through the TAPI device:
16
ApdTapiDevice1.PlayWaveFile('greeting.wav');
17
TApdTapiDevice Component 427
1
1
RetryWait
property
Default: 60
! The number of seconds to wait after a busy signal before trying the number again.
3
4
5
After encountering a busy signal, TApdTapiDevice checks to see if it should try this number
again by comparing Attempts to MaxAttempts. If more attempts are required, it first waits
RetryWait seconds before dialing again to give the dialed machine time to complete the
current session.
See also: Attempts, MaxAttempts
SaveWaveFile
method
6
procedure SaveWaveFile(FileName : String; Overwrite : Boolean);
FileName is the file to save. Overwrite indicates whether an existing file should be
overwritten. If Overwrite is False and a file with the same name exists, then an exception is
thrown. By default, data is recorded at 8,000 kHz, 16 bits, mono (the maximum sound
quality allowed for most TAPI wave devices). You can save the wave data after the
OnTapiWaveNotify event is received with a Msg parameter of waDataReady.
10
The following example starts recording wave data on a button click and saves the recorded
data when notified that the recording is done:
11
12
13
14
15
16
17
428 Chapter 12: TAPI Components
1
1
SelectDevice
method
procedure SelectDevice;
SelectDevice uses the same dialog box as the property editor for SelectedDevice. You can
call SelectDevice to prompt the user for a TAPI device to use for subsequent dial or answer
operations.
property
7
8
9
10
11
method
12
13
14
15
16
17
1
1
SetDevConfig
method
2
3
4
5
6
7
8
9
10
11
SetRecordingParams
procedure SetRecordingParams(NumChannels : Byte;
NumSamplesPerSecond : Integer; NumBitsPerSample : Byte);
12
13
14
! Displays the TAPI property sheets for the selected TAPI device.
TAPI maintains a set of port properties for each TAPI device. These property sheets are
accessible from the Windows Modem applet in the Control Panel. You can also make them
available in your application by calling ShowConfigDialog.
16
17
430 Chapter 12: TAPI Components
method
procedure ShowConfigDialog;
15
method
ShowConfigDialogEdit
method
function ShowConfigDialogEdit(
const Init : TTapiConfigRec) : TTapiConfigRec;
1
2
3
4
property
Default: True
If ShowPorts is True, the available serial ports are displayed in the drop-down box in the
Device Selection dialog box. If ShowTapiDevices is True, the TAPI devices are displayed. If
both ShowPorts and ShowTapiDevices are False, nothing is shown in the drop-down box in
the dialog.
10
When ShowPorts is True, the available serial ports will be displayed in the dialog box. If one
of these devices is selected, the TApdComPort.TapiMode will be set to tmOff. Use TapiMode
to determine whether to open the port with ConfigAndOpen or whether to open the
TApdComPort directly.
12
11
13
14
15
16
17
TApdTapiDevice Component 431
1
1
ShowTapiDevices
property
Default: True
If ShowTapiDevices is True, SelectDevice shows both TAPI devices and available serial
ports. If ShowTapiDevices is False, SelectDevice shows only serial ports.
See also: SelectDevice, ShowPorts
SilenceThreshold
run-time property
6
7
8
9
10
11
12
13
14
15
16
Default: 50
17
432 Chapter 12: TAPI Components
1
1
method
The following example sets the maximum message length to 45 seconds, starts recording
wave data on a button click, and then saves the recorded data when notified that the
recording is done:
procedure TForm1.ApdTapiDevice1TapiWaveNotify(
CP : TObject; Msg : TWaveMessage);
begin
if Msg = waDataReady then
ApdTapiDevice1.SaveWaveFile('Call01.wav');
end;
property
7
8
9
10
11
12
13
14
15
16
17
1
1
StopWaveFile
method
procedure StopWaveFile;
2
3
4
5
6
method
procedure StopWaveRecord;
7
8
9
10
11
12
13
14
15
TapiLog is usually set automatically at design time to the first TApdTapiLog or derived
component the TApdTapiDevice finds on the form. If necessary, use the Object Inspector to
select a different a logging component.
16
Setting the TapiLog property at run time is necessary only when using a dynamically created
logging component or when selecting among several logging components.
17
434 Chapter 12: TAPI Components
1
1
property
TapiState
2
3
Default: tsNone
6
7
8
Value
Meaning
tsIdle
tsOffering
tsAccepted
tsDialTone
tsDialing
tsRingback
Ringback detected.
tsBusy
Line is busy.
tsSpecialInfo
tsConnected
Call is connected.
tsProceeding
Call is proceeding.
tsOnHold
tsConferenced
Call is conferenced.
9
10
11
12
13
14
15
16
17
1
1
1
2
3
Value
Meaning
tsOnHoldPendConf
tsOnHoldPendTransfer
tsDisconnected
tsUnknown
TapiStatusMsg
method
4
function TApdCustomTapiDevice.TapiStatusMsg(
const Message, State, Reason : DWORD) : string;
5
6
7
8
9
10
11
12
13
14
15
! Returns a text message for the progress of the current TAPI call.
TapiStatusMsg is intended primarily for use in OnTapiStatus event handlers. Message is the
Message parameter passed into OnTapiStatus. State is the Param1 parameter passed into
OnTapiStatus. TapiStatusMsg combines the values of Message and State to arrive at a unique
resource string ID, stored in APW.RC. Reason is the Param2 parameter passed into
OnTapiStatus. Reason adds additional information for LineCallState_Disconnected
messages. This parameter is ignored for all other messages.
The following example shows an OnTapiStatus event handler that calls TapiStatusMsg and
displays the returned string:
TForm1 = class(TForm)
...
ApdTapiDevice1 : TApdTapiDevice;
StatusStr
: TLabel;
...
end;
procedure TForm1.ApdTapiDevice1TapiStatus(
CP : TObject; First, Last: Boolean; Device, Message, Param1,
Param2, Param3 : LongInt);
begin
...
StatusStr.Caption :=
ApdTapiDevice1.TapiStatusMsg(Message, Param1, Param2);
...
end;
16
17
436 Chapter 12: TAPI Components
1
1
TranslateAddress
method
A canonical address is an address that contains the country code as well as the phone
number. TAPI also takes into account any settings you have made to your modem properties
in the Control Panel. For example, if you have call waiting enabled and the code to disable
call waiting is *70, TAPI prepends *70 to the dialable address string when you call
TranslateAddress.
3
4
run-time property
Default: 2
! Sets the number of seconds of silence to detect when recording wave files.
Wave recording can be terminated in one of three ways. First, you can manually terminate
recording by calling StopWaveRecord. Second, recording will automatically terminate when
the amount of time specified by MaxMessageLength has passed. Finally, wave recording can
terminate as a result of silence detected on the line.
When TrimSeconds is set to a non-zero value, the wave data is examined as it is recorded.
Silence is determined by comparing the average of the wave data for one second to a silence
threshold as defined by the SilenceThreshold property. If TrimSeconds seconds of silence is
detected, the OnTapiWaveSilence event is generated. If no OnTapiWaveSilence event is
defined then the recording is stopped and the call is terminated. Even after a hangup, a
telephone line contains a good deal of random noise so it is not guaranteed that silence will
be detected immediately after a hangup.
See also: OnTapiWaveSilence, SilenceThreshold, StartWaveRecord, StopWaveRecord
7
8
9
10
11
12
13
14
15
16
17
1
1
UseSoundCard
run-time property
Default: False
UseSoundCard determines whether the output from PlayWaveFile goes to the TAPI device
or to the sound card. By default the output is sent to the TAPI waveform audio device
(through the phone). Set UseSoundCard to True to play the wave file through the sound
card.
The following example plays a wave file through the sound card rather than over the phone
line and then resets the device so that subsequent sounds are played through the TAPI
device:
ApdTapiDevice1.UseSoundCard := True;
ApdTapiDevice1.PlayWaveFile('Call01.wav');
ApdTapiDevice1.UseSoundCard := False;
8
9
WaveFileName
If a wave file is currently playing, WaveFileName is the name of the file. If no wave file is
currently playing, WaveFileName is the name of the last wave file that was played.
WaveFileName is automatically set when you use PlayWaveFile to play a file.
The following example sets a labels Caption to the name of the current wave file:
12
13
Label1.Caption := ApdTapiDevice1.WaveFileName;
14
15
16
17
438 Chapter 12: TAPI Components
1
1
WaveState
Meaning
wsIdle
wsPlaying
wsRecording
wsData
8
9
10
11
12
13
14
15
16
17
1
1
TApdAbstractTapiStatus Class
TApdAbstractTapiStatus is an abstract class that defines the methods and properties needed
by a component that automatically displays status while TApdTapiDevice is dialing or
answering a call. You generally wont need to create a descendent class of your own, since
Async Professional supplies one, the TApdTapiStatus component (see page 443).
3
4
5
6
7
8
9
10
11
12
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdAbstractTapiStatus (AdTapi)
13
14
Properties
Display
15
16
CreateDisplay
! Version
Methods
17
TapiDevice
DestroyDisplay
UpdateDisplay
Reference Section
CreateDisplay
1
dynamic abstract method
2
procedure CreateDisplay; dynamic; abstract;
! An abstract method that creates a form to display dialing and answering status.
CreateDisplay must then assign the instance of this form to the Display property.
See also: DestroyDisplay, Display
DestroyDisplay
6
dynamic abstract method
run-time property
10
11
12
13
TapiDevice
property
14
15
16
17
1
1
1
2
3
4
5
6
7
8
UpdateDisplay
9
10
11
12
13
14
15
16
17
442 Chapter 12: TAPI Components
1
1
TApdTapiStatus Component
Figure 12.1 shows the TStandardTapiDisplay form that is associated with a TApdTapiStatus
component.
7
8
9
10
11
12
13
For an example of using a TApdTapiStatus component, see either the dial or answer
examples in Making calls on page 400 and Answering calls on page 402.
14
15
16
17
1
1
Hierarchy
TComponent (VCL)
2
3
TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdAbstractTapiStatus (AdTapi) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
TApdTapiStatus (AdTStat)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
444 Chapter 12: TAPI Components
1
1
TApdTapiLog Class
TApdTapiLog creates or appends to a text file whose name is given by the TapiHistoryName
property. Each time the OnTapiLog event is generated, the associated TApdTapiLog instance
opens the file, writes a new line to it, and closes the file.
3
4
10:11:34
10:11:34
10:11:53
10:11:53
PM
PM
PM
PM
: call started
:
dialing 262-6000
:
cancelled
: call finished
5/7/96
5/7/96
5/7/96
5/7/96
5/7/96
5/7/96
5/7/96
10:50:50
10:50:50
10:51:02
10:51:02
10:51:07
10:51:11
10:51:11
PM
PM
PM
PM
PM
PM
PM
: call started
:
dialing 262-6000
:
busy
:
dial failed
:
dialing 262-6000
:
cancelled
: call finished
5/7/96
5/7/96
5/7/96
5/7/96
11:11:34
11:11:34
11:11:53
11:30:07
PM
PM
PM
PM
: call started
:
dialing 262-6000
:
connected
: call finished
6
7
8
9
10
11
Hierarchy
12
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
13
TApdTapiLog (AdTapi)
14
Properties
TapiHistoryName
TapiDevice
! Version
15
Methods
16
UpdateLog
17
TApdTapiLog Class 445
1
1
Reference Section
TapiDevice
property
2
property TapiDevice : TApdCustomTapiDevice
TapiDevice is automatically initialized when the TapiLog property of the owning TAPI
component is set. TapiDevice can be changed to assign the log component to a different
TAPI component.
TapiHistoryName
property
6
7
8
9
10
Default: APROTAPI.HIS
virtual method
11
12
The Log parameter has the same values passed to the OnTapiLog event handler of
TApdTapiDevice. UpdateLog creates or appends to the log file, builds and writes a text
string for each event, and closes the log file.
15
TApdTapiLog contains a field named TapiDevice that UpdateLog uses to obtain additional
information (e.g., Number and Dialing) about the dial or answer operation.
See also: TApdTapiDevice.OnTapiLog
16
17
446 Chapter 12: TAPI Components
1
1
1
2
Async Professional provides a modem database and several components for configuring,
dialing, and answering modems and managing phone books. These components are ideal
for controlling modems since they include a modem database and all of the features a
modem-based program might need. Your users simply select their modem (or the closest
match) from the database and your application loads the associated configuration strings
for that modem from the database.
3
4
The modem components provide routines for retrieving modem information from the
libmodem database, manipulating a modem by sending commands through TApdComPort
components, and processing response data, a dialing engine for making repeated dial
attempts, and a few user-interface components for maintaining phonebooks and dialing the
modem. The following units and components are described in this chapter.
5
6
For projects ported from previous versions of Async Professional, the TAdModem,
TApdSModem and supporting components are still available as deprecated components.
AdMdm
Contains a component (TAdModem) that provides a simple interface for accessing the most
commonly used modem operations. It combines the features of most of the other modem
components into one component.
9
10
AdLibMdm
Contains TApdLibModem, a VCL component that provides an interface to the libmodem
modem database.
11
AdMdmDlg
12
Contains a modem status dialog for use with the TAdModem component.
13
14
15
16
17
447
1
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
modemcap and libmodem 448
1
1
TApdLibModem Component
Detailed configuration, response and feature information for a wide variety of modems is
stored in numerous XML documents. By default, these documents are stored in the
/etc/modemcap directory. The modemcap.xml document contains an index of all available
modem definitions.
Several data structures are used to describe the modem cap index and the modem detail
files. These types are defined in the AxLibMdm.pas unit. The structures and methods that
are most applicable to the TAdModem are listed here with a brief description of the
structure. Refer to the libmodem source code (AdLibMdm.pas) and help pages for a more
detailed discussion of these structures.
The TApdLibModem class uses the following structures. Several fields are TLists, each item
points to an item in a sequence, the type of item is provided following the field name.
{ an entry from modemcap.xml describing the location and
identification of a single modem }
PLmModemName = ^TLmModemName;
TLmModemName = record
ModemName
: string;
Manufacturer : string;
Model
: string;
ModemFile
: string;
end;
{ a modem response }
PLmResponseData = ^TLmResponseData;
TLmResponseData = record
Response
: string;
ResponseType
: string;
end;
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
LmResponseData
2
3
4
6
7
8
9
10
11
12
13
{ a modem command }
PLmModemCommand = ^TLmModemCommand;
TLmModemCommand = record
Command
: string;
Sequence
: Integer;
end;
14
15
16
17
TApdLibModem Component 450
1
1
SerialSpeedFaxDetect
SerialSpeedDataDetect
HostCommandFaxDetect
HostCommandDataDetect
ModemResponseFaxConnect
ModemResponseDataConnect
AnswerCommand
end;
:
:
:
:
:
:
:
string;
string;
string;
string;
string;
string;
TList;
1
2
3
6
7
8
9
10
11
12
13
14
15
16
17
1
1
{ wave details }
TLmWaveDriver = record
BaudRate
WaveHardwareID
WaveDevices
LowerMid
LowerWaveInPid
LowerWaveOutPid
WaveOutMixerDest
WaveOutMixerSource
WaveInMixerDest
WaveInMixerSource
WaveFormat
end;
{ voice modem properties }
TLmVoiceSettings = record
VoiceProfile
HandsetCloseDelay
SpeakerPhoneSpecs
AbortPlay
CallerIDOutSide
CallerIDPrivate
TerminatePlay
TerminateRecord
VoiceManufacturerID
VoiceProductIDWaveIn
VoiceProductIDWaveOut
VoiceSwitchFeatures
VoiceBaudRate
VoiceMixerMid
VoiceMixerPid
VoiceMixerLineID
CloseHandset
EnableCallerID
EnableDistinctiveRing
GenerateDigit
HandsetPlayFormat
HandsetRecordFormat
LineSetPlayFormat
LineSetRecordFormat
OpenHandset
SpeakerPhoneDisable
SpeakerPhoneEnable
SpeakerPhoneMute
SpeakerPhoneSetVolumeGain
1
:
:
:
:
:
:
:
:
:
:
:
string;
string;
string;
string;
string;
string;
string;
string;
string;
string;
TList;
2
3
4
// LmWaveFormat
6
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
string;
Integer;
string;
string;
string;
string;
string;
string;
string;
string;
string;
string;
Integer;
string;
string;
string;
:
:
:
:
:
:
:
:
:
:
:
:
:
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
TList;
7
8
9
10
11
12
//
//
//
//
//
//
//
//
//
//
//
//
//
LmModemCommand;
LmModemCommand;
LmModemCommand;
LmModemCommand;
LmModemCommand;
LmModemCommand;
LmModemCommand;
LmModemCommand;
LmModemCommand;
LmModemCommand;
LmModemCommand;
LmModemCommand;
LmModemCommand;
13
14
15
16
17
1
1
SpeakerPhoneUnMute
StartPlay
StartRecord
StopPlay
StopRecord
VoiceAnswer
VoiceDialNumberSetup
VoiceToDataAnswer
WaveDriver
end;
:
:
:
:
:
:
:
:
:
TList;
// LmModemCommand;
TList;
// LmModemCommand;
TList;
// LmModemCommand;
TList;
// LmModemCommand;
TList;
// LmModemCommand;
TList;
// LmModemCommand;
TList;
// LmModemCommand;
TList;
// LmModemCommand;
TLmWaveDriver;
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdLibModem Component 453
1
1
ConfigDelay
end;
: Integer;
1
2
string;
string;
string;
Integer;
Integer;
Boolean;
string;
Integer;
string;
string;
string;
Integer;
Integer;
Integer;
3
4
6
7
8
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
string;
string;
string;
string;
string;
string;
string;
string;
string;
string;
Integer;
string;
string;
string;
string;
string;
string;
string;
Integer;
Integer;
Boolean;
Boolean;
Boolean;
10
11
12
13
14
15
16
17
TApdLibModem Component 454
1
1
SupportsSpeakerVolumeLow
SupportsSpeakerVolumeMed
SupportsSpeakerVolumeHigh
SupportsSpeakerModeOff
SupportsSpeakerModeDial
SupportsSpeakerModeOn
SupportsSpeakerModeSetup
SupportsSetDataCompressionNegot
SupportsSetErrorControlProtNegot
SupportsSetForcedErrorControl
SupportsSetCellular
SupportsSetHardwareFlowControl
SupportsSetSoftwareFlowControl
SupportsCCITTBellToggle
SupportsSetSpeedNegotiation
SupportsSetTonePulse
SupportsBlindDial
SupportsSetV21V23
SupportsModemDiagnostics
MaxDTERate
MaxDCERate
CurrentCountry
MaximumPortSpeed
PowerDelay
ConfigDelay
BaudRate
Responses
Answer
Fax
FaxDetails
Voice
Hangup
Init
Monitor
Settings
Hardware
BaudRates
Options
end;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Boolean;
Integer;
Integer;
string;
Integer;
Integer;
Integer;
Integer;
TLmResponses;
TList;
TList;
TLmFaxDetails;
TLmVoiceSettings;
TList;
TList;
TList;
TLmModemSettings;
TLmModemHardware;
TStringList;
TStringList;
Not all of the proceeding structures and fields are used in Async Professional, they are
included for future enhancements.
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Hierarchy
TComponent (VCL)
TApdLibModem(AdLibMdm)
Properties
ModemCapFolder
Methods
AddModem
DeleteModem
GetModems
AddModemRecord
DeleteModemRecord
SelectModem
CreateNewDetailFile
GetModem
6
7
8
9
10
11
12
13
14
15
16
17
TApdLibModem Component 456
1
1
Reference Section
AddModem
1
method
2
function AddModem(
const ModemDetailFile : string; Modem : TLmModem) : Integer;
3
4
method
function AddModemRecord(
ModemRecord : TLmModemRecord) : Integer;
9
10
11
method
12
function CreateNewDetailFile(
const ModemDetailFile : string) : Integer;
13
14
ModemDetailFile is the name of the new modem detail file. If ModemDetailFile already
exists, it will be overwritten. The result of this method is ecOK if the file was created
successfully.
15
16
17
1
1
DeleteModem
method
function DeleteModem(
const ModemDetailFile : string; Modem : TLmModem) : Integer;
1
2
3
4
method
function DeleteModemRecord(
ModemRecord : TLmModemRecord) : Integer;
GetModem
method
10
11
12
13
14
15
16
17
1
1
GetModems
method
function GetModems(
const ModemDetailFile : string) : TStringList;
1
2
3
4
The return value is a TStringList containing an item for each modem contained in the
modem detail file. The Strings portion of the item is the friendly name of the modem. The
Objects portion is a TLmModem structure defining the modem.
ModemCapFolder
property
6
7
8
9
method
function SelectModem(
var ModemFile, ModemManufacturer, ModemName: string;
var LmModem : TLmModem) : Boolean;
10
11
12
13
14
15
16
17
1
1
If the OK button is selected to close the dialog, ModemFile will contain the name of the
modem detail file where the selected modem resides; ModemManufacturer is the
manufacturer, and ModemName is the name of the modem; LmModem is the TLmModem
structure that defines the modem capabilities and configuration information.
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdLibModem Component 460
1
1
TAdModem Component
The TAdModem component combines the features of libmodem-based device selection and
configuration and modem control methods. TAdModem integrates the selection of the
modem from the modem database and the dialog to show the current status of the modem.
The TAdModem component is used to select and configure a modem and to dial or answer
the line.
There are many similarities between the TAdModem and TApdTapiDevice components.
The TApdTapiDevice uses the Microsoft TAPI library, and most of TAPI operates under the
black box principle. The TAdModem can be more flexible, especially when custom
modem or port configurations must be used.
The TAdModem component requires libmodem and the modemcap database. See
TApdLibModem Component on page 449, and the appropriate help pages, for details
concerning these libraries.
Modem selection
When using the TAdModem component, the appropriate modem definition must be loaded
from modemcap. To do this, call the TAdModem.SelectModem method, which will display
the dialog box shown in Figure 13.1.
8
9
10
11
12
The Manufacturer combo box will be filled with a list of known modem manufacturers
(those that are included in modemcap). Select a manufacturer from the list and the Modem
name combo box will be filled with a list of known modems from the appropriate modem
detail file. Select the modem name from the list and click OK.
To select a modem programatically, assign a TAdModemNameProp object to the
SelectedDevice property
13
14
15
16
17
1
1
Connectionless connections
The TAdModem can establish a connection direct to the port through the ConfigAndOpen
method. This does not establish a connection, except to the local modem. When the device
has been configured, the OnModemConnect event will be generated and you can
communicate with the modem.
2
3
Dialing
The TAdModem can also establish connections by dialing. To dial a number through the
modem, and have the modem negotiate a connection, call the TAdModem.Dial method.
The phone number to dial is passed in the ANumber parameter to the Dial method. This
number is dialed without modification. If you need to enter a prefix to gain an outside line,
to use a calling card, or other non-dialable use, those digits must be added to ANumber. For
example, if you want to dial 555-1212 but you need to dial 9 to access an outside line,
ANumber would be 9 555-1212.
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent(OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TAdCustomModem(AdMdm)
2
3
TAdModem(AdMdm)
Properties
AnswerOnRing
FailureCode
PassthroughMode
BPSRate
LastResponse
RetryWait
CancelCall
MaxAttempts
RingWaitTimeout
ComPort
ModemCapFolder
SelectedDevice
Dialing
ModemState
DialTimeout
NegotiationResponses
StatusDisplay
! Version
Methods
6
7
8
AutoAnswer
FailureCodeMsg
SetDevConfig
CancelCall
GetDevConfig
ModemLogToString
ConfigAndOpen
SendCommand
ModemStatusMsg
Dial
SelectDevice
TranslateAddress
Events
9
10
11
OnModemCallerID
OnModemDisconnect
OnModemLog
OnModemConnect
OnModemFail
OnModemStatusMethods
12
13
14
15
16
17
1
1
Reference Section
AnswerOnRing
property
2
property AnswerOnRing : Byte
Default: 2
The number of times the component should allow the incoming call to ring before
answering it.
The AnswerOnRing property determines the number of RING responses that the
TAdModem detects before answering the incoming call. Once the AutoAnswer method is
called, internal TApdDataPackets are initialized to detect the RING response from the
modem when an incoming call is signaled. When AnswerOfRing RING responses are
detected, the call is answered.
Caller ID information is transmitted between the first and second rings in most countries.
The AnswerOnRing property defaults to 2 to avoid problems with Caller ID information
corrupting the connection negotiations.
AutoAnswer
method
procedure AutoAnswer;
10
11
12
13
14
15
16
17
1
1
Auto answer mode can be cancelled by calling CancelCall. The auto answer mode is
cancelled regardless of whether the TAdModem is waiting in the background for the
incoming call or the modem is currently answering the call.
Calling AutoAnswer does not turn on the auto answer (AA) light on an external modem.
The AutoAnswer method does not use the auto answer feature of the modem.
BPSRate
7
8
method
procedure CancelCall;
10
11
If you call CancelCall while the TAdModem component is in auto answer mode, the modem
component is taken out of auto answer mode.
12
CancelCall is the TAdModem universal method for terminating the current call. It can be
used while waiting for an incoming call, answering an incoming call, dialing a call, or during
an established connection. TAdModem terminates the current process, assures that the
modems have disconnected, and places the modem into an idle state (not waiting for calls).
13
14
CancelCall returns when the connection, or connection attempt, has terminated. The
OnModemDisconnect event is generated if a connection was present when CancelCall was
called; if a connection was not present, no event is generated.
15
16
17
TAdModem Component 465
1
1
ComPort
property
ComPort is usually set automatically at design time to the first TApdComPort component
the TAdModem finds on the form. If you need to, you can use the Object Inspector to select
a different TApdComPort component.
Setting the ComPort property at run time is necessary only when using a dynamically
created TApdComPort or when selecting among several TApdComPort components.
3
4
Note that some properties of the TApdComPort may be overridden with properties
retrieved from modemcap when the TAdModem initializes the modem.
See also: TApdCustomComPort
ConfigAndOpen
method
7
procedure ConfigAndOpen;
! Configures the modem and provides access to the modem without a connection.
The ConfigAndOpen method configures the modem according to the configuration
settings retrieved from modemcap. Once the modem has been configured, the
OnModemConnect event is generated.
ConfigAndOpen is used primarily to configure the modem to a known state where it can be
used without a connection. For example, you can use ConfigAndOpen to provide terminal
access to a modem for diagnostics or for faxing.
While the modem is being configured, several TApdDataPackets will be initialized to
capture the responses from the modem. Once the modem has been configured, the
TApdDataPackets will be removed, providing no further notification of the state of the
modem.
8
9
10
11
12
Note that ConfigAndOpen establishes a connection to the port, not through the modem to
another device.
13
14
15
16
17
TAdModem Component 466
1
1
Dial
method
Dial initializes the modem and then dials the number specified by the ANumber parameter.
When the connection is established, the OnModemConnected event is generated.
Dial returns immediately. The OnModemConnect event is generated when the appropriate
connection responses have been received from the modem. The OnModemFail event is
generated if the modem could not be initialized, could not detect dial tone (if that was
required by the configuration), if the modems could not negotiate a mutually acceptable set
of connection parameters, or if the remote party did not answer the call within DialTimeout
seconds. The FailureCode property can be queried to determine the actual reason for the
failure.
6
7
8
9
10
11
property
12
Default: 60
! The number of seconds to wait for a connection after dialing the number.
When a dial attempt begins, the TAdModem component allows DialTimeout seconds for a
connection result to be received from the modem. The timeout countdown starts when the
Dial method is called. If the connection responses are not received within this time, a
timeout occurs, the operation is cancelled and the OnModemFail event is generated.
See also: Dial, FailureCode, OnModemFail
13
14
15
16
17
1
1
FailureCode
FailureCode is the result of the last AutoAnswer, ConfigAndOpen, or Dial method that was
called. FailureCode indicates the nature of the failure.
This property is used primarily in the OnModemFail event handler to determine the reason
for the failure.
method
method
10
11
This method can be used to confirm the modem configuration prior to use, or to make
changes to the current configuration.
12
13
14
15
16
17
TAdModem Component 468
1
1
ModemCapFolder
property
! The name of the directory where the modemcap modem database has been installed.
The modemcap database file contains a list of modems and their configuration strings. This
folder is used when SelectDevice is called to display a list of modems from which the user
can choose. ModemCapFolder is also used at design time to display the list of modems
when the SelectedDevice property is modified.
3
4
method
6
function ModemLogToString(
const LogCode : TAdModemLogCode) : string;
8
9
10
11
12
13
Default: msUnknown
ModemState is used internally to track modem responses and controlling the state of the
TAdModem component for configuration, dialing, and answering. This property is made
public for possible use of status routines.
14
15
16
17
1
1
Value
Description
msUnknown
msIdle
msInitializing
msAutoAnswerBackground
msAutoAnswerWait
msAnswerWait
msDialWait
msConnectWait
msConnected
msHangup
msCancel
3
4
6
7
8
10
11
12
13
14
15
16
17
TAdModem Component 470
1
1
OnModemCallerID
method
6
7
8
DATE: MM/DD/YY<CR><LF>
10
11
12
13
14
15
16
17
1
1
OnModemConnect
method
TModemNotifyEvent = procedure(
Modem : TAdCustomModem) of object;
The OnModemConnect event is generated when dialing or answering after the modem
returns the connection response. This event is also generated after a call to ConfigAndOpen
once the modem has been configured.
OnModemDisconnect
method
10
11
12
Modem is the TAdCustomModem that generated the event. No other parameters are
provided.
13
Note that some devices and protocols routinely toggle DCD. For these situations, consult the
device and protocol documentation for details on detecting connection termination.
14
15
16
17
TAdModem Component 472
1
1
OnModemFail
method
TModemNotifyEvent = procedure (
Modem : TAdCustomModem) of object;
! Defines an event handler that is generated when a modem or connection failure is detected.
The OnModemFail event is generated if the modem could not be initialized, or if a
connection could not be established. When dialing, this event is generated if the modem
could not detect dial tone (if the configuration required dial tone), if the modems could not
negotiate a mutually acceptable set of connection parameters, or if the remote party did not
answer the call within DialTimeout seconds. When answering, this event is generated if the
modems could not negotiate a mutually acceptable set of connection parameters, of if the
connection attempt timed out.
Modem is the TAdCustomModem that generated the event. No other parameters are
provided. The reason for the failure can be obtained from the FailureCode property.
3
4
6
7
method
8
9
TModemLogEvent = procedure(
Modem : TAdCustomModem; LogCode : TApdModemLogCode) of object;
! Defines an event handler that is generated at designated points during a dial or answer
attempt.
The primary purpose of this event is to give the application a chance to log auditing
information about telephone calls and whether they succeed or fail. This event is intended
primarily for high-level logging, not to determine program flow.
Modem is the TAdCustomModem that generated the event. LogCode is the
TAdModemLogCode that described the event being logged.
10
11
12
13
14
15
16
17
1
1
Description
mlNone
None
mlDial
Dialing
mlAutoAnswer
Initiated AutoAnswer
mlAnswer
mlConnect
Connected
mlCancel
Call cancelled
mlBusy
mlConnectFail
1
2
3
4
method
! Defines an event handler that is generated when the state of the component changes.
8
9
10
Modem is the TAdCustomModem that generated the event. ModemState is the new state of
the component. See the ModemState definition for a list of possible ModemState values and
their meanings.
11
12
RingCount
13
14
Default: 0
15
16
17
TAdModem Component 474
1
1
RingWaitTimeout
property
Default: 1200
3
4
method
6
7
8
9
10
11
12
13
14
15
16
17
TAdModem Component 475
1
1
SelectedDevice
property
TAdModemNameProp = class(TPersistent)
published
property Manufacturer : string;
property Name : string;
end;
SelectedDevice displays the modem manufacturer, model, and name of the modem that has
been selected through the SelectDevice method. The properties of the
TAdModemNameProp are read-only at design time and are available to determine which
modemcap structure will be used.
To change modems configurations at run time, you may either call the SelectDevice method
to display the device selection dialog or assign a TAdModemNameProp class to this
property.
Selecting a new modem configuration through the SelectedDevice property or SelectDevice
method while a connection is established will raise the ecModemBusy exception.
See also: GetDevConfig, SelectDevice, SetDevConfig
6
7
8
9
SendCommand
method
10
11
12
13
14
15
16
17
TAdModem Component 476
1
1
SetDevConfig
method
The modemcap database file contains a list of modems and their configuration. The
SetDevConfig method forces a new configuration structure, which will be used in
subsequent calls to the AutoAnswer, ConfigAndOpen, and Dial methods.
This method is intended to be used after the GetDevConfig method provides the default
configuration structure for the modem. Additional configuration settings, or port options,
can be defined for the session. Changes made through SetDevConfig will remain in effect
until the SelectedDevice is changed or the application is terminated. This method will not
change the modem definition in the modemcap database.
StatusDisplay
property
9
10
11
12
13
14
15
16
17
TAdModem Component 477
1
1
TAdModemStatus Component
2
3
4
Figure 13.2 shows the dialog box that the TAdModemStatus component displays.
6
7
Figure 13.2: TAdModemStatus dialog box.
The Status label displays a string describing the current TAdModem.ModemState property
value, and indicates what the TAdModem is doing. The Using label displays the
TAdModem.SelectedDevice.Name property value and the serial port that is being used. The
Elapsed time label displays the number of seconds that have elapsed since the current
operation began.
The Cancel button will cancel the operation by calling the CancelCall method of the
TAdModem component.
8
9
10
11
12
13
14
15
16
17
1
1
The down arrow button will display a more detailed status dialog, as shown in Figure 13.3.
1
2
3
4
6
Figure 13.3: TAdModemStatus expanded dialog box.
To create a custom status dialog box, the OnModemStatus event of the TAdModem
component can be used to update a separate form in your application, or to update a status
bar. You can also create a new component descending from the TApdAbstractModemStatus
class. The UpdateStatus method of the TApdAbstractModemStatus class is automatically
called by the TAdModem component whenever the OnModemStatus event of the
TAdModem component is generated. This method must be implemented to update your
custom dialog. See the AxMdmDlg.pas unit for details on creating a custom dialog box.
Hierarchy
8
9
10
11
TComponent (VCL)
! TApdBaseComponent(OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
12
TApdAbstractModemStatus(AdMdmDlg)
13
TAdModemStatus(AdMdmDlg)
14
Properties
Caption
Started
StatusDialog
15
! Version
16
Methods
UpdateDisplay
17
TAdModemStatus Component 479
1
1
Reference Section
Caption
property
2
property Caption : string
Started
Default: False
7
8
! Indicates whether the status dialog box has been created and initialized.
The TForm descendant specified by the StatusDialog component is created and initialized
when the UpdateDisplay method is called for the first time. Started indicates whether
StatusDialog has been created. When the StatusDialog is no longer needed, the form is
destroyed and Started is set to False.
Started is used by the TAdModemStatus dialog, it is available, but not required, for custom
status dialogs.
See also: StatusDialog, UpdateDisplay
9
10
11
12
13
14
15
16
17
1
1
StatusDialog
property
3
4
6
7
method
procedure UpdateDisplay(
Modem : TAdCustomModem; const Str0, Str1, Str2, Str3 : string);
8
9
10
Modem is the TAdCustomModem whose status has changed. Str0, Str1, Str2 and Str3 are
strings that can be used to provide additional status indicators for the display.
11
12
13
14
15
16
17
TAdModemStatus Component 481
1
1
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TAdModemStatus Component 482
1
1
1
2
Many communications applications need to transfer files or other large amounts of data
from one machine to another. This could be accomplished by having the sender call
PutBlock repeatedly and the receiver call GetBlock correspondingly. However, the
application would have a tremendous amount of detail work still to do. It would need logic
to transfer file name and size information, to check for and recover from transmission
errors, to handle file I/O, etc., etc.
3
4
Thats why Async Professional provides standard, tested, reliable, high performance file
transfer protocols. The term protocol means that both sides of the communication link
behave in a clear, well-defined manner following agreed-upon rules. The rules vary among
the different protocols and some protocols offer more control and features than others. At a
minimum, each protocol handles file I/O and serial port I/O and checks for errors. Some
protocols also include error correcting logic, multi-file transfers, and automatic recovery
after partial file transfers.
5
6
7
Async Professional offers the most widely used industry standard file transfer protocols, as
shown in Table 14.1.
Protocol
Component
Description
Xmodem
TApdProtocol
10
XmodemCRC
TApdProtocol
11
Xmodem1K
TApdProtocol
Xmodem1KG
TApdProtocol
Ymodem
TApdProtocol
YmodemG
TApdProtocol
Zmodem
TApdProtocol
12
13
14
15
16
17
483
1
1
Component
Description
Kermit
TApdProtocol
ASCII
TApdProtocol
ASCII stream with inter-character and interline delays. See ASCII on page 519 for more
information.
FTP
TApdFTPClient
5
6
7
Three related classes are also described in this chapter. TApdAbstractStatus defines a
mechanism by which the protocol can report its status (percent completion, transfer rate,
etc.) to the user. TApdProtocolStatus derives from TApdAbstractStatus to present protocol
status in a particular style. TApdProtocolLog is a small component that writes to a log file
the status of each file transferred by an associated TApdProtocol component.
8
9
10
11
12
13
14
15
16
17
484 Chapter 14: File Transfer Protocols
1
1
General Issues
The Async Professional protocol engine is implemented in a group of units with names like
AwAbsPcl (abstract protocol services), AwXmodem (Xmodem protocol), AwKermit
(Kermit protocol), etc. These units are linked directly into your application. The
TApdProtocol component, implemented in the AdProtcl unit, is a shell around the protocol
engine.
The protocol engine works in the background by using Async Professional timer, data
available, and data match triggers. Windows can continue with other tasks while a file
transfer is in progress as long as the other tasks yield properly for other events.
The following subsections document issues that arise for all types of file transfers that use
the Async Professional protocol engine. Note that the following general issues do not relate
to the TApdFTPClient component.
Buffer sizes
When a TApdComPort component is created, you specify the input and output buffer sizes
that the Windows communications driver is to use. An interactive communications process
such as a terminal window can safely use small buffer sizes, say 4K bytes for input and
output. A protocol file transfer requires larger buffers. Why? Consider how a file transfer
program is likely to be used under Windows.
8
9
Once a file transfer starts, it is likely that the user will work in another window until the file
transfer finishes. Because the transfer is running as a background application, it is at the
mercy of other Windows tasks. Many Windows applications and built-in Windows
operations can hog the CPU to an extent that prevents the background transfer from
succeeding.
10
To different degrees, all file transfer protocols are time-critical. They must respond to
incoming events in a timely fashion, usually within a few seconds. If they fail to respond in
the required time, the remote protocol software times out and repeats the failed operation.
Such timeouts and repetitions at best reduce the protocol transfer rate and at worst can
cause the protocol to fail.
12
In practice, it takes a very ill-behaved program or unusual user (e.g., someone who spends
30 seconds to move a window) to cause most protocols to fail. But this can happen and your
application should do whatever it can to minimize the chances.
One of the things your program can do is use a large input buffer. The Windows
communications driver continues to receive data and store it in the input buffer even if the
associated application program isnt getting any time to run. With a 30K byte input buffer
and a data rate of 1600 characters per second, the buffer can hold 19 seconds worth of
11
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
incoming data before overflowing. When the application eventually regains control it
processes all received data before relinquishing control. The input buffer is then ready to
hold another 19 seconds worth of data.
A large output buffer is also valuable when transmitting files. Streaming protocols such as
YmodemG and Zmodem, and even Kermit to a lesser degree, typically transmit until they
fill the output buffer, then relinquish control. They dont regain control until the buffer
drains enough to hold another data block and Windows can process the associated status
trigger message.
If the status trigger message is delayed because another Windows application didnt yield,
the Windows communications driver continues to transmit the data remaining in the output
buffer. Using the same numbers as the input buffer example, the driver can transmit
independently for up to 19 seconds before running out of data.
When transmitting files under protocol control, the output buffer size must be at least 2078
bytes (i.e., 2K plus 30 bytes). This size is required because the protocols send protocol data
to the port by copying the entire block into the output buffer. If the block size is 1024 bytes
and every character is escaped (preceded by a special character that prevents the link from
misinterpreting the data as a control sequence), the output buffer must hold 2048 bytes. The
extra 30 bytes is a safety margin provided so that the protocol doesnt need to check for
output buffer space for block check characters and a subsequent header, if there is one. The
protocols use the direct copy approach because its much faster than calling PutChar for
each character in the block.
In summary, your application should use input and output buffers that are as small as
possible. However, the smallest possible buffer might actually be quite large, even as large as
32K, for applications that are designed to run in the background.
Protocol events
12
The protocol component generates several kinds of events. General descriptions of these
events follow:
13
OnProtocolAccept
14
15
16
Generated as soon as the protocol window knows the name of an incoming file. This
provides an opportunity to accept or reject the file, or to change its name. See the
OnProtocolAccept event on page 544 for details about how to handle this event. Also see
AcceptFile processing on page 495.
17
486 Chapter 14: File Transfer Protocols
1
1
OnProtocolError
procedure(CP : TObject; ErrorCode : SmallInt) of object;
Generated when an unrecoverable error occurs. Recoverable errors do not generate this
message because such errors are a routine part of transferring files and the failed operation
is retried automatically. See OnProtocolError (page 545) for details. Also see Error
handling on page 488.
1
2
3
OnProtocolFinish
procedure(CP : TObject; ErrorCode : SmallInt) of object;
Generated after all files have been transferred or after the protocol terminates due to an
unrecoverable error. This event also sends the final result code of the protocol.
OnProtocolLog
Generated at the start and end of transferring each file. This provides an opportunity to log
the status of each file transfer. See OnProtocolLog (page 546) for details. Also see Protocol
logging on page 493.
OnProtocolNextFile
Generated whenever it is time to transmit another file. By default this message is handled by
the protocol component, which returns the name of the next file that matches the FileMask
property. Programs can intercept this event to provide other ways to choose the next file. See
OnProtocolNextFile (page 547) for details. Also see NextFile processing on page 494.
OnProtocolStatus
9
10
11
Generated at regular intervals so that programs can display the progress of the protocol. See
OnProtocolStatus (page 548) for details. Also see Protocol status on page 489.
12
13
Aborting a protocol
There will certainly be times when a protocol in progress must be canceled (e.g., when
something goes wrong at the remote computer or the user simply decides not to continue
the transfer). Async Professional protocols provide for this situation with the
CancelProtocol method.
To cancel any protocol simply call the CancelProtocol method of the TApdProtocol
component. This method sends an appropriate cancel sequence to the remote computer and
terminates. The protocol component remains intact, ready to handle additional protocol
transfers.
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
When protocol transfers take place over a modem link it is a good idea to monitor the DCD
(data carrier detect) line and abort the protocol if carrier is lost. The DCD line goes high
when modems first connect and remains high until one of the modems hangs up.
Occasionally, line noise or other disturbances in the telephone network break the
connection between the modems, causing DCD to go low.
Some protocols quickly detect that the remote isnt acknowledging after the connection is
broken. These protocols soon abort with an error code of ecTimeout or ecTooManyErrors.
By contrast, streaming protocols can take a very long time to notice that the connection is
broken because they dont require acknowledgments.
The protocol component provides an option to handle dropped carrier automatically. Set
the AbortNoCarrier property to True before calling StartTransmit or StartReceive and the
protocol engine automatically aborts if the DCD line is not high at any point during the
protocol. The protocol cancels itself immediately and generates an OnProtocolFinish event
with an error code of ecAbortNoCarrier.
Using the AbortNoCarrier property is better than checking DCD and calling
CancelProtocol in your own code. When you do this, the protocol engine sends a cancel
sequence to the remote computer. If hardware flow control is enabled and the modem has
lowered the DSR or CTS signals as well as DCD, the protocol waits several seconds before
deciding it cant send the cancel command, leading to an unnecessary delay for the
application. The AbortNoCarrier option prevents the protocol engine from sending the
cancel sequence, so the protocol stops immediately.
Error handling
All protocol transfers are subject to errors, including parity errors, files not found, and other
file I/O errors. Whenever possible the protocol window handles errors internally by retrying
an operation or requesting the remote computer to retry. At some point, however, it
determines that the situation is unrecoverable and generates an OnProtocolError event. An
application should include a handler for this event. Following is a simple example:
procedure Form1.ApdProtocol1ProtocolError(
CP : TObject; ErrorCode : SmallInt);
begin
ShowMessage('Fatal protocol error: ' + ErrorMsg(ErrorCode));
end;
15
This event handlers sole task is to display a message about the error. ErrorMsg is a function
from the AdExcept unit that returns an English string for any Async Professional error code.
16
See Error Handling and Exception Classes on page 900 for additional information about
errors.
17
488 Chapter 14: File Transfer Protocols
1
1
Protocol status
A protocol transfer can last a few seconds or several hours depending on the size and speed
of the transfer. Because the protocol component handles the details of the transfer from start
to finish, your applications code is not executing during this entire time. You and your users
certainly want to know whats happening as the transfer progresses, so Async Professional
provides a hook for your application to regularly regain control during this time.
During a protocol transfer the protocol window frequently generates an OnProtocolStatus
event. This gives your code the opportunity to monitor and display the progress of the
protocol. Following are code fragments that illustrate how:
TForm1 = class(TForm)
...
FN: TLabel;
BT: TLabel;
BR: TLabel;
...
end;
2
3
4
6
7
procedure TForm1.ApdProtocol1ProtocolStatus(
CP : TObject; Options : Word);
begin
case Options of
apFirstCall :
...do setup stuff
apLastCall :
...do cleanup stuff
else
{show status}
FN.Caption := ApdProtocol.FileName;
BT.Caption := IntToStr(ApdProtocol.BytesTransferred);
BR.Caption := IntToStr(ApdProtocol.BytesRemaining);
end;
end;
8
9
10
11
12
13
14
15
Options is set to apFirstCall the first time the protocol generates the event after being started
by StartTransmit or StartReceive. Options is set to apLastCall the last time it generates the
event, when the protocol is finished. Options equals zero for all other times.
16
17
1
1
The rest of the information about protocol progress is obtained by reading the values of
various TApdProtocol properties, including:
BlockCheckMethod - the type of block check calculation used by the protocol. See the
reference section entry for this property (page 530) for a complete description of all block
check types.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BlockErrors - the number of errors for the current block. This is the number of times the
protocol has unsuccessfully tried to transmit or receive the current block. It is reset to zero
when the block is finally accepted.
BlockLength - the current transfer block length. Although this value is usually static, some
protocols modify the length of the block on the fly. Zmodem in particular reduces the block
length after several block errors in a row and raises it again after several good blocks.
BlockNumber - the number of blocks transmitted so far. This is obtained by dividing the
number of bytes transferred by the current block length, so it will change if the block length
changes.
BytesRemaining - the size of the file minus BytesTransferred. When the file size isnt known,
BytesRemaining returns zero.
BytesTransferred - the number of bytes transmitted or received so far. When transmitting,
this number is sometimes only an estimate. The uncertainty comes from the fact that the
protocol window doesnt know when a particular byte has actually been transferred.
BytesTransferred is the number of bytes the protocol window has transferred to the output
buffer of the communications driver, minus the number of bytes that the driver reports are
currently in the buffer. Unfortunately, this calculation is still imperfect because its
impossible to know how much of the output buffer holds actual file data and how much
holds overhead characters needed by the protocol. Each protocol has a few simple rules it
uses to estimate this proportion, which in practice yield good estimates.
ElapsedTicks - the number of ticks elapsed since the protocol started. In order to provide
accurate CPS values, the protocol engine doesnt start the timer until it receives the first
block from the remote computer.
FileDate - the date and time of the file being transmitted or received. If the protocol does not
support this feature, FileDate returns zero.
FileLength - the size of the file being transmitted or received. For transmitted files the file
size is always known. For received files the file size is known only if the protocol supports
this feature and the receiver has received this information. If the file size is not known,
FileLength returns zero.
FileName - the fully qualified name of the file that is being received or transmitted. When
receiving with a protocol that does not transfer the file name, FileName simply returns the
name previously assigned to it.
1
1
InitialPosition - used only for resumed file transfers using the Zmodem protocol. To display
an accurate transfer rate (CPS, or character per second, rate), status routines for these
protocols must subtract InitialPosition from BytesTransferred to obtain the actual number
of bytes transferred during this session. If this is not a resumed file transfer, InitialPosition
returns zero.
ProtocolError - the code of the last error encountered by the protocol. This equals zero
except for the first status call after an error is encountered. See Error Handling and
Exception Classes on page 900 for additional information.
ProtocolStatus - a code that indicates the current state of the protocol. Table 14.2 shows all of
the possible values. The usual status value is psOK, which means that the protocol is
operating normally. Other status values indicate recoverable error conditions, protocol
resume conditions, protocol start-up states, and internal protocol states. Fatal protocol
errors are not represented by protocol states; they are first reported via the OnProtocolError
event. However, it is possible that a final status message might be sent after a fatal error
occurs.
1
2
3
4
6
7
Value
Explanation
psOK
Protocol is OK.
psProtocolHandshake
psInvalidDate
psFileRejected
psFileRenamed
psSkipFile
psFileDoesntExist
psCantWriteFile
psTimeout
psBlockCheckError
psLongPacket
10
psDuplicateBlock
11
psProtocolError
12
Error in protocol.
psCancelRequested
13
Cancel requested.
psEndFile
14
At end of file.
8
9
10
11
12
13
14
15
16
17
General Issues 491
1
1
1
2
3
4
5
Table 14.2: Possible values for the ProtocolStatus property of TApdProtocol (continued)
Status Code
Value
Explanation
psSequenceError
15
psAbortNoCarrier
16
psGotCrcE
17
psGotCrcG
18
psGotCrcW
19
psGotCrcQ
20
TotalErrors - the number of errors encountered since the current file was started. It is reset
only when a new file is started.
Various properties that describe the option settings for the protocol may also be used within
the status routine. These include HonorDirectory, IncludeDirectory, RTSLowForWrite,
AbortNoCarrier, and other options that are specific to particular protocols.
10
The StatusInterval property, which defaults to 18, is the maximum number of ticks between
OnProtocolStatus events. The protocol generates an OnProtocolStatus event after every
significant event (received a file name, received a complete block, etc.) or after at most
StatusInterval ticks.
11
Async Professional includes a mechanism for providing an automatic protocol status display
without programming, through the TApdProtocols StatusDisplay property:
12
13
14
15
16
17
492 Chapter 14: File Transfer Protocols
1
1
Protocol logging
1
2
3
File transfer is often an automated process. For example, an application might send all of the
days transaction files to a remote computer during the night. In this case the application
would also keep a record of the files that were successfully transmitted and those that
werent.
The Async Professional protocol logging feature is ideal for this kind of application. It
provides the opportunity to log information about each received or transmitted file and
whether the transfer succeeded.
To support logging, the protocol component generates on OnProtocolLog event at the start
and end of each file transfer. The event passes a parameter that identifies the current logging
action. Here is an example that handles this event:
procedure TForm1.ApdProtocol1ProtocolLog(
CP : TObject; Log : Word);
begin
case Log of
lfReceiveStart,
lfTransmitStart :
CurrentFile.Caption := ApdProtocol1.FileName;
6
7
8
9
10
lfReceiveOk,
lfTransmitOk :
GoodList.Items.Add(ApdProtocol1.FileName);
11
lfReceiveFail,
lfTransmitFail :
BadList.Items.Add(ApdProtocol1.FileName);
12
13
lfReceiveSkip
lfTransmitSkip :
SkipList.Items.Add(ApdProtocol1.FileName);
end;
end;
14
The example shows every possible logging value. The meaning of the various logging
conditions should be clear except for perhaps lfReceiveSkip and lfTransmitSkip.
lfReceiveSkip is generated by any of the protocols when an incoming file is rejected by the
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NextFile processing
Several of the protocols provided by Async Professional can transmit and receive batches of
files. When the protocol is ready to transmit a new file it generates an OnProtocolNextFile
event. The event handler responds by returning the name of the next file to transmit, or an
empty string to terminate the batch.
In most cases, you dont need to worry about handling this event because the protocol
component does so itself. The protocol component determines the next file to send with
DOS filemask processing, using the mask assigned to the FileMask property.
For non-batch protocols like Xmodem the file mask should not contain wildcards. Such
protocols are capable of transmitting only a single file at a time, and if the mask matches
more than one file only the first matching file is transmitted.
17
494 Chapter 14: File Transfer Protocols
1
1
When the filemask technique is not adequate, you can write an event handler that
implements whatever behavior you need.
Here is an OnProtocolNextFile event handler that provides custom NextFile processing.
const
FileIndex : Word = 0;
File1 = 'C:\AUTOEXEC.BAT';
File2 = 'C:\CONFIG.SYS';
File3 = 'C:\ASYNCPRO\ADPORT.PAS';
...
procedure TForm.ApdProtocol1ProtocolNextFile(
CP : TObject; var FName : string);
begin
Inc(FileIndex);
case FileIndex of
1 : FName := File1;
2 : FName := File2;
3 : FName := File3;
else FName := '';
end;
end;
1
2
3
4
6
7
8
This example sends only the three files named by the constants File1, File2, and File3. The
event handler returns each string in sequence. After the three files are transmitted, the
handler returns an empty string to tell the protocol that no more files are available to
transmit.
Async Professional does not provide built-in support for transmitting an arbitrary list of
files. Thats because VCL provides the TStringList class, which can easily be combined with
an OnProtocolNextFile event handler to send any list of files. The EXFLIST example
program shows how.
9
10
11
12
AcceptFile processing
When receiving files, there may be times when you dont want the incoming file. Consider,
for example, an open BBS where a first time caller is attempting to upload a 10M byte file at
2400 baud. Since this would tie up the BBS for more than 11 hours you probably would want
to refuse it immediately. If the caller is using a protocol that transmits the file size in advance,
you can detect that its bigger than you want and refuse the upload.
As another example, suppose that a BBS has a well-publicized rule that it accepts only LZH
uploads and it detects that an incoming file has a ZIP extension. If a caller is using a protocol
that transmits the file name in advance, you can refuse an upload immediately.
13
14
15
16
The OnProtocolAccept event can be used to build such behavior into your application.
17
General Issues 495
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Note that Zmodem, alone among the Async Professional protocols, has built-in
functionality for certain kinds of accept file functions. For example, it can reject an upload
that would overwrite an existing file, or accept it only if the uploads time stamp is newer
than the existing file. These options are described fully in Zmodem on page 507. The
AcceptFile function is more general than this, and applies to all of the Async Professional
protocols.
Once the protocol knows the name of an incoming file, but before it starts receiving data, it
generates an OnProtocolAccept event. A form can respond to the event by setting the Accept
parameter to True to accept the file, or False to refuse it. By default, all files are accepted.
For all protocols except Zmodem, the first rejected file terminates the entire batch transfer.
Zmodem has provisions for skipping files, and the transmitter picks up again with the next
file after the rejected one.
The OnProtocolAccept event also provides an opportunity to rename an incoming file if its
current name isnt acceptable. For example, if a file name conflicts with an existing file, you
can accept the file but change its name.
Note that all protocols have built-in options for handling incoming file name collisions. See
the WriteFailAction property on page WriteFailAction property for a complete description.
You dont need to write an OnProtocolAccept event handler if these constants provide the
needed behavior.
Here is an event handler that rejects all files with the ARC extension:
procedure TForm1.ApdProtocol1ProtocolAccept(
CP : TObject; var Accept : Boolean; var FName : string);
begin
Accept := AnsiCompareText(ExtractFileExt(FName), '.ARC') <> 0;
end;
This example examines the extension of the incoming file and sets Accept to False if it
matches .ARC. Note that the function can check various properties to obtain additional
information about the file. In particular, the file size is available by reading the FileLength
property for protocols that transmit the size.
Internal logic
The protocol component has so far been described as a black boxyou initialize it and call
StartTransmit or StartReceive to perform the protocol magic. Now it is time to look inside
the box, at how the protocol engine works. With this additional information, you will be
able to use the protocols more effectively and take better advantage of the events generated
by the protocol window.
17
496 Chapter 14: File Transfer Protocols
1
1
Receiving files
When receiving files, the protocol window employs the following logic shown in Figure
14.1. This diagram generally applies to all protocols.
1
No connect
handshake
2
No file
3
generate OnProtocolLog
6
4
Fail
generate OnProtocolAccept
Fail
8
9
6
Fail
open file
10
7
Fail
11
12
13
close file
14
generate OnProtocolLog
10
(batch only)
15
end protocol
16
Figure 14.1: Protocol window logic when receiving files.
17
General Issues 497
1
1
The protocol first attempts to handshake with the remote machine. A handshake consists
of a valid response to an initial character sequence sent by the transmitter. If the handshake
is unsuccessful after a specified number of retries, the protocol ends.
If the handshake is successful, the transmitter is asked for the name of the next file to
transmit. It responds by sending a block containing the name.
The protocol generates the OnProtocolLog event to give the application an opportunity to
record the file name or take any other special action needed at the start of the transfer. Note
that the logging routine receives the file name before the OnProtocolAccept event handler
has had a chance to modify it.
4
5
6
7
8
Next the protocol generates the OnProtocolAccept event. If the message handler sets Accept
to False, the file is skipped and control is transferred to step 9. Otherwise, the built-in
WriteFail options or Zmodems built-in file management rules are applied. If the protocol
fails at this point, control is transferred to step 9.
The received file is created using the name from the file name header, perhaps as modified
by the OnProtocolAccept event handler. Step 6 also allocates work buffers and initializes
several internal variables used to manage an 8K byte receive buffer. If the open fails, control
is transferred to step 8, which disposes of buffers and closes the file.
10
The actual transfer of data comes next in step 7. The internal operations of this step vary
tremendously among the protocols, so it is condensed in this diagram. The
OnProtocolStatus event is generated at least once for each block received. If unrecoverable
errors occur for any reason (user abort, broken connection, disk full, etc.), control is
transferred to step 8.
11
After the file transfer is complete, the file is closed in step 8. Then the OnProtocolLog event
is generated with information regarding whether the file was received OK, rejected, or failed.
12
In a batch protocol, control returns to the top of the loop to get another file header. If one is
received, the whole process is repeated. Otherwise, the protocol is ended by coordinating
with the transmitter and cleaning up.
13
14
15
16
17
498 Chapter 14: File Transfer Protocols
1
1
Transmitting files
When transmitting files, the protocol window employs the following logic as shown in
Figure 14.2. This diagram generally applies to all protocols.
1
No connect
handshake
2
No file
3
generate OnProtocolLog
6
4
Fail
open file
5
Fail
10
close file
7
generate OnProtocolLog
11
(batch only)
12
8
end protocol
13
Figure 14.2: Protocol window logic when transmitting files.
The protocol first attempts to handshake with the remote machine. A handshake consists of
sending an initial character sequence and waiting for a valid response. If the handshake is
unsuccessful after a specified number of retries, the protocol ends.
If the handshake is successful, the protocol generates an OnProtocolNextFile event. The
default handler of the component returns the next file based on a file mask, or a custom
event handler can return the next file using its own logic.
14
15
16
17
1
1
1
2
3
4
5
6
7
The protocol generates the OnProtocolLog event to give the application an opportunity to
record the outgoing file name or take any other special action needed at the start of the
transfer.
The outgoing file is opened in step 4. This step also allocates work buffers and initializes
variables used to manage an 8K byte send buffer. If any of these steps fail, control is
transferred to step 6 to clean up.
The actual transfer of data comes next in step 5. The file is read in 8K byte blocks and sent
using the block size native to the protocol. The OnProtocolStatus event is generated at least
once for every block sent. If unrecoverable errors occur, control is immediately transferred
to step 6.
After the file transfer is complete, the file is closed and buffers are disposed in step 6. Then
the OnProtocolLog event is generated with information regarding whether the file was
transferred OK, rejected, or failed.
In a batch protocol, control returns to the top of the loop to get another file to send. If one is
available, the whole process is repeated. Otherwise, the protocol is ended by coordinating
with the receiver and cleaning up.
8
9
10
11
12
13
14
15
16
17
500 Chapter 14: File Transfer Protocols
1
1
Xmodem
Xmodem is the oldest protocol supported by Async Professional. It was developed and first
implemented by Ward Christensen in 1977 and placed in the public domain. Since then, it
has become an extremely popular protocol and continues in use today (although at a
diminished frequency).
Xmodem is also the simplest, and perhaps the slowest, protocol supported by Async
Professional. Xmodem uses blocks of only 128 bytes and requires an acknowledgment of
each block. It uses only a simple checksum for data integrity.
What follows is a simplified description of the Xmodem protocol, although it describes far
more than is required to actually use the protocol in Async Professional. For additional
details on the internals of the Xmodem protocol, see the YMODEM.DOC file in the
PROTDOC.LZH archive. Figure 14.3 shows the format for XModem blocks.
3
4
6
7
<SOH>
<block#>
not
<block#>
<checksum>
The <SOH> character marks the start of the block. Next comes a one byte block number
followed by a ones complement of the block number. The block number starts at one and
goes up to 255 where it rolls over to zero and starts the cycle again. Following the block
numbers are 128 bytes of data and a one-byte checksum. The checksum is calculated by
adding together all the data bytes and ignoring any carries that result. Table 14.3 describes a
typical Xmodem protocol transfer.
Receiver
<---
15
<ACK>
--->
<---
13
14
<ACK>
--->
<---
<EOT>
<NAK>
--->
<---
11
12
10
16
<ACK>
17
Xmodem 501
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
The receiver always starts the protocol by issuing a <NAK>, also called the handshake
character. It waits 10 seconds for the transmitter to send a block of data. If it doesnt get a
block within 10 seconds, it sends another <NAK>. This continues for 10 retries, after which
the receiver gives up.
If the receiver does get a block, it compares the checksum it calculates to the received
checksum. If the checksums differ, the receiver sends a <NAK> and the transmitter resends
the block. If the checksums match, the receiver accepts the block by sending an <ACK>.
This continues until the complete file is transmitted. The transmitter signifies this by
sending an <EOT>, which the receiver acknowledges with an <ACK>.
Either side can cancel the protocol at any time by sending three <CAN> characters (^X).
However, during an Xmodem receive the receiver cannot tell whether the <CAN>
characters are real data or a cancel request. The sequence is recognized as a cancel request
only when it comes between blocks. Hence, more than three <CAN> characters are
sometimes required to cancel the receiver. Sufficient characters are required to complete the
current block, then three more <CAN> characters to cancel the protocol.
From this description several things become clear. First, this protocol does not transfer any
information about the file being transmitted. Hence, the receiver must assign a name to the
incoming file.
The receiver also doesnt know the exact size of the file, even after it is completely received.
The received file size is always a multiple of the block size. This Xmodem implementation
fills the last partial block of a transfer with characters of value BlockFillChar, whose default
is ^Z. .BlockFillChar is a typed constant defined in AwTPcl.pas. To change the default
BlockFillChar, simply assign the new character to that typed constant.
Xmodem often exhibits a start-up delay. The transmitter always waits for a <NAK> from
the receiver as its start signal. If the receiving program was started first, the transmitter
probably missed the first <NAK> and must wait for the receiver to time out and send
another <NAK>.
Xmodem offers no escaping of binary control characters. Escaping means that characters
can be transformed before being transmitted to prevent certain binary data characters, such
as <XON>, from being interpreted as data link control characters. As a result, you cant use
software flow control in an Xmodem transfer (since the flow control software would
misinterpret <XON> or <XOFF> characters in the data stream as flow control requests) and
Xmodem itself cant tell the difference between <CAN> characters used for protocol
cancellation and for data.
The only merit of the basic Xmodem protocol is that it is so widespread that its probably
supported by any microcomputer communications program you can find, thus providing a
lowest common denominator between systems.
17
502 Chapter 14: File Transfer Protocols
1
1
Xmodem extensions
Xmodem has been tweaked and improved through the years. Some of these variations have
become standards of their own and are supported by Async Professional. These Xmodem
extensions are treated as separate protocols enabled by assigning a different value to the
ProtocolType property.
The first of these improvements is called Xmodem CRC, which substitutes a 16 bit CRC
(cyclic redundancy check) for the original checksum. This offers a much higher level of
data integrity. When given the opportunity, you should always choose Xmodem CRC over
plain Xmodem.
The receiver indicates that it wants to use Xmodem CRC by sending the character C instead
of <NAK> to start the protocol. If the transmitter doesnt respond to the C within three
attempts, the receiver assumes the transmitter isnt capable of using Xmodem CRC. The
receiver automatically drops back to using checksums by sending a <NAK>.
Another popular extension is called Xmodem 1K. This derivative builds on Xmodem CRC
by using 1024 byte blocks instead of 128 byte blocks. When Xmodem 1K is active, each
block starts with an <STX> character instead of an <SOH>. Xmodem 1K also uses a 16 bit
CRC as the block check.
A larger block size can greatly speed up the protocol because it reduces the number of times
the transmitter must wait for an acknowledgment. However, it can actually reduce
throughput over noisy lines because more data must be retransmitted when errors are
encountered. The implementation of Xmodem 1K in Async Professional drops back to 128
byte blocks whenever it receives more than 5 <NAK> characters in a row. Once it drops
back to 128 byte blocks, it never tries to step back up to 1024 byte blocks.
The final Xmodem extension supported by Async Professional is Xmodem 1KG. This
streaming protocol is requested when the receiver sends G as the initial handshake
character instead of <NAK>. Streaming in this context means that the transmitter
continuously transmits blocks without waiting for acknowledgements. In fact, all blocks are
assumed to be correct and the receiver never sends acknowledgements. If the receiver does
encounter a bad block, it aborts the entire transfer by sending a <NAK>.
You shouldnt even consider using this streaming protocol unless you are using error
correcting modems with their error control features turned on. In fact, you might want to
have your application refuse to use Xmodem 1KG if error correcting modems arent
detected. The OnGotErrCorrection event of the TApdModem component (see page 461)
can be used to detect an error correcting connection. The advantage of a streaming protocol
like Xmodem 1KG is its very high throughput. There is no acknowledgement delay, so the
protocol is extremely efficient. Zmodem has this same property, but can also retry and
recover from errors.
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
Xmodem 503
1
1
Ymodem
Ymodem is essentially Xmodem 1K with batch facilities added, which means that a single
protocol session can transfer as many files as you care to transmit. Another important
enhancement is that the transmitter can provide the receiver with the incoming file name,
size, and timestamp.
Ymodem achieves this by adding block zero to the Xmodem 1K protocol. Block zero is
transferred first and contains file information in the format shown in Figure 14.4.
<SOH>
<0>
<255>
<CRChi> <CRClo>
8
Figure 14.4: File information and format for a YModem block zero transfer.
9
10
11
12
13
The <name> field is the only required field. It supplies the name of the file in lower case
letters. Path information can be included but the protocol requires that all \ characters be
converted to /.
The <len> field specifies the file length as an ASCII string. This field allows the receiver to
truncate the received file to discard the filler characters at the end of the last block.
The <date> field is the date and time stamp of the file. It is transmitted as the number of
seconds since January 1, 1970 GMT, expressed in ASCII octal digits (a Unix convention).
Async Professional takes care of properly formatting this block. You dont need to do
anything but specify the name of the file to transmit. When receiving Ymodem files, Async
Professional uses the information in this block, if present, to adjust the size of the received
file and its modification date.
14
15
16
17
504 Chapter 14: File Transfer Protocols
1
1
Receiver
<---
<SOH><0><255><file info><crc>
<ACK>
<---
--->
<ACK>
--->
<ACK>
--->
<---
<SOH><0><255><file info><crc>
<---
<--<EOT>
--->
--->
<---
<ACK>
<---
--->
<---
<EOT>
--->
<SOH><0><255><128 zeros><crc>
--->
<---
<ACK>
10
11
<ACK>
As with the Xmodem protocols, the Ymodem protocol starts when the receiver sends a
handshake character (C) to the transmitter. The transmitter responds with a properly
formatted block zero. The receiver acknowledges this with an <ACK> and then starts a
normal Xmodem CRC protocol by issuing another C handshake character.
12
13
14
15
16
17
Ymodem 505
1
1
1
2
3
4
Ymodem extensions
The Ymodem specification permits Ymodem to use a combination of 128 and 1024 byte
blocks. Most Ymodem protocols start with 1024 byte blocks and drop back to 128 byte
blocks only if repeated errors are detected. Once the block size is reduced to 128 bytes, it is
never stepped back up to 1024.
Like Xmodem, Ymodem also offers a streaming extension called Ymodem G. This is similar
in performance (and drawbacks) to Xmodem 1KG, but like Ymodem itself offers the
advantages of batch transfers and file information.
5
6
7
8
9
10
11
12
13
14
15
16
17
506 Chapter 14: File Transfer Protocols
1
1
Zmodem
Of all the protocols supported by Async Professional, Zmodem offers the best overall mix of
speed, features, and tolerance for errors. The Zmodem protocol has many options and
clearly was meant to have lots of room for growth. The Async Professional implementation
of Zmodem does not cover the entire protocol specification but it does implement the
features most likely to be required by your application. It should generally be your protocol
of choice.
Zmodem was developed for the public domain by Chuck Forsberg under contract to
Telenet. The original purpose was to provide a durable protocol with strong error recovery
features and good performance over a variety of network types (switched, satellite, etc.). It
has generally achieved these design goals.
What follows is a simplified explanation of Zmodem that provides more than enough
information to use it with Async Professional. Refer to the ZMODEM.DOC file of
PROTDOC.LZH for further details.
Zmodem borrows some concepts from Xmodem, Ymodem, and Kermit but is really a
completely new protocol. Instead of adopting the simple block structure of Xmodem and
Ymodem, Zmodem employs headers, data subpackets, and frames. A header contains a
header identifier, a type byte, four information bytes, and some block check bytes. A data
subpacket contains up to 1024 data bytes, a data subpacket type identifier, and some block
check bytes. A frame consists of one header and zero or more data subpackets.
Due to the complexity and variety of the Zmodem header and data subpacket formats, they
are not all detailed here. Instead, Table 14.5 provides a high level look at a sample Zmodem
file transfer.
Table 14.5: Description of a typical ZModem protocol transfer
Sender
Receiver
--->
ZrQinit
--->
ZFile
ZrInit
--->
<---
6
7
8
9
10
11
13
14
ZData
--->
data subpacket
--->
...
12
Explanation
rz<cr>
<---
15
16
17
Zmodem 507
1
1
1
2
Receiver
--->
<---
ZFin
4
5
6
7
8
OO
--->
<---
--->
Receiver acknowledges.
Transmitter signs off.
The ZXxx tags are the header types that the two computers trade back and forth as they
decide what is to be done. You dont need to understand them unless you find yourself trying
to decipher a Zmodem transfer using the Async Professional tracing facility. To do so, youll
likely need to consult the ZMODEM.DOC file and/or the Async Professional source code.
In most cases all data in the file is sent in one ZData frame (the ZData header followed by as
many data subpackets as required). The receiver doesnt have to acknowledge any of the
blocks unless the transmitter specifically asks for it. The Zmodem protocol as implemented
by Async Professional never asks for an acknowledgement; however, it respects such
requests from the transmitter.
Typically, once a file transfer is underway, the receiver interrupts the transmitter only if it
receives a bad block as determined by comparing block check values. An error is reported
by sending a ZrPos header, telling the transmitter where in the file to start retransmitting.
10
The protocol can be canceled at any time if either side sends five <CAN> characters (^X).
11
13
14
Zmodem escapes certain control characters. Escaping means that characters are
transformed before being transmitted to prevent certain binary data characters, such as
<XON> and <CAN>, from being interpreted as data link control characters.
Escaping isnt something you need to enable or disable because its always on. It is mentioned
here because escaping is what permits you to use software flow control with Zmodem. That
isnt possible with the Xmodem/Ymodem family.
15
16
17
508 Chapter 14: File Transfer Protocols
12
Explanation
1
2
3
4
Zmodem escapes all control characters when requested to by the remote protocol.
Protocol options
While the Zmodem specification describes all sorts of features, not all Zmodem
implementations are expected to support all of the features. One of the first things that
happens in a Zmodem protocol is that the receiver tells the transmitter what features it
supports. The transmitter might modify its standard behavior to accommodate the
receivers support (or lack of support) for a particular option.
6
7
Since this process is handled automatically, you generally dont need to worry about it. For
your information, the protocol options that Async Professional Zmodem provides and
doesnt provide are listed here.
10
11
13
Encryption.
LZ data compression.
14
15
Sparse files.
17
Zmodem 509
1
1
1
2
3
4
5
6
Transfer resume
The Zmodem specification describes an option called recover/resume. This option is
requested by the transmitter when it wants to resume a previously interrupted file transfer.
When the receiver sees the request for this option, it compares the incoming file name with
the files in its destination directory. If the incoming file already exists and is smaller than the
one being transmitted, the receiver assumes that the transmitter wants to transfer only the
remaining portion of the file.
When this condition exists, the receiver opens the existing file and moves the file pointer to
the end of the file. It then tells the transmitter to move its file pointer to the same point in its
copy of the file. The transmitter starts sending data from that point, which resumes the
transfer from where it was interrupted.
This option can also be used to append new data to a remote copy of a file.
In either case, you use this option as follows:
ApdProtocol.FileMask := 'BIGFILE';
ApdProtocol.ZmodemRecover := True;
ApdProtocol.StartTransmit;
Zmodem has a variety of file management options built into it. These are simple rules that
tell Zmodem whether or not to accept a file. Table 14.6 shows the possible options.
Table 14.6: ZModem file management options
Option Code
Explanation
zfoWriteNewerLonger
zfoWriteCrc
zfoWriteAppend
zfoWriteClobber
Transfer always.
zfoWriteNewer
zfoWriteDifferent
zfoWriteProtect
The zfoWriteCrc option, which requests that a file be transferred only if its CRC is different
from the remote copys, is not supported. When this option is requested, it is treated the
same as the zfoWriteNewer option.
17
510 Chapter 14: File Transfer Protocols
1
1
The file management options are always requested by the transmitter. To use them, assign a
value to the ZmodemFileOption property before calling StartTransmit. The default
behavior is zfoWriteNewer. For example, to transmit all files regardless of whether such files
already exist on the remote machine, make the following assignment:
1
2
ApdProtocol.ZmodemFileOption := zfoWriteClobber;
Even though the transmitter sets the file management options, Async Professional allows the
receiver to change them. For example, suppose the transmitter has requested
zfoWriteClobber but you want to accept only newer files. In this case you would set the
ZmodemOptionOverride property to True before calling StartReceive:
3
4
ApdProtocol.ZmodemOptionOverride := True;
ApdProtocol.ZmodemFileOption := zfoWriteNewer;
Setting this property to True tells Zmodem to ignore the file management options requested
by the transmitter and to use zfoWriteNewer instead.
Another file management property called ZmodemSkipNoFile is available. Set this property
to True to force the receiver to skip any incoming file that doesnt already exist in the
destination directory.
Whatever file management rules are in effect, the receiver applies them and either accepts
each file or rejects it. If the file is accepted, the file transfer proceeds normally. If the file is
rejected, the receiver sends a ZSkip frame to the transmitter, which stops sending the
current file and moves on to the next one in its list.
8
9
Dont forget that you can implement your own file management rules with an
OnProtocolAccept event handler.
10
11
The Zmodem protocol decreases or increases the number of bytes transmitted per block in
response to retransmission requests, usually due to poor line conditions or random line
errors. The rationale is that small blocks can transmit more frequently without errors, since
theres less time for a small block to be hit by line noise. And, even if a small block is
corrupted by noise, it is faster to retransmit than a large block.
The protocol employs the following logic to control the block size. If the transmitter receives
an unsolicited request from the receiver to resend data, it reduces the block size from 1024 to
512. If the transmitter receives another request to resend, it reduces the block size from 512
to 256. It never reduces the block size below 256 bytes. Conversely, the transmitter raises the
block size immediately back to 1024 bytes when it sends four blocks in a row without
receiving any requests to resend.
12
13
14
15
16
17
Zmodem 511
1
1
1
2
Similar logic is employed with 8K Zmodem, which uses 8192 byte blocks by default. The
block size is halved for each retransmission request received, down to a minimum of 256
bytes. The block size is increased to 8K bytes in a single step after four blocks are
transmitted without any requests to resend.
Block size control is automatic and cannot be disabled. While this behavior is not
documented in the public domain Zmodem specification, it is the process followed by the
popular DSZ program and is acceptable to any common Zmodem implementation.
5
6
7
8
9
Async Professional Zmodem also includes support for 8K byte blocks. This behavior is
outside the public domain specification and was added largely for programmers who need
to transfer files to or from several popular BBS and FIDONet mailer programs. Since large
blocks are not supported by all common Zmodem implementations, their use is not
automaticyou must specifically enable them before starting a file transfer by setting the
Zmodem8K property to True.
The output buffer size of the port object used by the protocol window must also be large
enough to support the 8K option. The output buffer must be capable of holding an entire 8K
block with escaping, which in the worst case can double the size of the block. Hence, the
output buffer must be at least 2*8192+30, or 16414, bytes. (See Buffer sizes on page 485
for more information.)
10
11
12
13
14
15
16
17
512 Chapter 14: File Transfer Protocols
1
1
Kermit
The Kermit protocol was developed to allow file transfers in environments that other
protocols cant handle. Such environments include links that only pass 7 data bits, links that
cant handle control characters, computer systems that cant handle large blocks, and diverse
other links such as those between a PC and a mainframe.
Kermit is a public domain protocol that was developed at Columbia University. (The name
refers to Kermit the Frog, from The Muppet Show.) What follows is a simplified explanation
of Kermit that provides more than enough information to use it with Async Professional.
For additional details, get the Kermit protocol specification from Columbia University,
Kermit Distribution, Department OP, 612 West 115th Street, New York, NY 10025.
3
4
Character quoting
Character quoting means pretty much the same thing that escaping means in Zmodem. The
character is replaced by a quote character and a modified form of the original character. The
quote character tells the receiver how to convert the modified character back to its original
value. Quoting ensures that certain binary characters are never put into the data stream
where they could be misinterpreted by a modem or another part of the serial link.
Although Zmodem transforms only a few critical characters such as <XON> and <XOFF>,
Kermit quotes nearly all characters. This is one of the features that permits Kermit to run in
nearly any environment. When quoting is finished, a Kermit data packet consists almost
entirely of printable ASCII characters. The only exceptions are an <SOH> character at the
start of each packet and a <CR> at the end.
Kermit quotes control characters by replacing them with a quote character and a modified
version of the control character. For example, ^A becomes #A where # is the quote
character. The process of converting ^A to A is called Ctl and it works like this:
7
8
9
10
11
12
13
14
15
16
17
Kermit 513
1
1
1
2
3
Kermit has a simple built-in data compression mechanism called run length encoding.
When it sees a long string of repeated characters, it compresses the string into a quote
character, a length byte, and the repeated character. Obviously, there must be at least 4
repeated characters before there is any compression. The quote character for run length
encoding is ~. Hence, the string AAAAA becomes ~%A, where % is equivalent to a
binary 5 after the ToChar operation.
Kermit packets
4
5
<SOH>
<len>
<seq>
<type>
<check>
<term>
6
7
8
9
10
11
12
The <SOH> character, also called the mark field, indicates the start of a Kermit packet.
The length byte specifies the number of bytes that follow. Since it must be transmitted as a
printable 7 bit character the binary maximum value is 94, which means that the maximum
length of a normal Kermit packet is 96 bytes including the <SOH> and the <length> field.
The <seq> byte is a packet sequence number in the range of 0 to 63. After 63 it cycles
back to 0.
The <type> byte describes the various Kermit packet types, which are analogous to the
Zmodem frame types.
The data field contains up to 91 bytes including all quote characters. The number of actual
data bytes could be considerably less, particularly if binary data is being transmitted.
13
The standard Kermit <check> field is a single-byte checksum. Kermit offers two optional
block check methods called two-byte checksum and three-byte CRC. See the
BlockCheckMethod property (page 530) for more information.
14
The <term> character is the packet terminator which equals carriage return (ASCII 13) by
default. You will probably never need to change the terminator.
15
16
17
514 Chapter 14: File Transfer Protocols
1
1
Receiver
--->
<---
KFile
KData
KAck
KAck
KAck
KAck
--->
<---
KBreak
...
KEndoffile
KAck
6
7
--->
<---
--->
<---
--->
<---
KData
--->
<---
Explanation
The KXxx tags are the packet types that the two computers exchange as they decide what is
to be done. You dont need to understand them unless you find yourself trying to decipher a
Kermit transfer using the Async Professional tracing facility. To do so, youll likely need to
consult the Kermit specification file and/or the Async Professional source code.
Kermit options
Like Zmodem, Kermit offers a variety of options. An implementation of Kermit is not
required to support all options. Hence, one of the first things that happens in a Kermit
protocol is that the two sides exchange their desired options and use the lowest common
denominator of the two sets.
9
10
11
12
13
14
15
16
17
Kermit 515
1
1
1
2
3
4
5
6
Table 14.8 shows the Kermit options that Async Professional supports and the default values
each uses. The entries in the first column are TApdProtocol property names that can be used
to adjust each option.
Table 14.8: Kermit property options and default values
Property
Default
Explanation
KermitMaxLen
80 bytes
KermitTimeoutSecs
5 seconds
KermitPadCount
0 bytes
KermitPadCharacter
KermitTerminator
<CR>
KermitCtlPrefix
KermitHighbitPrefix
BlockCheckMethod
KermitRepeatPrefix
Repeat prefix is ~.
KermitMaxWindows
No sliding windows.
7
8
9
10
11
12
13
14
15
16
KermitMaxLen is the maximum number of bytes you want Kermit to include in one packet.
The normal maximum value is 94; the default value is 80 as suggested by the Kermit
Protocol Manual. If KermitMaxLen exceeds 94, the Kermit long packets feature is enabled.
The absolute maximum value is 1024.
KermitTimeoutSecs is the amount of time, in seconds, that a Kermit transmitter will wait for
an acknowledgement or a Kermit receiver will wait for the next byte to be received. If more
than KermitTimeoutSecs seconds elapse without receiving anything, Kermit assumes an
error occurred and resends.
KermitPadCount and KermitPadCharacter describe padding that can be added at the front
of all Kermit packets. The only reason for padding is if the remote machine needs a delay
between sending a packet and receiving a response. In this case, you can specify enough
padding characters to generate the required delay. Generally, though, padding is
unnecessary. The Kermit protocol as implemented by Async Professional automatically
honors a remotes request for padding.
KermitTerminator is the character that follows the check field in a packet. Although all
Kermit packets have a terminator, it is used only by systems that need an end-of-line
character before they can start processing input.
17
516 Chapter 14: File Transfer Protocols
1
1
KermitCtlPrefix is the control character prefix that Kermit uses when performing Ctl
quoting to transform control characters into printable ASCII characters. Generally you
wont need to change this prefix.
KermitHighbitPrefix specifies how Kermit transforms high-bit characters into characters
without the high-bit set. Generally you wont need to change this setting. See the property
description for more information.
BlockCheckMethod specifies the type of block checking Kermit should perform. 1
corresponds to the bcmChecksum value of the TBlockCheckMethod type, and it means that
Kermit should use a single-byte checksum. All Kermit implementations are guaranteed to
support this form of block checking. bcmChecksum2 means that Kermit should use a twobyte checksum, which offers only slightly more protection than the single-byte checksum.
bcmCrcK means that Kermit should use a three-byte CRC. This is the preferred block check
method because it offers the highest level of error detection. Unfortunately, not all Kermit
implementations support the non-default block check methods. If the remote computer
doesnt support the block check method you request, both sides drop back to the single-byte
checksum.
1
2
3
4
6
7
The two sides of a Kermit protocol automatically negotiate which options to use, so no
intervention is required by your program. If you wish to change the default options, use
these properties.
10
Async Professional does not provide Kermit server functions and does not support file
attribute packets.
11
Long packets
12
Async Professional includes support for long packets, which is an extension to standard
Kermit that permits data packets of up to 1024 bytes. Long packets can substantially
improve protocol throughput on clean connections that have small turnaround delays. Long
packet support is turned off by default and must be enabled by setting KermitMaxLen to a
value between 95 and 1024. Most other Kermit implementations also disable this option by
default.
13
Although the specification allows for packets up to 9024 bytes, Async Professional limits
long packets to 1024 bytes. Packets longer than 1024 bytes do not appreciably increase
throughput, but they dramatically increase retransmission time when a line error occurs.
14
15
16
17
Kermit 517
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
The specification also recommends the use of the higher-order checksums with long
packets, but does not require it. Async Professional defaults to 2 byte checksums when long
packet support is enabled, but drops back to 1 byte checksums if requested to do so by the
remote Kermit.
16
17
518 Chapter 14: File Transfer Protocols
1
1
ASCII
The term ASCII protocol is a bit of a misnomer, because in an ASCII transfer neither side of
the link is following well-documented rules. An ASCII protocol is really just a convenient
way of transmitting a text file.
A typical use for the ASCII protocol is when you need to transfer a text file to a
minicomputer that doesnt have any protocols available. One way of accomplishing this is to
run an Async Professional program that supports a terminal window and the ASCII
protocol, such as the TCom demo program. You connect to the minicomputer, navigate to
the minicomputers editor, and open up a new text file. Then you start an ASCII protocol
transmit of the file you need to transfer. The minicomputers editor sees this as keystroke
input to the editor. You finish the transfer by saving the editors file.
The ASCII protocol provides options for tailoring such transfers to the remote machines
speed, which might necessitate delays between transmitted characters and lines. For
example, when transmitting a file into a remote computers editor, you might need to use
delays to avoid overflowing the editors keystroke buffer.
It is difficult for the receiver to know when an ASCII transfer is over because there is no
agreed-upon method for indicating termination. The ASCII protocol terminates on any of
three conditions: when it receives a ^Z character, when it times out waiting for more data, or
when the user aborts the protocol and the application calls CancelProtocol. When any of
these conditions is detected, the file is saved and the protocol ends.
3
4
6
7
8
9
10
End-of-line translations
Computer systems sometimes use different character sequences to terminate each line of a
text file. Most PC software stores both a carriage return <CR> and a line feed <LF> at the
end of each line. Other systems store only <LF> or only <CR> at the end of each line.
11
12
13
14
15
16
17
ASCII 519
1
1
1
2
3
4
The ASCII protocol provides a number of options for translating from one end-of-line
sequence to another, both when transmitting and when receiving. When performing these
translations, the <CR> and <LF> characters are treated separately, based on the values
assigned to the AsciiCRTranslation and AsciiLFTranslation properties. Table 14.9 shows the
enumerated values used to control the behavior.
Table 14.9: ACII protocol enumerated property values
Value
Explanation
aetNone
aetStrip
aetAddCRBefore
aetAddLFAfter
7
8
9
10
11
12
13
14
15
16
17
520 Chapter 14: File Transfer Protocols
1
1
FTP
Async Professional provides two File Transfer Protocol (FTP) components that make it easy
to implement FTP client support in your application.
The TApdFtpClient component takes care of the FTP protocol details and presents a
friendly interface for transferring files to and from an FTP server. In addition, the
component also provides a set of standard functions for manipulating files and directories at
the FTP server.
3
4
The TApdFtpLog component automates the process of logging an FTP client-server dialog
for auditing FTP activities.
Overview of FTP
File Transfer Protocol (FTP) is used to transfer files from one location on the Internet to
another. An FTP client establishes a connection (called the control connection) to an FTP
server at a well-known port number (usually 21). The control connection is used for a
command-response dialog between the client and server. The client issues an FTP
command which consists of an ASCII string containing a mnemonic command followed by
any parameters required for the command. The server then responds with a reply consisting
of an ASCII string containing a three digit reply code followed by some text. During a file
transfer, a separate data connection is established to transfer the file data. When the transfer
is complete, the data connection is closed.
When an FTP client establishes a control connection with an FTP server, the server will
respond with a reply code that indicates that the user login procedure can commence. The
login procedure consists of sending commands containing the users ID name, password,
and (possibly) account information as parameters. An FTP server requires authenticated
login information before giving a user access to files and directories, however many servers
allow a user to login anonymously for restricted access. Users log in anonymously using
ANONYMOUS for their user ID name and their e-mail address for their password.
7
8
9
10
11
12
13
14
15
16
17
FTP 521
1
1
1
2
3
4
5
6
7
8
9
10
11
12
Reply Code
Explanation
421
425
426
451
452
500
501
502
503
504
505
506
Usage error.
522
530
550
551
553
13
14
15
16
17
522 Chapter 14: File Transfer Protocols
1
1
TApdProtocol Component
TApdProtocol implements all of the Async Professional file transfer capabilities in one
comprehensive component. General issues associated with using this component are
discussed in the first part of this chapter.
Note that certain properties that are described in the following reference section are specific
to a particular protocol type. If a particular property is not supported by the current value of
the ProtocolType property (e.g., the AsciiCharDelay property is not relevant to the
Zmodem protocol), assigning a value to that property stores the new value in a field of the
component, but has no effect until the ProtocolType is changed to the corresponding
protocol. Protocol-specific properties have names that begin with the name of the protocol
itself (e.g., ZmodemOptionOverride, ZmodemSkipNoFile, ZmodemFileOption,
ZmodemRecover, and Zmodem8K).
3
4
Example
This example shows how to construct and use a protocol component. It includes a terminal
window so you can navigate around an on-line service while you test the program, and a
TApdProtocolStatus component so you can see the progress of the transfer.
Create a new project, add the following components, and set the property values as
indicated in Table 14.11.
9
10
Property
Value
TApdComPort
ComNumber
11
TApdEmulator
12
TApdTerminal
TApdProtocol
FileMask
EXPROT*.*
TButton
Name
Upload
TButton
Name
Download
13
TApdProtocolStatus
14
15
16
17
TApdProtocol Component 523
1
1
1
2
3
Double-click on the Upload buttons OnClick event handler within the Object Inspector and
modify the generated method to match this:
procedure TForm1.UploadClick(Sender : TObject);
begin
ApdProtocol1.StartTransmit;
end;
This method starts a Zmodem background protocol transmit session for all of the files
matching the mask EXPROT*.*. (Zmodem is the default protocol type for TApdProtocol
instances.)
Double-click on the Download buttons OnClick event handler within the Object Inspector
and modify the generated method to match this:
6
7
8
9
10
11
12
This method starts a Zmodem background session to receive whatever files the transmitter
sends.
The form includes a TApdProtocolStatus component, which is automatically displayed by
the protocol and periodically updated to show the progress of the file transfer.
This example is in the EXPROT project in the \ASYNCPRO\EXAMPLES directory.
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomProtocol (AdProtcl)
TApdProtocol (AdProtcl)
13
14
15
16
17
524 Chapter 14: File Transfer Protocols
1
1
Properties
AbortNoCarrier
FileName
ProtocolError
ActualBPS
FinishWait
ProtocolLog
AsciiCharDelay
HandshakeRetry
ProtocolStatus
AsciiCRTranslation
HandshakeWait
ProtocolType
AsciiEOFTimeout
HonorDirectory
RTSLowForWrite
AsciiEOLChar
IncludeDirectory
StatusDisplay
AsciiLFTranslation
InitialPosition
StatusInterval
AsciiLineDelay
InProgress
TotalErrors
AsciiSuppressCtrlZ
KermitCtlPrefix
TransmitTimeout
Batch
KermitHighbitPrefix
TurnDelay
BlockCheckMethod
KermitLongBlocks
BlockErrors
KermitMaxLen
BlockLength
KermitMaxWindows
WriteFailAction
BlockNumber
KermitPadCharacter
XYmodemBlockWait
BytesRemaining
KermitPadCount
Zmodem8K
BytesTransferred
KermitRepeatPrefix
ZmodemFileOption
ComPort
KermitSWCTurnDelay
ZmodemFinishRetry
DestinationDirectory
KermitTerminator
ZmodemOptionOverride
ElapsedTicks
KermitTimeoutSecs
ZmodemRecover
FileDate
KermitWindowsTotal
ZmodemSkipNoFile
FileLength
KermitWindowsUsed
FileMask
Overhead
UpcaseFileNames
2
3
4
! Version
7
8
9
10
11
Methods
12
CancelProtocol
StartReceive
EstimateTransferSecs
StartTransmit
StatusMsg
13
Events
14
OnProtocolAccept
OnProtocolFinish
OnProtocolNextFile
OnProtocolError
OnProtocolLog
OnProtocolStatus
15
16
17
1
1
Reference Section
AbortNoCarrier
property
2
property AbortNoCarrier : Boolean
Default: False
! Determines whether the protocol is canceled automatically when the DCD modem signal
4
5
6
7
8
9
10
drops.
Using the AbortNoCarrier property is better than checking DCD and calling
CancelProtocol in your own code. When you do this, the protocol engine sends a cancel
sequence to the remote computer. If hardware flow control is enabled and the modem has
lowered the DSR or CTS signals as well as DCD, the protocol waits several seconds before
deciding it cant send the cancel command, leading to an unnecessary delay for the
application. The AbortNoCarrier property prevents the protocol engine from sending the
cancel sequence, so the protocol stops immediately.
Note that when transferring through Winsock the DCD signal is not present (Winsock does
not contain the concept of a DCD line). The TApdWinsockPort artificially raises and lowers
the DCD property according to the connection state. The DCD property is therefore valid
for testing connection states, and the AbortNoCarrier functionality will work as expected.
See also: CancelProtocol
ActualBPS
run-time property
11
12
13
14
15
16
17
526 Chapter 14: File Transfer Protocols
1
1
Without setting ActualBPS, the protocol would base transfer rate calculations on a bps rate
of 19200, the port baud rate. You should set ActualBPS to 9600, the actual connection speed.
Even this is somewhat inaccurate because it doesnt take into account the improvements due
to data compression, which are difficult to predict.
1
2
property
3
4
Default: 0
! Determines the number of milliseconds to delay between characters during an ASCII file
transfer.
The default delay of zero should be retained whenever possible to maximize performance.
However, if ASCII data is being fed directly into an application such as a text editor, it might
be necessary to insert delays to allow the application time to process the data.
The following example sets the inter-character delay to 2 milliseconds and the inter-line
delay to 50 milliseconds:
ApdProtocol1.AsciiCharDelay := 2;
ApdProtocol1.AsciiLineDelay := 50;
6
7
8
9
property
10
11
12
Default: aetNone
13
14
Value
Description
aetNone
aetStrip
aetAddLFAfter
15
16
17
1
1
1
2
3
4
5
6
7
8
9
The following example causes all <LF> characters to be stripped while <CR> characters are
transmitted:
ApdProtocol1.ProtocolType := ptAscii;
ApdProtocol1.AsciiCRTranslation := aetNone;
ApdProtocol1.AsciiLFTranslation := aetStrip;
ApdProtocol1.StartTransmit;
property
Default: 364
property
10
11
12
13
Note that this character is not involved in on-the-fly translation of end-of-line characters
read from or written to an ASCII file; that translation is controlled by the
AsciiCRTranslation and AsciiLFTranslation properties.
14
The default end-of-line character is <CR> or ^M. If you are transmitting Unix files, which
use <LF> or ^J for the end-of-line marker, you should set AsciiEOLChar to ^J.
See also: AsciiLineDelay
15
16
17
528 Chapter 14: File Transfer Protocols
1
1
AsciiLFTranslation
property
TAsciiEOLTranslation = (
aetNone, aetStrip, aetAddCRBefore, aetAddLFAfter);
Default: aetNone
Description
aetNone
aetStrip
aetAddCRBefore
property
8
9
Default: 0
! Determines the number of milliseconds to delay between lines during an ASCII file transfer.
10
The default delay of zero should be retained whenever possible to maximize performance.
However, if ASCII data is being fed directly into an application such as a text editor, it might
be necessary to insert delays to allow the application time to process the data.
11
12
AsciiSuppressCtrlZ
property
13
14
Default: False
! Determines whether an ASCII protocol stops transmitting when it encounters the first ^Z in
the file.
If this property is False, the ASCII protocol transmits all characters in the file, including ^Z
characters. If it is True, it stops before transmitting the first ^Z that it encounters. Generally
you should leave this property set to False because the receiver might use ^Z as an end-ofprotocol indicator, as Async Professional does.
15
16
17
1
1
Batch
Batch transfers are those that allow sending more than one file in the same protocol session.
Batch transfers in Async Professional include: Kermit, Ymodem, and Zmodem.
This property is most useful within an OnProtocolStatus event handler. See Protocol
status on page 489 for more information.
BlockCheckMethod
property
6
7
8
TBlockCheckMethod = (
bcmNone, bcmChecksum, bcmChecksum2, bcmCrc16, bcmCrc32, bcmCrcK);
9
10
11
12
13
14
Value
Description
bcmNone
No error checking.
bcmChecksum
bcmChecksum2
bcmCrc16
16-bit CRC.
bcmCrc32
bcmCrcK
The Xmodem1K, Xmodem1KG, Ymodem, YmodemG, and ASCII protocols provide either
no error checking or a single error checking mode, so they ignore assignments to
BlockCheckMethod.
15
16
17
530 Chapter 14: File Transfer Protocols
1
1
The Zmodem protocol accepts only the bcmCrc16 and bcmCrc32 types. The Kermit
protocol accepts only the bcmChecksum, bcmCheckSum2, and bcmCrcK types.
No error is generated if an unaccepted type is assigned, but the assignment is ignored. You
should be sure to set the desired ProtocolType before setting a non-default
BlockCheckMethod.
3
4
! The number of errors that have occurred while transferring the current block.
This property is most useful within an OnProtocolStatus event handler. See Protocol
status on page 489 for more information.
BlockLength
10
For some protocols this value remains fixed (e.g., Xmodem always uses 128 byte blocks); for
others it can vary during the transfer process (e.g., Zmodem can vary between 8192 bytes
and 256 bytes depending on options and line conditions).
This property is most useful within an OnProtocolStatus event handler. See Protocol
status on page 489 for more information.
12
BlockNumber
13
11
14
15
This property is most useful within an OnProtocolStatus event handler. See Protocol
status on page 489 for more information.
16
17
1
1
BytesRemaining
This is computed as the FileLength minus the value of BytesTransferred. When the file size
isnt known, BytesRemaining returns zero.
This property is most useful within an OnProtocolStatus event handler. See Protocol
status on page 489 for more information.
See also: BytesTransferred, FileLength
5
6
BytesTransferred
When transmitting, this number is sometimes only an estimate. The uncertainty comes
from the fact that the protocol window doesnt know when a particular byte has actually
been transferred. BytesTransferred is the number of bytes the protocol window has
transferred to the output buffer of the communications driver, minus the number of bytes
that the driver reports are currently in the buffer.
Unfortunately, this calculation is still imperfect because its impossible to know how much of
the output buffer holds actual file data and how much holds overhead characters needed by
the protocol. Each protocol has a few simple rules it uses to estimate this proportion, which
in practice yield good estimates.
11
This property is most useful within an OnProtocolStatus event handler. See Protocol
status on page 489 for more information.
12
13
14
15
16
17
532 Chapter 14: File Transfer Protocols
1
1
CancelProtocol
method
procedure CancelProtocol;
CancelProtocol cancels the protocol regardless of its current state. If appropriate, a cancel
string is sent to the remote computer. The protocol generates an OnProtocolFinish event
with the error code ecCancelRequested, then cleans up and terminates.
The following example shows how to cancel a protocol from within a protocol status dialog
box:
procedure TStandardDisplay.CancelClick(Sender: TObject);
begin
ApdProtocol1.CancelProtocol;
end;
3
4
property
7
8
The comport should almost always be set to use 8 data bits, 1 stop bit, and no parity. It
should have input and output buffers that meet the guidelines described in Buffer sizes on
page 485. Most transfer protocols require that some form of flow control be enabled in the
comport component.
10
DestinationDirectory
12
property
11
13
14
15
16
17
1
1
ElapsedTicks
2
3
This property is most useful within an OnProtocolStatus event handler. See Protocol
status on page 489 for more information.
method
6
function EstimateTransferSecs(const Size : LongInt) : LongInt;
7
8
9
10
11
12
13
14
= ActualBPS div 10
Efficiency
15
BlockLength
-------------------------------------------------
16
17
534 Chapter 14: File Transfer Protocols
1
1
1
2
3
4
7
8
9
10
11
12
13
14
15
16
17
TApdProtocol Component 535
1
1
FileLength
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
property
17
property
If FileName does not include drive or path information, the incoming file is stored in the
current directory or the directory specified by DestinationDirectory. If FileName includes
drive and/or path information and HonorDirectory is True, the incoming file is stored in
that directory regardless of whether a value was assigned to DestinationDirectory.
The following example stores a file received via Xmodem to
C:\DOWNLOAD\RECEIVE.TMP:
1
2
3
ApdProtocol1.ProtocolType := ptXmodem;
ApdProtocol1.FileName := 'C:\DOWNLOAD\RECEIVE.TMP';
ApdProtocol1.StartReceive;
property
Default: 364
! Determines how long the receiver waits for an end-of-transmission signal before timing out.
This property applies only to Xmodem, Ymodem, and Zmodem protocols.
At the end of an Xmodem or Ymodem file transfer the transmitter sends an <EOT> to the
receiver to signal the end of the file and then waits FinishWait ticks (20 seconds by default)
for a response. Normally this provides ample time. However, when Xmodem1KG and
YmodemG are used over links with long propagation times or slow receivers, the default
value might not be enough. Use FinishWait to extend the amount of time that the
transmitter waits before timing out and reporting an error. Note that FinishWait is specified
in ticks.
Similarly, in a Zmodem transfer the transmitter sends a ZFin packet to the receiver to signal
the end of the file and then waits FinishWait ticks to receive an acknowledgement before
timing out.
See also: ZmodemFinishRetry
7
8
9
10
11
12
13
14
15
16
17
1
1
HandshakeRetry
property
Default: 10
This property controls how many times each protocol attempts to detect the initial
handshake from its remote partner. HandshakeRetry applies to all protocols but ASCII,
which does not perform handshaking.
See also: HandshakeWait
5
6
HandshakeWait
property
Default: 182
This property is the number of ticks a protocol waits when a handshake attempt fails before
it tries again. HandshakeWait applies to all protocols but ASCII, which does not perform
handshaking.
10
HonorDirectory
property
11
12
Default: False
! Determines whether a protocol honors the directory name of a file being received.
13
If HonorDirectory is set to True, a received file is stored in the directory specified by the
transmitter, unless that directory does not already exist, in which case it is stored in the
current directory or the DestinationDirectory. If HonorDirectory is set to False, the
transmitters directory is ignored.
14
15
16
17
538 Chapter 14: File Transfer Protocols
1
1
IncludeDirectory
property
Default: False
3
4
6
property InitialPosition : LongInt
This property applies only to Zmodemprotocols, which support resumed file transfers. For a
transfer from scratch, InitialPosition returns zero. For a resumed transfer, InitialPosition
returns the offset where the transfer was resumed. This offset should be subtracted from
BytesTransferred to obtain the actual number of bytes transferred during the resumed
session.
8
9
This property is most useful within an OnProtocolStatus event handler. See Protocol
status on page 489 for more information.
10
The following example shows how to compute the character per second transfer rate in a
protocol status routine. The constant values are used to convert ticks to seconds. Note that
the same expression is valid whether or not the transfer has been resumed.
11
CPS :=
(91*(ApdProtocol.BytesTransferred-ApdProtocol.InitialPosition))
div (5*ApdProtocol.ElapsedTicks);
12
13
14
15
16
17
1
1
InProgress
A property such as this is important because Async Professional protocols run in the
background. A call to StartTransmit or StartReceive returns immediately to your code.
Use InProgress to determine whether a file transfer is already taking place or not before
trying to start another transfer.
See also: OnProtocolFinish
6
7
KermitCtlPrefix
property
Default: #
8
9
10
11
12
Default: Y
! Determines the technique Kermit uses to quote characters that have their eighth bit set.
13
The value specified by this property is not always transmitted literally as a quote character. If
it equals Y, the default, it means that the protocol wont use high bit quoting unless the
remote requires it, in which case it uses the prefix character requested by the remote.
14
If KermitHighbitPrefix equals & or is in the ASCII range 33-62 or 96-126, it indicates that
the protocol requires high bit quoting and that its value is the character used for the prefix.
15
If C equals N or any other value not listed here, the protocol wont use high bit quoting at
all, even if the remote requests it.
16
17
540 Chapter 14: File Transfer Protocols
1
1
property
KermitLongBlocks
property
3
4
Default: 80
6
7
property
10
Default: 0
11
12
13
14
15
16
17
TApdProtocol Component 541
1
1
KermitPadCharacter
property
! Determines the character that Kermit uses to pad the beginning of each packet.
3
4
5
6
7
8
property
Default: 0
! Determines the number of pad characters that Kermit transmits at the beginning of each
packet.
See Kermit options on page 515 for more information.
See also: KermitPadCharacter
KermitRepeatPrefix
property
9
property KermitRepeatPrefix : Char
10
Default: ~
! Determines the prefix that Kermit uses when compressing strings of repeated characters.
11
12
When Kermit sees four or more equal and adjacent characters, it compresses the sequence
into a quote character (KermitRepeatPrefix), a length byte, and the repeated character. The
default quote character rarely needs to be changed.
See Character quoting on page 513 for more information.
13
14
15
16
17
542 Chapter 14: File Transfer Protocols
1
1
KermitSWCTurnDelay
property
Default: 0
EstimateTransferSecs uses the value of the TurnDelay property for Kermit transfers when
sliding windows control is not enabled, and the KermitSWCTurnDelay property when it is
enabled.
KermitTerminator
property
10
11
12
13
14
15
16
17
1
1
KermitTimeoutSecs
property
Default: 5
! Determines how long Kermit waits for the next expected byte.
3
4
5
6
KermitWindowsTotal
! Returns the total number of Kermit sliding windows negotiated for the current transfer.
7
8
9
10
11
! Returns the number of Kermit sliding windows that currently contain data.
If sliding windows control is disabled, KermitWindowsUsed returns 0.
See also: KermitMaxWindows, KermitWindowsTotal
12
13
14
15
16
17
544 Chapter 14: File Transfer Protocols
1
1
OnProtocolAccept
event
TPassString = string[255];
! Defines an event handler that is called as soon as the name of an incoming file is known.
This event handler provides an opportunity for the receiver to reject or rename the
incoming file. If an OnProtocolAccept handler is not installed, all files are accepted (subject
to the setting of the WriteFailAction property).
CP is the protocol component that is receiving the file. The event handler should set Accept
to True to accept the file, False to reject it. FName is the name of the file to be received. The
event handler can change the name if, for example, it would overwrite an existing file.
See AcceptFile processing on page 495 for more information.
6
7
event
8
9
TProtocolErrorEvent = procedure(
CP : TObject; ErrorCode : SmallInt) of object;
! Defines an event handler that is called when an unrecoverable protocol error occurs.
10
This event is generated only for unrecoverable errors. Most protocol errors caused by line
noise are handled automatically by the protocol and are not reported to this event handler.
11
CP is the protocol component that generated the error. ErrorCode is a number indicating
the type of error.
12
Note that the OnProtocolFinish event is generated soon after the OnProtocolError event and
passes the same error code. OnProtocolFinish is generated for both successful and failed
transfers, so you may want to use it instead of an OnProtocolError handler.
13
14
15
16
17
1
1
OnProtocolFinish
event
TProtocolFinishEvent = procedure(
CP : TObject; ErrorCode : SmallInt) of object;
4
5
6
7
8
9
This event is generated whether the protocol ends successfully or not. If it ends successfully,
ErrorCode is zero. Otherwise, ErrorCode is a number indicating the type of error. CP is the
protocol component that generated the error.
An application could use this handler to display a completion dialog box (needed only if a
protocol status event handler is not also in use) or to enable the scheduling of another file
transfer.
The following example displays a message whenever a protocol finishes, and enables an
associated terminal window to accept data again:
procedure TForm1.ApdProtocol1ProtocolFinish(
CP : TObject; ErrorCode : SmallInt);
begin
ShowMessage('Protocol finished: '+ErrorMsg(ErrorCode));
ApdTerminal1.Active := True;
end;
10
11
OnProtocolLog
event
12
13
14
! Defines an event handler that is called at well-defined points during a protocol transfer.
The primary purpose of this event is to give applications a chance to log statistical
information about file transfers such as the transfer time and whether they succeeded or
failed. Applications can also use this event for start-up and cleanup activities such as
deleting partial files after unsuccessful downloads.
15
16
17
546 Chapter 14: File Transfer Protocols
1
1
CP is the protocol component that needs to be logged. Log is a code that indicates the
current state of the file transfer. The possible states are:
Log
State
lfReceiveStart
lfReceiveOK
lfReceiveFail
lfReceiveSkip
lfTransmitStart
lfTransmitOK
lfTransmitFail
lfTransmitSkip
1
2
3
4
No other information is passed along with the event. Use protocol status properties such as
FileName and ElapsedTicks to get additional information about the state of the transfer.
event
10
11
TPassString = string[255];
! Defines an event handler that is called to determine the next file to transmit in a batch
12
transfer.
If no handler is installed for this event, Async Professional transmits the files that match the
DOS filemask assigned to the FileMask property. If you need to transmit a batch of files that
cannot be described by a single filemask, you need to install an event handler for
OnProtocolNextFile.
CP is the protocol component that is transmitting. The event handler should return the next
file to transmit in FName, or an empty string to terminate the batch.
13
14
15
16
17
TApdProtocol Component 547
1
1
OnProtocolStatus
event
2
3
4
5
6
7
8
9
TProtocolStatusEvent = procedure(
CP : TObject; Options : Word) of object;
10
Overhead
11
12
13
14
15
! Determines the number of overhead bytes per data block used by EstimateTransferSecs.
When a protocol transfers a data block, not all of the bytes are actually data from the file
being transferred. Some of them are part of the packet header and others may be used to
quote or escape data characters that cannot be transmitted as-is.
When you select a protocol by assigning to the ProtocolType property, the TApdProtocol
component assigns a default value to Overhead that matches the characteristics of the
protocol. For some protocols the exact value of Overhead depends on the actual data being
transmitted, but the default is a reasonable estimate that gives reasonable transfer time
estimates. If the estimates are consistently in error, you can assign a new value to Overhead.
See also: EstimateTransferSecs, TurnDelay
16
17
548 Chapter 14: File Transfer Protocols
1
1
property
ProtocolError
This property returns zero except for the first call after an error is encountered. See Error
Handling and Exception Classes on page 900 for a complete list of error codes.
property
6
7
8
9
10
11
12
13
14
15
16
17
TApdProtocol Component 549
1
1
ProtocolType
property
Default: ptZmodem
Async Professional encapsulates all of the file transfer protocols that it supports into a single
component. To select a particular type of protocol, you must assign the desired type to the
ProtocolType property. You should generally assign to ProtocolType shortly after creating
the TApdProtocol component and before assigning other properties, since various defaults
are assigned whenever you change ProtocolType, and some properties are valid only when
ProtocolType has a particular value.
Assigning a new value to ProtocolType first deallocates any protocol-specific memory used
by the prior protocol, then allocates and initializes any structures required by the current
protocol.
You should generally not assign ptNoProtocol to ProtocolType, but it can be used to
deallocate previous protocol memory while temporarily not allocating new protocol
memory.
See also: BlockCheckMethod
10
RTSLowForWrite
11
property
Default: False
12
13
14
15
16
! Determines whether protocols force RTS low while writing received data to disk.
When RTSLowForWrite is set to True, hardware flow control is used to prevent the
transmitter from sending additional data while the receiver writes data to disk. As soon as
the disk write is finished, RTS is raised again. This feature might be required if other
Windows applications are being run at the same time as a protocol transfer or if the disk
driver leaves interrupts disabled for an excessive time.
In order for this option to be effective, disk write caching must be disabled.
If the protocol is transferring files using a modem, it might also be necessary to configure
the modem to react correctly to the RTS signal.
17
550 Chapter 14: File Transfer Protocols
1
1
StartReceive
method
procedure StartReceive;
3. Set ProtocolType.
4. Set other properties to customize the protocol.
5. Write suitable handlers for protocol events.
6. Call StartReceive.
StartReceive returns immediately and receives files in the background, occasionally
generating events to keep the application apprised of progress. When the protocol is
finished, either successfully or with a fatal error, it generates an OnProtocolFinish event and
its InProgress property starts returning False.
7
8
method
procedure StartTransmit;
9
10
11
12
13
14
15
7. Call StartTransmit.
16
17
TApdProtocol Component 551
1
1
1
2
3
4
StatusDisplay
property
If StatusDisplay is nil, as it is by default, the protocol does not provide an automatic status
window. You can install an OnProtocolStatus event handler to display status in this case.
If you create an instance of a class derived from TApdAbstractStatus, such as the provided
TApdProtocolStatus component (see page 582), and assign it to ProtocolStatus, the status
window will be displayed and updated automatically.
StatusInterval
8
9
property
Default: 18
The OnProtocolStatus event is generated for each block transmitted or received, after the
completion of each major operation (e.g., renaming a file, detecting an error, ending the
transfer), and at intervals of StatusInterval ticks.
This property also determines how frequently the StatusDisplay window is updated.
12
13
14
15
16
17
552 Chapter 14: File Transfer Protocols
1
1
StatusMsg
method
This routine is intended primarily for use in protocol status routines. It returns a status
string from the string table resource linked into your EXE. The string ID numbers
correspond to the values of the psXxx protocol status constants (see page 491). If the string
table doesnt contain a string resource with the requested ID, an empty string is returned.
3
4
6
property TotalErrors : Word
! The number of errors encountered since the current file transfer was started.
This error count is reset whenever a new file is started. This property is most useful within
an OnProtocolStatus event handler. See Protocol status on page 489 for more
information.
TransmitTimeout
property
10
property TransmitTimeout : Word
Default: 1092
11
Determines the maximum time a sender will wait for the receiver to release flow control.
If the receiver blocks flow control for longer than TransmitTimeout ticks (60 seconds by
default), the protocol is aborted.
12
13
14
15
16
17
1
1
TurnDelay
property
Default: 0
EstimateTransferSecs.
When a protocol transfers a data block, the transmitter must often wait for an
acknowledgement from the receiver before it transmits the next block. This delay slows
down the overall throughput of the protocol and must be accounted for by
EstimateTransferSecs.
When you select a protocol by assigning to the ProtocolType property, the TApdProtocol
component assigns a default value to TurnDelay that is a good estimate for the given
protocol. However, the actual TurnDelay often depends on the characteristics of the
communications link between the sender and receiver (e.g., a satellite link would impose a
longer delay than a null modem cable). If the values returned by EstimateTransferSecs are
consistently in error, you can assign a new value to TurnDelay.
See also: EstimateTransferSecs, Overhead
UpcaseFileNames
property
9
property UpcaseFileNames : Boolean
10
Default: True
16
17
554 Chapter 14: File Transfer Protocols
1
1
WriteFailAction
property
TWriteFailAction = (
wfWriteNone, wfWriteFail, wfWriteRename, wfWriteAnyway);
Default: wfWriteRename
Determines the receivers behavior when the destination file already exists.
Description
wfWriteFail
wfWriteRename
wfWriteAnyway
When wfWriteRename is selected and the destination file already exists, the first character in
the incoming file name is replaced with $ (e.g., SAMPLE.DOC becomes
$AMPLE.DOC). If that renamed file already exists, it is overwritten without warning.
The logic that handles these overwrite options is executed after the OnProtocolAccept event
has been generated. If you write an event handler that deals with possible overwrites, be sure
to set WriteFailAction to wfWriteAnyway before starting a transfer.
See also: OnProtocolAccept, ZmodemFileOption
XYmodemBlockWait
7
8
9
10
property
11
Default: 91
! Determines the number of ticks Xmodem and Ymodem wait between blocks for a response
from the remote.
If the wait exceeds XYmodemBlockWait ticks, a sending protocol retransmits the block and
a receiving protocol aborts the transfer. The default wait is about 5 seconds.
See also: TransmitTimeout
12
13
14
15
16
17
1
1
Zmodem8K
property
Default: False
ZmodemFileOption
property
5
6
Default: zfoWriteNewer
8
9
10
11
12
13
14
15
Value
Description
zfoWriteNewerLonger
zfoWriteCrc
zfoWriteAppend
zfoWriteClobber
Transfer regardless.
zfoWriteNewer
zfoWriteDifferent
zfoWriteProtect
Regardless of the value of this property, new incoming files are accepted unless the
ZmodemSkipNoFile property is set to False.
The logic that handles these file management options is executed after the
OnProtocolAccept event has been generated. If you write an event handler that deals with
possible overwrites, be sure to set ZmodemFileOption to zfoWriteClobber before starting to
receive.
See also: ZmodemOptionOverride, ZmodemSkipNoFile
16
17
556 Chapter 14: File Transfer Protocols
1
1
ZmodemFinishRetry
property
Default: 0
! Specifies the number of times to retry the final handshake of a Zmodem protocol session.
A Zmodem transmitter signals that it has no more files to transmit by sending a ZFin frame.
The receiver acknowledges this by sending its own ZFin frame. The transmitter then sends
OO as the final frame of the transfer.
The Zmodem specification indicates that this portion of the protocol isnt critical (since all
files have already been completely received) and that a timeout while waiting for the
response should be ignored. However, this strategy doesnt work well with DSZ, a Zmodem
implementation by Omen Technology, Inc.
DSZ retries after a ZFin timeout, which can sometimes cause unneeded packet transfers
when the handshake timeout is 10 seconds or less. To handle this situation, Async
Professional mimics DSZ when ZmodemFinishRetry is set a non-zero value. It waits
FinishWait ticks for a response.
ZmodemFinishRetry is the number of times to resend the ZFin in response to a timeout.
When ZmodemFinishRetry is zero the ZFin is sent only once. If no response is received the
protocol finishes without an error.
3
4
6
7
8
9
property
10
11
Default: False
12
13
14
15
16
17
TApdProtocol Component 557
1
1
ZmodemRecover
property
Default: False
Zmodem is capable of resuming interrupted file transfers if the receiver kept the partial file
when a previous transfer was interrupted. The transmitter requests this action by setting
ZmodemRecover to True. The request is transmitted to the receiver along with the file name
to be recovered. If the receiver has this file, it sends back the current file size. The transmitter
then adjusts its file offset and starts sending data from that point. If the receiver doesnt
already have this file, a normal file transfer takes place.
See Transfer resume on page 510 for more information.
See also: InitialPosition
ZmodemSkipNoFile
property ZmodemSkipNoFile : Boolean
Default: False
! Determines whether a Zmodem receiver should skip all files that dont already exist.
See also: ZmodemFileOption
10
11
12
13
14
15
16
17
558 Chapter 14: File Transfer Protocols
1
1
property
TApdFtpClient Component
The TApdFtpClient component is a specialized TApdWinsockPort that implements clientside file transfer protocol (FTP) capabilities as defined by RFC 959. TApdFtpClient presents
an intuitive interface that makes it easy to navigate and manipulate directories and files on
an FTP server.
Connecting and logging on to an FTP server is performed by the Login method. Logging off
and disconnecting is performed by Logout. Directory manipulation is performed by the
ChangeDir, Delete, ListDir, MakeDir, and Rename methods. File transfer and manipulation
is performed by the Delete, Rename, Retrieve, and Store methods. Server status and help
information are performed by the Help, and Status methods, and an arbitrary FTP
command string can be sent to the connected FTP server via SendFtpCommand.
Only one FTP operation is allowed at any given time, however these methods operate in an
asynchronous (i.e., non-blocking) fashion. This means that when a method is called to
initiate an FTP operation, it returns immediately and the operation is performed in the
background. When the operation is completed, the OnFtpStatus event is fired to notify the
application. During file transfer operations, the OnFtpStatus event is fired periodically to
provide status updates.
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
" TApdComPort (AdPort) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
TApdCustomFtpClient (AdFtp)
TApdFtpClient (AdFtp)
Properties
6
7
Account
" InBuffFree
" StopBits
" BaseAddress
" InBuffUsed
" SWFlowOptions
" BufferFull
" ComHandle
13
14
15
16
" LineBreak
" TraceName
" LineError
" TraceSize
Connected
" LogHex
" Tracing
ConnectTimeout
" LogName
" CTS
" LogSize
" DataBits
" ModemStatus
" DCD
# Open
" DeltaDCD
" UseEventWord
UserLoggedIn
UserName
PassiveMode
! Version
Password
# WsAddress
" OutBuffFree
# WsLocalAddresses
" DeltaRI
" OutBuffUsed
# WsLocalAddressIndex
# DeviceLayer
" Output
# WsMode
" DSR
" OutSize
# WsPort
" DTR
" Parity
# WsSocksServerInfo
FileLength
FileType
" FlowState
FtpLog
TransferTimeout
" DeltaDSR
17
" TapiMode
" TraceAllHex
" DeltaCTS
12
InProgress
" InSize
BytesTransferred
11
ServerAddress
" AutoOpen
" Baud
10
" HWFlowOptions
RestartAt
# WsTelnet
" RI
" XOffChar
" RS485Mode
" XOnChar
" RTS
Methods
1
" ForcePortOpen
" PutChar
" ActiveDeviceLayer
" GetBlock
" PutString
" AddDataTrigger
" GetChar
" RemoveAllTriggers
" AddStatusTrigger
Help
Abort
" AddTimerTrigger
" RemoveTrigger
" InitPort
Rename
" AddTraceEntry
ListDir
Retrieve
ChangeDir
Login
" CharReady
" CheckForString
Logout
MakeDir
" SendBreak
2
3
4
SendFtpCommand
" SetBreak
CurrentDir
" PeekBlock
" SetStatusTrigger
Delete
" PeekChar
" SetTimerTrigger
" FlushInBuffer
" ProcessCommunications
Status
" FlushOutBuffer
" PutBlock
Store
Events
6
7
8
OnFtpError
" OnTriggerAvail
" OnTriggerStatus
OnFtpLog
" OnTriggerData
" OnTriggerTimer
OnFtpReply
" OnTriggerLineError
# OnWsAccept
OnFtpStatus
" OnTriggerModemStatus
# OnWsConnect
" OnPortClose
" OnTriggerOutbuffFree
# OnWsDisconnect
" OnPortOpen
" OnTriggerOutbuffUsed
OnWsError
" OnTrigger
" OnTriggerOutSent
9
10
11
12
13
14
15
16
17
1
1
Reference
Abort
2
3
method
procedure Abort;
4
5
property
Account information is required by some FTP servers for login or storing files. If the server
requests account information to complete an operation, the Account string is automatically
sent to the server.
9
property BytesTransferred : Longint
10
11
12
13
14
15
16
17
562 Chapter 14: File Transfer Protocols
1
1
ChangeDir
method
3
4
6
Connected
8
9
property
10
11
Default: 0
12
connection.
When establishing the initial control connection to the FTP server, the ConnectTimeout
property determines the timeout (in ticks) associated with the connection attempt. If
ConnectTimeout is 0 (the default), the TApdFTPClient will not timeout. If ConnectTimeout
> 0, the connection attempt will be terminated if a connection is not made within
ConnectTimeout ticks. If a timeout occurs, the OnFTPError event is generated with
ErrorCode = ecFtpConnectTimeout.
See also: Login
13
14
15
16
17
1
1
CurrentDir
method
! Obtains the path name of the current working directory from the FTP server.
If a directory operation is not allowed given the current protocol state, CurrentDir returns
False, otherwise True is returned and the operation is initiated. When the server responds
with the requested information, the OnFtpStatus event is fired with the csCurrentDir
command status code, and the InfoText parameter will point to a null terminated string
containing the path name of the current working directory.
If the operation is rejected by the server, the OnFtpError event is fired and the operation is
terminated.
7
8
9
method
10
If the file or directory is successfully deleted at the server, the OnFtpStatus event is fired with
the scComplete status code. If the delete operation is rejected by the server, the OnFtpError
event is fired and the operation is terminated.
11
12
FileLength
13
14
15
16
17
564 Chapter 14: File Transfer Protocols
1
1
FileType
property
Default: ftAscii
property
6
property FtpLog : TApdFtpLog
If FtpLog is nil (the default), TApdFtpClient does not provide automatic logging. You can
install an OnFtpLog event handler to provide logging services in this case.
FtpLog is usually set automatically at design time to the first TApdFtpLog component that is
found on the form. If necessary, use the Object Inspector to select a different logging
component.
Setting the FtpLog property at run time is necessary only when using a dynamically created
logging component or when selecting among several logging components.
10
11
12
13
14
15
16
17
TApdFtpClient Component 565
1
1
Help
method
2
3
4
If the help operation is successful, the OnFtpStatus event is fired with the csDataAvail
command status code, and the InfoText parameter will point to a null terminated string
containing the raw text of the help information received from the server.
If the help operation is rejected by the server, the OnFtpError event is fired and the
operation is terminated.
8
9
10
11
12
13
14
15
16
method
function ListDir(
const RemotePathName : string; FullList : Boolean) : Boolean;
17
If the list operation is successful, the OnFtpStatus event is fired with the csDataAvail
command status code, and the InfoText parameter will point to a null terminated string
containing the raw text of the directory listing received from the server.
If the list operation is rejected by the server, the OnFtpError event is fired and the operation
is terminated.
Login
method
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Logout
method
2
3
! Terminates the active FTP session and closes the control connection.
If a file transfer is in progress then the control connection will remain open until the transfer
has completed.
If logout is allowed given the current protocol state the function returns True immediately.
When the user is logged out by the server, the OnFtpStatus event is fired with the scLogout
status code and the UserLoggedIn property is set to False.
When the control connection port has closed, the OnFtpStatus event is fired with the
scClose status code.
method
7
function MakeDir(const RemotePathName : string) : Boolean;
8
9
10
11
12
13
14
event
The server has rejected the FTP operation attempted and the operation is terminated.
ErrorCode contains the FTP error code returned by the server, and ErrorText points to a
null terminated string containing the text of the error.
See also: FTP Error Codes
17
568 Chapter 14: File Transfer Protocols
1
1
OnFtpLog
event
! Defines an event handler that is called at designated points during an FTP file operation.
The primary purpose of this event is to give the application a chance to log auditing
information about file operations during a FTP session.
See also: TApdFtpLog
OnFtpReply
event
! Defines an event handler that is called when an FTP server returns a reply.
An FTP reply consists of a 3-digit alphanumeric code as defined in RFC 959, followed by
some text. ReplyCode contains the integer form of the 3-digit alphanumeric code, and
ReplyText points to a null terminated string containing the entire reply text.
10
The primary purpose of this event is to monitor the servers response to the operations
initiated by the application. This event can be useful during debugging.
11
OnFtpStatus
event
12
13
14
! Defines an event handler that is called when the state of the FTP protocol changes.
StatusCode indicates the current state of the FTP client. When StatusCode equals
csDataAvail, InfoText points to a null terminated string containing raw text received from
the server. Otherwise InfoText is nil.
15
16
17
1
1
Meaning
scClose
scOpen
scLogin
scLogout
The FTP server has logged the user out. If this status is
the result of a call to Logout, then it will be followed by
scClose status when the port closes and should not be used
in this case to log on as another user.
scComplete
scCurrentDir
scDataAvail
scProgress
scTransferOk
scTimeout
7
8
9
10
11
12
13
14
15
16
17
1
1
OnWsError
event
This event handler is generated when an unhandled Winsock error occurs within the
control or data connection. ErrorCode contains the error code returned by Winsock. See
Error Handling and Exception Classes on page 900 for a list of error codes.
Password
property
Users who do not have a personal login account can gain access an FTP site with an
anonymous account. To log in with the anonymous account, set UserName to
ANONYMOUS and the password is your e-mail address.
8
9
method
function Rename(
const RemotePathName, NewPathName : string) : Boolean;
10
11
12
13
14
15
16
17
TApdFtpClient Component 571
1
1
RestartAt
run-time property
2
3
4
5
6
7
8
9
10
method
11
12
13
14
15
16
! Retrieve transfers a file from the FTP server to the local machine.
RemotePathName specifies the file at the server, and LocalPathName specifies the pathname
of the file on the local machine. RetrieveMode specifies how data will be written to an
existing local file.
The file will be transferred according to the file type specified by the FileType property.
If the local file already exists: rmAppend specifies that the incoming file data will be
appended to the end of the file; rmReplace specifies that the contents of the local file will be
replaced; rmRestart specifies that either the contents of the local file will be replaced starting
at the location specified by the RestartAt property, or if RestartAt = 0, the incoming data will
be appended to the end of the file. See RestartAt for more information about restarting a file
transfer.
If the local file does not exist, it will be created.
17
572 Chapter 14: File Transfer Protocols
1
1
method
1
2
3
4
6
7
FtpCmd is an FTP command string as specified in RFC 959. The FTP commands that can
be issued via this method are restricted to those not requiring a data connection. Thus all
file transfer commands (e.g., STOR, RETR, etc.) and the LIST and NLST commands are
prohibited. To illustrate, here are a few accepted commands:
SendFtpCommand('CWD pub/apro');
SendFtpCommand('STAT pub');
SendFtpCommand('HELP RETR');
9
10
11
The function returns True immediately if the command is initiated, otherwise False is
returned. Upon successful completion, the OnFtpStatus event is fired with the scComplete
status code.
12
If the server rejects the command for some reason, then the OnFtpError event is fired and
the operation is terminated.
13
14
15
16
17
TApdFtpClient Component 573
1
1
ServerAddress
property
2
3
4
5
method
6
7
8
9
10
11
If the operation is rejected by the server, the OnFtpError event is fired and the operation is
terminated.
12
13
14
15
16
17
574 Chapter 14: File Transfer Protocols
1
1
Store
method
1
2
3
RemotePathName specifies the file at the server. LocalPathName specifies the file on the
local machine. StoreMode identifies how the file will be written to an existing remote file.
The file will be transferred according to the file type specified by the FileType property. Be
sure to set FileType prior to initiating a file transfer. For text files use ftAscii, otherwise use
ftBinary.
If the remote file specified by RemotePathName already exists in the servers working
directory, StoreMode controls the effect of the transfer according to the following values:
Value
Effect
smAppend
The local file data will be appended at the end of the remote
file.
smReplace
smUnique
A remote file will be created with a unique name and the local
file will be written to it.
smRestart
6
7
8
9
10
11
If the remote file does not exist, it will be created in the servers current working directory.
See ChangeDir for information about changing the servers working directory.
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
property
Default: 1092
8
9
10
11
12
13
14
15
16
17
576 Chapter 14: File Transfer Protocols
1
1
UserName
property
FTP requires users to log in with a user name and password to gain access to the server. Be
sure to set Password prior to calling Login when connecting to an FTP server.
Users who do not have a personal login account can gain access an FTP site with an
anonymous account. To log in with the anonymous account, set UserName to
ANONYMOUS and the password is to the users e-mail address.
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdFtpClient Component 577
1
1
TApdAbstractStatus Class
TApdAbstractStatus is an abstract class that defines the methods and properties needed by a
component that automatically displays status while a TApdProtocol component is in the
process of transferring a file. You generally wont need to create a descendent class of your
own, since Async Professional supplies one, the TApdProtocolStatus component described
on page 582.
3
4
5
6
7
8
9
11
Once you have created an instance of your TApdAbstractStatus descendant, you must assign
it to the StatusDisplay property of your TProtocol component. When the protocol needs to
update the status display it calls the UpdateDisplay method of TApdAbstractStatus, which
you must override in order to update your particular kind of status window.
12
The source code for the TApdProtocolStatus component (in the AdPStat unit) serves as a
comprehensive example of writing a TApdAbstractStatus descendant.
10
13
14
15
16
17
578 Chapter 14: File Transfer Protocols
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdAbstractStatus (AdProtcl)
Properties
Display
Protocol
! Version
Methods
CreateDisplay
DestroyDisplay
UpdateDisplay
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Reference Section
CreateDisplay
2
procedure CreateDisplay; virtual; abstract;
3
4
5
6
7
8
9
10
11
12
14
15
16
property
17
run-time property
Protocol
13
UpdateDisplay
method
A descendant of TApdAbstractStatus must override this method to update the display form.
The TApdProtocol component calls this method regularly from its OnProtocolStatus event
handler.
On the very first call to UpdateDisplay, First equals True and UpdateDisplay should typically
call the Show method of Display to draw the outline and background of the status form. On
the very last call to UpdateDisplay, First equals False and UpdateDisplay should typically set
the Visible property of Display to False to erase the status window.
For all other calls to UpdateDisplay, First and Last both equal False. During these calls,
UpdateDisplay must update the various labels in the Display form. To get information about
the protocol status, it should use the Protocol field of TApdAbstractStatus to read the values
of various properties such as FileName and BytesTransferred. See Protocol status on
page 489 for a list of the most commonly used properties.
The CancelClick event handler, if one is provided, should call the CancelProtocol method of
TApdProtocol to terminate the protocol because the user clicked the Cancel button.
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
TApdProtocolStatus Component
3
4
5
6
7
8
9
10
11
12
13
14
Hierarchy
15
TComponent (VCL)
TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
16
17
1
1
TApdProtocolLog Component
TApdProtocolLog creates or appends to a text file whose name is given by the HistoryName
property. Each time the OnProtocolLog event of TApdProtocol is generated, the associated
TApdProtocolLog instance opens the file, writes a new line to it, and closes the file.
3
4
TApdProtocolLog also deletes the partial file that exists whenever a receive fails and the
protocol type is not Zmodem (which can resume interrupted transfers).
Following is a sample of the text file created by TApdProtocolLog:
Zmodem transmit started on 7/6/01 8:33:21 AM : C:\TEMP\PROJ1.EXE
Zmodem transmit finished OK 7/6/01 8:33:28 AM : C:\TEMP\PROJ1.EXE
Elapsed time:
0:07
CPS: 1792
Size: 12547
Zmodem transmit started on 7/6/01 8:33:28 AM : C:\TEMP\PROJ2.EXE
Zmodem transmit finished OK 7/6/01 8:33:37 AM : C:\TEMP\PROJ2.EXE
Elapsed time:
0:08
CPS: 1971
Size: 15775
Zmodem transmit started on 7/6/01 8:33:37 AM : C:\TEMP\PROJ2.EXE
Zmodem transmit failed C:\TEMP\PROJ2.EXE Cancel requested
Zmodem receive started on 7/6/01 8:34:03 AM : ZIPVO.PAS
Zmodem receive failed ZIPVO.PAS Cancel requested
8
9
10
12
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdProtocolLog (AdProtcl)
13
14
Properties
HistoryName
11
Hierarchy
DeleteFailed
Protocol
15
! Version
16
Methods
UpdateLog
17
TApdProtocolLog Component 583
1
1
Reference Section
DeleteFailed
property
2
property DeleteFailed : TDeleteFailed
Default: dfNonRecoverable
4
5
6
7
8
9
10
11
Description
dfNever
dfAlways
dfNonRecoverable
Regardless of the value of DeleteFailed, received files are never deleted when the protocol
error is ecCantWriteFile, since that error usually indicates that the receiver doesnt want to
disturb an existing file with the same name.
HistoryName
property
12
13
14
Default: APRO.HIS
! Determines the name of the file used to store the protocol log.
You should generally set the value of HistoryName before calling TApdProtocols
StartReceive or StartTransmit methods. However, because the log file is opened and closed
for each update, you can change HistoryName at any time you wish. If you set HistoryName
to an empty string, automatic logging is disabled until you assign a non-empty string.
15
16
17
584 Chapter 14: File Transfer Protocols
1
1
Protocol
property
Protocol is automatically initialized when the ProtocolLog property of the owning protocol
component is set. You can change Protocol to assign the log component to a different
protocol component.
UpdateLog
virtual method
The Log parameter has the same values passed to the OnProtocolLog event handler of
TApdProtocol. UpdateLog creates or appends to the log file, builds and writes a text string
for each event, and closes the log file. Additionally, it deletes the partially received file if Log
equals lfReceiveFail and the protocol type is not Zmodem.
Note that TApdProtocolLog contains a field named Protocol that UpdateLog uses to obtain
additional information about the protocol such as the FileName, FileLength, ElapsedTicks,
and ProtocolType.
9
10
11
12
13
14
15
16
17
TApdProtocolLog Component 585
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
586 Chapter 14: File Transfer Protocols
1
1
1
2
Document transfer using facsimile (fax) machines has become quite commonyou might
even say pervasivein todays business environment. Almost all of the currently
manufactured modems are faxmodems. A faxmodem is a standard data modem that also
has the ability, when used with appropriate software, to send and receive faxes. Since the
faxmodem is under program control, it can provide more sophisticated capabilities than a
dedicated fax machine. A few of the possibilities include database storage, editing, and
forwarding of received documents, as well as scheduled fax transmissions to multiple
recipients.
3
4
5
6
7
8
Microsoft has provided various levels of fax services in successive versions of Windows and
is trying to broaden and homogenize its fax services over all of its Windows operating
systems and environments. Parts of the fax services are available to programmers, but the
documentation is both scarce and sparse, causing many programmers to look elsewhere for
fax services.
9
10
11
12
13
14
15
16
17
587
1
1
Integrating faxmodem support into your application involves two central tasks:
Document conversion
3
Faxmodem send/receive
Document conversion means converting a file into a format suitable for fax transmission or
converting a received fax into a format suitable for further processing (viewing, printing,
etc.). Faxmodem send/receive covers all the steps needed to control a faxmodem when
sending and receiving fax documents.
Document conversion
Document conversion is the process of creating a compressed bitmap image suitable for fax
transmission. Async Professional can convert the following file formats:
17
588 Chapter 15: Fax Components
1
1
Faxmodem send/receive
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
Faxmodem specifications
Wherever possible the faxmodem components insulate you from the details of document
conversion and faxmodem control. Just as with the file transfer protocols, you dont need to
read and understand all of the faxmodem technical specifications to use the faxmodem
routines. However, it does help to have a basic understanding of the specifications. For
further information, see the technical specifications listed in Table 15.1.
Table 15.1: Technical specification documents
Document Number
Description
RS-465
RS-466
EIA/TIA-578
EIA/TIA-592
These documents are available from the EIA and TIA organizations directly. They can also
be obtained from Global Engineering Documents, a company that distributes engineering
specifications of all kinds. You can reach them by telephone at 800-854-7179 or 303-7922181. Their fax number is 303-397-2740.
10
11
12
13
14
15
16
17
590 Chapter 15: Fax Components
1
1
Document Conversion
Faxmodems dont transmit documents directly. Instead, they transmit a compressed bitmap
image in a format that is specific to Group 3 fax devices. The TApdFaxConverter component
provides methods for converting standard image file formats into this format. Async
Professional uses a proprietary image file format (APF) that stores bitmap data in this
Group 3 format. The TApdFaxUnpacker component provides methods for unpacking APF
files into standard image file formats.
2
3
4
6
7
8
9
10
11
fax header
12
13
.
.
14
.
header for page N
15
You usually dont need to understand this format in any detail, but the information is
documented here in case you need to write APF manipulation routines that arent provided
with Async Professional.
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
The file always begins with a header that contains, among other information, the number of
pages in the fax. Each page of the document follows, including a page header and the
compressed page data. The fax header and page header structures are defined in detail later
in this section.
The page data is a series of compressed raster line images. The line image optionally begins
with a word containing the number of bytes in the compressed line. (This word is stored
only in APF files that are ready for transmission; it is used to aid in padding each line to
match timing parameters of the receiving fax machine.) The length word is followed by the
line image in Group 3 compression format. If a pixel is set, it corresponds to a black dot on
the original image; if it is clear, it corresponds to a white dot.
Fax images can be converted and stored using two different resolutions. Standard resolution
is 200 horizontal dots per inch by 100 vertical dots per inch. High resolution has the same
horizontal resolution, but uses 200 vertical dots per inch. In some fax documentation, the
resolutions are described as 98 dots per inch and 196 dots per inch. Those numbers are
actually more exact, but 100 and 200 are easier to remember and are commonly used in
most fax documentation.
The standard width of a fax page is 1728 pixels, or about 8.5 inches. Several optional widths
are also available. Async Professional supports only one of the optional widths: 2048 pixels
per row, or about 10 inches. There is no fundamental limit on fax page length. Even so, youll
probably want to limit it to 11 inches, or 14 inches if you want to mimic legal size paper. This
is especially important when you consider that many faxes are now printed on sheet-fed
laser printers.
You specify the fax resolution and horizontal width when a document is converted to an
APF file. The resolution and width of each page are stored in the page header. When the APF
file is later transmitted, the TApdSendFax component reads the page header to determine
the resolution and width to use to transmit the fax.
13
14
15
16
Purpose
Signature
FDateTime
Date and time that the file was created (in DOS format).
SenderID
17
592 Chapter 15: Fax Components
1
1
Field
Purpose
Filler
PageCount
PageOfs
Padding
Purpose
ImgLength
ImgFlags
Padding
7
8
9
10
11
12
13
14
15
16
17
1
1
TApdFaxConverter Component
Converting a document to APF format is the first step in the fax transmission process. You
can convert your documents just before you transmit them or you can convert them in
advance. If you like, this conversion process can be completely transparent to your users or
you can convert your documents in a separate step that is not immediately followed by
transmission. Async Professional also provides a Windows printer driver that can create
APF files.
3
4
The TApdFaxConverter component can be used to convert ASCII text, BMP, PCX, DCX,
and TIFF files to Async Professionals proprietary file format. For input images not directly
supported by Async Professional, events and methods are published by the component that
allow the conversion of user-defined input images. Additionally, TApdFaxConverter can be
used for generically reading input image file for user-defined tasks.
8
9
10
11
12
13
14
15
The TApdFaxConverter component converts ASCII text files into APF files when the
InputDocumentType property of the converter is set to idText or idTextEx. Each text line of
the input file must end with a carriage return and a line feed. The converter can handle all
256 characters in the OEM character set. The converter cannot convert files that contain
embedded word processor formatting commands.
The text converter reads each line of the text file and converts the line into an appropriate
number of bitmapped raster lines. In essence, it converts each line into a picture of itself. To
do this, it uses a font table that contains a bitmap of each ASCII character. The number of
raster lines per text line depends on the pixel height of each character and the vertical
resolution of the fax conversion. The number of pixels in each raster line depends on the
pixel width of each character. For each raster line and each character in the line, the
converter finds the character bitmap in the font table and extracts the appropriate horizontal
pixel row. After looping through all the rows in the font, the converter has created a bitmap
image of the text line.
Async Professional can use any of the fonts available to Windows (such as the TrueType
fonts) when InputDocumentType is set to idTextEx, or it uses a set of built-in bitmapped
fonts when the InputDocumentType property is set to idText. The EnhFont property
controls which font is used when InputDocumentType is set to idTextEx.
16
17
594 Chapter 15: Fax Components
1
1
There are two built-in fonts available when InputDocumentType is set to idText a standard
font (ffStandard) and a smaller font (ffSmall). ffSmall is a small 12x8 (12 pixels wide by 8
pixels high) font used for creating header lines at the top of each transmitted fax page.
ffStandard is a 20x16 font used for all other text. ffStandard was chosen to provide text lines
at 6 lines per inch (66 lines on a standard 11 inch page). If you specify a high resolution
image, the fonts are scaled vertically to 16 and 32 pixels, respectively.
The built-in fonts are stored in APFAX.FNT, which is 16KB. This font file can be distributed
with your applications. Alternatively, you can bind APFAX.FNT directly into your program
by activating the compiler define BindFaxFont in AWCVTFAX.PAS (its defined by default).
When BindFaxFont is defined, APFAX.RES (created from APFAX.FNT using Borlands
Resource Workshop and a user-defined resource type) is linked into your program at
compile time. This adds about 16KB to your EXE file.
1
2
3
4
Async Professional provides document conversion routines for four popular graphics image
formats: BMP, PCX, DCX, and TIFF. The PCX format originated with the PC Paintbrush
program. The Async Professional conversion routines are tested with PCX images up
through version 3.0. DCX files are special container files that contain one or more PCX
images. TIFF (Tagged Image File Format) is a multi-platform format that is designed to
allow easy migration between platforms such as the Macintosh and the IBM PC. The Async
Professional conversion routines are tested with TIFF images up through version 4.0. BMP
files are standard Windows bitmap files.
Most Async Professional conversion routines work with monochrome images only. The
exception to this rule is the bitmap converter, which has the ability to dither color images.
Note that the dithering process is slower, so you should keep your images monochrome if
possible. Converting a BMP, PCX, or TIFF image file always produces an APF file containing
one fax page. Converting a DCX file produces a fax containing as many pages as are
contained in the DCX file.
Because BMP, PCX, DCX, and TIFF images are already a sequence of compressed raster
lines, the job of the TApdFaxConverter component is different than that done in the text
conversion process. For these files, the conversion routines unpack the images, then repack
them into the format required for faxing.
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
The images supported by Async Professional are stored assuming a pixel aspect ratio of 1 to
1, which means that the height of a pixel is the same as its width. For example, a 10 by 10 box
of pixels would appear on screen as a square, not a rectangle. Fax images, on the other hand,
have one of two aspect ratios. In high resolution, the aspect ratio is 1 to 1. In standard
resolution, the aspect ratio is 2 to 1. Hence, in a standard resolution fax, a 10 by 10 box of
pixels would not appear as a square. Instead it would be a rectangle twice as high as it is
wide.
Given the differences in aspect ratios, an image converted to a standard resolution APF
image appears distortedtall and thin. To solve this problem, the TApdFaxConverter
component can either double the width of an image or halve the height of an image when it
is converted to a standard resolution fax and the modified image still fits on the page.
These behaviors are enabled by turning on the coDoubleWidth and coHalfHeight options,
respectively. The coDoubleWidth option is on by default. coDoubleWidth was chosen over
coHalfHeight, since doubling the width of the image does not discard data, whereas halving
the height of the image causes every other line to be discarded.
The TApdFaxConverter also includes another option, coCenterImage, that is used during
image file conversions. When this option is enabled, as it is by default, graphic images are
automatically centered horizontally on the fax page. See the Options property on page 619
for more information about these options.
16
17
596 Chapter 15: Fax Components
1
1
After opening the image file, make one or more calls to the GetRasterLine method of the
converter. GetRasterLine takes four parameters: Buffer, BufLen, EndOfPage, and
MorePages.
Buffer is the buffer that receives the raster data you are reading. You should make this buffer
at least 512 bytes long. The actual length, in bytes, of the raster line is in BufLen upon return.
If the EndOfPage parameter is set to True on return, the end of the current page has been
reached. If MorePages is True, there are more pages in the file to be processed.
Lastly, you must call CloseFile to close the image file when you are done processing it.
Calling CloseFile closes the physical image file and disposes of several internal data
structures that are used to read the image file.
The following pseudo-code shows a typical use of the manual image processing methods of
the converter:
procedure ProcessImageFile(
FName : string; DocType : TFaxInputDocumentType);
var
Cvt : TApdFaxConverter;
Buffer : PByteArray; {type defined in SysUtils}
BufLen : Integer;
EndOfPage : Boolean;
MorePages : Boolean;
begin
GetMem(Buffer, 512);
6
7
8
9
10
try
Cvt := TApdFaxConverter.Create(nil);
except
FreeMem(Buffer, 512);
raise;
end;
11
12
Cvt.InputDocumentType := DocType;
Cvt.DocumentFile := FName;
13
try
Cvt.OpenFile;
except
Cvt.Free;
FreeMem(Buffer, 512);
raise;
end;
14
15
16
17
TApdFaxConverter Component 597
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
MorePages := True;
try
while MorePages do begin
...code for handling beginning of new page...
EndOfPage := False;
while not EndOfPage do begin
Cvt.GetRasterLine(Buffer^, BufLen, EndOfPage, MorePages);
...code to process data in Buffer...
end;
...code for handling end of page...
end;
finally
Cvt.CloseFile;
Cvt.Free;
FreeMem(Buffer, 512);
end;
end;
For a more complete demonstration of these features, see the EXIMAGE example program.
17
598 Chapter 15: Fax Components
1
1
uncompressed, raster data. Each raster line in the file is just long enough to hold each line
(i.e., no padding). The OnOpenUserFile, OnReadUserLine, and OnCloseUserFile events
open, read, and close image files of this hypothetical image type.
type
TImageHeader = packed record
Width : Word;
Height : Word;
end;
var
Header : TImageHeader; InputFile : File; ReadLen : Integer;
BytesInFile : LongInt; BytesProcessed : LongInt;
procedure Form1.ApdFaxConverter1OpenUserFile(
F : TObject; FName : string);
begin
{open the physical file}
AssignFile(InputFile, FName);
Reset(InputFile, 1);
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
Example
This simple example demonstrates the steps involved in creating an APF file from an ASCII
text file. Create a new project, add the following components, and set the property values as
indicated in the following table:
Property
Value
TApdFaxConverter
DocumentFile
TApdFaxConverter
InputDocumentType
idText
TLabel
10
11
12
13
14
15
16
TButton
Double click on the TButton component. A shell for an OnClick event is generated for you.
Modify the generated code to match the following code:
procedure TForm1.Button1Click(Sender : TObject);
var
SaveCursor : TCursor;
begin
SaveCursor := Cursor;
Cursor := crHourglass;
try
ApdFaxConverter1.ConvertToFile;
finally
Cursor := SaveCursor;
end;
end;
17
600 Chapter 15: Fax Components
1
1
This event changes the forms cursor to an hourglass, converts the file you specified in the
DocumentFile property, and then changes the cursor back to what it was before the
conversion.
Next, click on the TApdFaxConverter component, then click on the Events tab in the
Object Inspector. Double click on the OnStatus event. A shell of an OnStatus event
handler is generated for you. Modify the shell to match the following code:
procedure TForm1.ApdFaxConverter1Status(
F : TObject; Starting, Ending : Boolean;
PagesConverted, LinesConverted : Integer;
BytesToConvert, BytesConverted : LongInt;
var Abort : Boolean);
begin
if (BytesConverted <> 0) then begin
Label1.Caption := Format('Conversion is %d%% complete',
[(BytesToConvert * 100) div BytesConverted]);
Label1.Refresh;
end;
Abort := False;
end;
This procedure displays the progress of the conversion operation. You could also take
advantage of the PagesConverted and LinesConverted parameters to display additional
status information.
Now, save the project and run it. Click on the button. After a few moments, the hourglass
cursor should disappear and you will have, in the same directory as your input file, a file
called MYFILE.APF (where MYFILE is the first part of the filename that you chose for the
DocumentFile property). You can view this file with the VIEWER demonstration program,
or with the viewer in TCom.
1
2
3
4
6
7
8
9
10
11
12
13
The TApdFaxConverter component can convert many file formats into APF files when the
InputDocumentType property is idShell. When the InputDocumentType property is
idShell, the TApdFaxConverter component will use the ShellExecute API method to execute
the application associated with the selected file type and print the document to the
TurboPower fax printer driver. Unlike other InputDocumentTypes that you may have used
in the past, idShell uses the application that created the document to print to the printer
driver (i.e. Microsoft Word would be the one to send a .DOC file). Essentially, this would
use the ShellExecute with the printto parameter to print the specified document to our
APF Fax Printer or Print To Fax depending on your operating system.
14
15
16
17
1
1
1
2
3
4
5
6
7
8
If the application associated with the selected file format does not support the printto
verb, but does support the print verb, then idShell will change the default printer to the fax
printer driver, print the document using ShellExecute and the print verb, and then change
back to the original default printer. For example, in Windows 95 Notepad does not support
the printto, but does support print, but both are supported in Windows 98 and 2000.
An exception is raised if the application does not support the printto or print verbs.
The following example converts C:\MYDOC.DOC to an APF file:
OpenDialog1.Filter := 'Any file(*.*)|*.*';
if OpenDialog1.Execute then begin
ApdFaxConverter1.DocumentFile := OpenDialog1.FileName;
ApdFaxConverter1.InputDocumentType := idShell;
ApdFaxConverter1.ConvertToFile;
end; //End if
The printer driver will not generate TApdFaxDriverInterface events when a document is
printed using the TApdFaxConverter component. When a document is being converted,
two registry keys are added. One is the window handle that will receive an APW_ENDDOC
message indicating that the print job is complete. The other is the name of the output file.
See the protected ConvertShell method (not documented) in AdFaxCnv.pas for details on
the specific registry keys. If either of these keys is present, the TApdFaxDriverInterface
components OnDocStart and OnDocEnd events are not generated.
9
10
11
12
13
14
15
16
17
602 Chapter 15: Fax Components
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomFaxConverter (AdFaxCvt)
2
3
TApdFaxConverter (AdFaxCvt)
Properties
DefUserExtension
LeftMargin
TabStop
DocumentFile
LinesPerPage
TopMargin
EnhFont
Options
FontFile
OutFileName
FontType
Resolution
InputDocumentType
StationID
! Version
Width
6
7
Methods
CloseFile
ConvertBitmapToFile
MakeEndOfPage
CompressRasterLine
ConvertToFile
OpenFile
Convert
GetRasterLine
9
10
Events
OnCloseUserFile
OnOutputLine
OnOpenUserFile
OnReadUserLine
OnStatus
11
12
13
14
15
16
17
1
1
Reference Section
CloseFile
method
2
procedure CloseFile;
If you need to manually process input image files without converting them to APF files, use
CloseFile to close a previously opened (using OpenFile) image file. See Processing image
files on page 596 for more information.
6
7
8
9
10
CompressRasterLine
method
procedure CompressRasterLine(
var Buffer, OutputData; var OutLen : Integer);
11
12
13
14
15
The following example reads a line of raster data from an input file, compresses it, and writes
it to disk:
var
Buffer
OutBuf
BufLen
OutLen
EOP
More
OutFile
:
:
:
:
:
:
:
array[1..512] of Byte;
array[1..512] of Byte;
Integer;
Integer;
Boolean;
Boolean;
File;
...
16
17
604 Chapter 15: Fax Components
1
1
AssignFile(OutFile, 'C:\COMPRESS.IMG');
Rewrite(OutFile, 1);
...
ApdFaxConverter1.DocumentFile := 'C:\COMPRESS.IMG';
ApdFaxConverter1.OpenFile;
EOP := False;
while not EOP do begin
ApdFaxConverter1.GetRasterLine(Buffer, BufLen, EOP, More);
{make sure buffer length is 1728 pixels}
if (BufLen < 216) then
FillChar(Buffer[BufLen + 1], 0, 216 - BufLen);
ApdFaxConverter1.CompressRasterLine(Buffer, OutBuf, OutLen);
BlockWrite(OutFile, OutBuf, OutLen);
end;
CloseFile(OutFile);
ApdFaxConverter1.CloseFile;
1
2
3
4
7
Convert
method
procedure Convert;
! Converts the input image file, outputting raster data to a user event.
Convert reads each raster line from the input image file (specified by the DocumentFile
property), compresses it in Group 3 format, and passes the compressed data to the
OnOutputLine event. In that event, process the compressed data (either output it to a file or
use it for some other purpose).
If InputDocumentType equals idUser, the OnOpenUserFile, OnReadUserLine, and
OnCloseUserFile events are called to open, read, and close the image file. See Converting
user-defined image files on page 598 for more information.
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
The following example converts an image file and writes the compressed Group 3 data to a
file:
const
OutFileOpened : Boolean = False; OutFile : File;
procedure TForm1.ApdFaxConverter1OutputLine(
F : TObject; Data : PByteArray; Len : Integer;
EndOfPage, MorePages : Boolean);
var
EOPBuf : array[1..64] of Byte;
EOPLen : Integer;
begin
if not OutFileOpened then begin
AssignFile(OutFile, 'C:\OUTPUT.IMG');
Rewrite(OutFile, 1);
OutFileOpened := True;
end;
if not EndOfPage then
BlockWrite(OutFile, Data^, Len);
if EndOfPage then begin
ApdFaxConverter1.MakeEndOfPage(EOPBuf, EOPLen);
BlockWrite(OutFile, EOPBuf, EOPLen);
if not MorePages then begin
CloseFile(OutFile);
OutFileOpened := False;
end;
end;
end;
...
ApdFaxConverter1.DocumentFile := OpenDialog.FileName;
ApdFaxConverter1.Convert;
14
15
16
17
606 Chapter 15: Fax Components
1
1
ConvertBitmapToFile
method
ConvertToFile reads each raster line from the input bitmap (specified by the Bmp
parameter), compresses it in Group 3 format, and writes the compressed data (along with
the relevant document and page headers) in the APF file specified by OutFileName.
If the input bitmap is a color image, it will automatically get dithered to a monochrome
image as part of the conversion process. If the OutFileName property does not specify a file
extension, the default extension (DefFaxFileExt = APF) is appended to the output
filename.
See also: OutFileName
3
4
ConvertToFile
method
procedure ConvertToFile;
8
9
10
11
12
13
14
15
16
17
1
1
DefUserExtension
property
2
3
4
5
property
If the filename specified in DocumentFile does not contain an extension, a default extension
is appended when the file is opened. The default extension depends on the value of
InputDocumentType:
9
10
11
12
13
InputDocumentType
Default Extension
idNone
No default
idText
TXT
idTextEx
TXT
idTiff
TIF
idPcx
PCX
idDcx
DCX
idBmp
BMP
idUser
14
Unless you are sure of the current directory, the value of DocumentFile should be a fullyqualified (i.e., containing drive and directory information) filename.
15
16
ApdFaxConverter1.DocumentFile := 'C:\MYIMAGE.TIF';
ApdFaxConverter1.InputDocumentType := idTiff;
17
608 Chapter 15: Fax Components
1
1
EnhFont
property
If InputDocumentType is idTextEx, the FontFile and FontType properties are ignored and
the font specified by EnhFont is used by the fax converter instead. Any font available to
Windows can be used (double click on the property to invoke the font dialog and see a list of
the fonts). Only one font can be used for a document (i.e., font sizes and types cannot be
mixed within a single document).
3
4
There is an upper limit on the size of the font, but this limit is not typically reached unless a
very large font is used (e.g., greater than 72 pt). If the limit is exceeded, an ecEnhFontTooBig
error occurs during the conversion process.
The fax converter makes no attempt to keep all text on the page when the size of the font is
changed. You must ensure that the line length in the text file fits on the page in the desired
font. You might also need to adjust the LinesPerPage property to keep the lines on the page.
6
7
property
8
9
! Specifies the filename of the font file used by the ASCII text converter.
When an ASCII text file is opened or converted and InputDocumentType is idText, built-in
fonts supplied in APFAX.FNT are used. If the compiler define BindFaxFont in
AWFAXCVT.PAS is activated (the default), APFAX.FNT is bound directly into your
program.
10
If BindFaxFont is not activated, the file specified in FontFile is loaded into memory. FontFile
must be the fully-qualified name of the font file.
12
13
11
14
15
16
17
TApdFaxConverter Component 609
1
1
FontType
property
Default: ffStandard
3
4
5
! Specifies the size of the font used to convert ASCII text files.
FontType is used only if InputDocumentType is idText (meaning that the default Async
Professional font file is used). The default font file contains two sizes of fonts. If you want to
use other fonts, see the EnhFont property.
ffStandard is a 20x16 font (20 pixels wide by 16 pixels high). This font allows about 8.5
characters per horizontal inch (about 85 characters per line in a standard width fax), and
about 12.5 lines per vertical inch.
ffSmall is a 12x8 font that allows for about 14 characters per horizontal inch (about 144
characters per line in a standard width fax), and about 25 lines per vertical inch.
The following example converts a text file to an APF file using a small font:
8
9
10
11
12
ApdFaxConverter1.DocumentFile := 'C:\MYFILE.TXT';
ApdFaxConverter1.InputDocumentType := idText;
ApdFaxConverter1.OutFileName := 'C:\FAX.APF';
ApdFaxConverter1.FontType := ffSmall;
ApdFaxConverter1.ConvertToFile;
method
13
GetRasterLine is used to manually read a line of raster data from an input image file. A call
to GetRasterLine must be preceded by a call to OpenFile.
14
GetRasterLine returns the raster data in Buffer. BufLen contains the length, in bytes, of the
raster data. EndOfPage is set to True if the end of the input page has been reached.
MorePages is set to True if there are additional pages in the input file.
15
See Processing image files on page 596 for more information about reading image files.
16
17
610 Chapter 15: Fax Components
1
1
The following example opens an image file, reads the data from it, and closes it:
var
Buffer
BufLen
EOP
More
:
:
:
:
array[1..512] of Byte;
Integer;
Boolean;
Boolean;
...
ApdFaxConverter1.DocumentFile := OpenDialog.FileName;
ApdFaxConverter1.OpenFile;
EOP := False;
while not EOP do begin
ApdFaxConverter1.GetRasterLine(Buffer, BufLen, EOP, More);
...process the image data...
end;
ApdFaxConverter1.CloseFile;
3
4
6
7
InputDocumentType
property
Default: idNone
10
11
12
13
InputDocumentType
Image Type
idNone
No input image
idText
idTextEx
idTiff
idPcx
idDcx
idBmp
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
InputDocumentType
Image Type
idBitmap
Memory bitmap
idUser
TApdFaxConverter, using the default font file, can convert CR/LF delimited ASCII text files
that have characters in the Windows OEM character set. If the text file contains non-OEM
characters, they will not be converted correctly unless you provide another font.
The idText and idTextEx values are both used for ASCII text files. If InputDocumentType is
idText, the Async Professional built-in fonts are used to convert the text file. This means that
the font in the file specified by FontFile is used. If InputDocumentType is idTextEx, one of
the Windows fonts is used to convert the text file. This means that the font specified by
EnhFont is used (FontFile and FontType are ignored).
TIFF files can be single or multi-strip images, but must contain either uncompressed raster
data or MacPaint compressed raster data. The byte-order of the file can be either Intel (little
endian, where words are stored in byte-reversed order) or Motorola (big endian, where
words are stored high byte first).
Input BMP files must be uncompressed.
User-defined input images can be in any format. You must ensure, however, that raster data
passed back to the TApdFaxConverter component is encoded such that one bit of raster data
represents one pixel of input image. See Converting user-defined image files on page 598
for more information about converting unsupported image files.
The following example sets a TApdFaxConverter component up to convert a text file:
ApdFaxConverter1.DocumentFile := 'C:\MYFILE.TXT';
ApdFaxConverter1.InputDocumentType := idText;
12
13
14
15
16
17
612 Chapter 15: Fax Components
1
1
LeftMargin
property
Default: 50
! Specifies the width in pixels of the left margin in the APF file.
To make output faxes look more attractive, the TApdFaxConverter can add a fixed left
margin to all pages in the fax. This is necessary for some fax machines (and some viewing
software) that print or display the left edge of the fax too close to the edge of the page or the
visible screen. The default left margin of 50 pixels provides a reasonable amount of white
space at the left edge of the page, without using too much of the horizontal space. On a
standard width fax, 50 pixels consumes only 3% of the horizontal space.
See also: TopMargin
LinesPerPage
3
4
6
property
Default: 60
9
10
11
12
13
14
15
16
17
1
1
MakeEndOfPage
method
2
3
4
5
6
7
event
8
property OnCloseUserFile : TFaxCloseFileEvent
14
15
16
17
614 Chapter 15: Fax Components
1
1
OnOpenUserFile
event
TFaxOpenFileEvent = procedure(
F : TObject; FName : string) of object;
3
4
Use the value passed in FName to open the file. Do not use the value in DocumentFile
because it is not guaranteed to have a file extension. FName is generated from the value in
DocumentFile and DefUserExtension (if there is not extension in DocumentFile).
See Converting user-defined image files on page 598 for an example of converting an
unsupported image file type.
The following example demonstrates the use of the OnOpenUserFile, OnReadUserLine, and
OnCloseUserFile events:
var
InputFile : File;
LineLen : Integer;
BytesProcessed : LongInt;
TotalBytes : LongInt;
9
10
procedure Form1.ApdFaxConverter1OpenUserFile(
F : TObject; FName : string);
begin
AssignFile(InputFile, FName);
Reset(InputFile, 1);
...read file header...
LineLen := WidthInBytesAsReadFromImageHeader;
BytesProcessed := 0;
TotalBytes := FileSize(InputFile) - SizeOf(Header);
end;
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
procedure Form1.ApdFaxConverter1ReadUserLine(
F : TObject; Data : PByteArray; var Len : Integer;
var EndOfPage, MorePages : Boolean; var BytesRead,
BytesToRead : LongInt);
begin
BlockRead(InputFile, Data^, LineLen, Len);
Inc(BytesProcessed, Len);
EndOfPage := Eof(InputFile);
MorePages := False;
BytesRead := BytesProcessed;
BytesToRead := TotalBytes;
end;
procedure Form1.ApdFaxConverter1CloseUserFile(F : TObject);
begin
CloseFile(InputFile);
end;
8
9
10
11
12
13
14
15
! Defines an event handler that is called to output a line of Group 3 compressed data.
When the Convert method is called, each line of raster data is read from the input image,
compressed in Group 3 format, and passed to the OnOutputLine event. You can then
process the compressed data.
F contains a pointer to the fax converter component that generated the event. Data is a
pointer to an array of bytes that contain the compressed data. Len is the length of the
compressed data.
If EndOfPage is True, the end of a page of input data has been reached. You should call
MakeEndOfPage at this point, to output an end-of-page code. If MorePages is True, there
are more pages of data to compress and output. If MorePages is False, you can dispose of any
buffers and other data that are required for your output.
See also: Convert, MakeEndOfPage
16
17
616 Chapter 15: Fax Components
1
1
event
OnReadUserLine
event
TFaxReadLineEvent = procedure(
F : TObject; Data : PByteArray; var Len : Integer;
var EndOfPage, MorePages : Boolean) of object;
! Defines an event handler that is called to read a line of data from a user-defined image file.
When InputDocumentType is idUser, the TApdFaxConverter calls event handlers to open,
read, and close a user-defined image file. OnReadUserLine is called each time a new line of
raster data must be compressed.Data is a pointer to a 0-based array of bytes. On return from
this function, it should contain a 1-bit-per-pixel representation of the data to be
compressed. The bits should be on for black pixels and off for white pixels. Len should be
equal to the length of the data.
EndOfPage should be set to True if the end of the user-defined page has been reached. If
EndOfPage is True, the value of MorePages should indicate whether any more pages are
available. If MorePages is True, the TApdFaxConverter begins a new page and begins calling
OnReadUserLine for more data. If MorePages is False, the conversion process ends. See
Converting user-defined image files on page 598 for more information.
3
4
6
7
8
event
9
10
11
12
! Defines an event handler that is called to notify the user of the status of a conversion
operation.
13
During the conversion process, the TApdFaxConverter regularly calls the OnStatus event to
notify the user of the progress of the conversion.
14
If Starting is True, the conversion of the document is just beginning. This is the appropriate
time for you to do pre-conversion work (e.g., show the status display form).
15
If Ending is True, the conversion of the document is about to end. This is the appropriate
time for you to do post-conversion work (e.g., destroy the form that you were using to
display the conversion status).
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
PagesConverted is the number of pages that have been processed in the input document.
PagesConverted is equal to 1 after the conversion of the first page is started, then equal to 2
after the conversion of the second page is started, and so on. LinesConverted is the number
of raster lines that have been read and compressed on the current page.
BytesConverted is the number of image bytes that have been read from the input file.
BytesToConvert is the total number of bytes that will be read from the input file. These two
values can be used to create a percent complete style progress bar for the conversion
process.
Abort determines whether the conversion process will terminate prematurely. Set Abort to
True if you need to abort the conversion process.
The following example shows how to implement a percent complete indicator for a fax
converter:
procedure Form1.ApdFaxConverter1Status(
F : TObject; Starting, Ending : Boolean;
PagesConverted, LinesConverted : Integer;
BytesConverted, BytesToConvert : LongInt; var Abort : Boolean);
const
Frm : TConvertStatusForm = nil;
begin
if Starting then begin
Frm := TConvertStatusForm.Create(Application);
Frm.Show;
end else if Ending then begin
Frm.Close;
Frm.Free;
end else begin
if Frm.AbortBtnClicked then
Abort := True
else
{show progress}
Frm.Label1.Caption := Format(
'Conversion is %d percent complete',
[(BytesConverted * 100) div BytesToConvert]);
end;
end;
15
16
17
618 Chapter 15: Fax Components
1
1
OpenFile
method
procedure OpenFile;
If you need to process an image file without converting it to an APF file, use OpenFile to
open the file specified by DocumentFile and InputDocumentType. Then use GetRasterLine
to read raster data from the image file. When you are finished reading the image, use
CloseFile to close the image file.
3
4
property
6
7
8
9
10
11
Option
Result
coDoubleWidth
coHalfHeight
coCenterImage
coYield
coYieldOften
coDoubleWidth and coHalfHeight adjust for the difference between standard and high
resolution faxes. If neither of these options are on, and an image is converted to a standard
resolution fax (Resolution equals frNormal), the resulting fax looks vertically elongated. If
coDoubleWidth is on, this effect is compensated for by doubling the width of the input
image (if possible), causing the standard resolution fax to look normal. Doubling is not
12
13
14
15
16
17
1
1
1
2
possible if the new width would be wider than the width specified by the Width property. If
coHalfHeight is on, this effect is compensated for by discarding every other raster line of
input image.
coDoubleWidth and coHalfHeight are mutually exclusive (they cannot both be on).
Attempts to add one of these options to the option set when the other is already in the set
are ignored.
If coCenterImage is on (the default), converted image files (not text files) are centered on the
fax page. If coCenterImage is not on, converted image files are placed flush left on the page.
5
6
7
8
9
10
If coYield is on (the default), the TApdFaxConverter yields to Windows at the end of every
converted page, giving other applications a chance to run. If coYield is not on, the
TApdFaxConverter hogs the system for the amount of time required to convert the input
file. This results in a faster conversion, but is not recommended.
coYieldOften is the same as coYield, except that yielding is much more frequent. Control is
relinquished by the converter at the end of every converted raster line. This results in a
slower conversion, but Windows runs better. If coYieldOften is turned on, coYield is turned
on automatically.
The following example turns on the yielding features of the converter:
{make sure the converter yields regularly}
ApdFaxConverter1.Options := ApdFaxConverter1.Options +
[coYield, coYieldOften];
11
12
13
14
property
15
16
ApdFaxConverter1.DocumentFile := 'C:\MYFILE.TXT';
ApdFaxConverter1.InputDocumentType := idText;
ApdFaxConverter1.OutFileName := 'C:\FAX.APF';
ApdFaxConverter1.ConvertToFile;
17
620 Chapter 15: Fax Components
1
1
Resolution
property
Default: frNormal
6
7
8
9
StationID
property
10
11
12
13
14
15
16
17
1
1
1
2
3
StationID is stored in the header of the converted APF file. This string is not used when the
fax is transmitted, since the StationID property of TApdAbstractFax is used to determine
the string that is sent through the faxmodem. If you want to send the station ID embedded
in the APF file, you should read the SenderID field from the fax header and use it to set the
StationID property of TApdAbstractFax before sending.
See also: TApdAbstractFax.StationID
TabStop
property
4
property TabStop : Cardinal
Default: 4
During a fax conversion, tab characters ($09) in the input text are expanded to one to
TabStop space characters ($20).
To demonstrate how space characters are inserted, these examples use the default TabStop of
4. If the input data is:
<tab>This is a test
9
10
11
<space><space><space><space>This is a test
12
Only three spaces are needed because the word test is only three spaces away from a
tabstop.
13
14
15
16
17
622 Chapter 15: Fax Components
1
1
TopMargin
property
Default: 0
! Specifies the size in raster lines of the top margin in the APF file.
To avoid problems with fax machines that print faxes too close to the top of the paper
(thereby distorting the image/text near the top of the page), the TApdFaxConverter can add
a fixed-sized region of white space at the top of every page.
3
4
TopMargin is the number of blank raster lines added to the top of every converted page. The
visible amount of white space varies depending on the value of Resolution (i.e., the margin
appears smaller on high resolution faxes).
See also: LeftMargin, Resolution
Width
property
7
property Width : TFaxWidth
TFaxWidth = (fwNormal, fwWide);
Default: fwNormal
10
11
12
13
14
15
16
17
TApdFaxConverter Component 623
1
1
TApdFaxUnpacker Component
Fax images are transmitted and received in a compressed bitmap image format. The
compressed data must then be unpacked before you can view, print, or edit the fax.
The unpacking methods of the TApdFaxUnpacker component handle all of the work of
opening the APF file, finding the desired page, and uncompressing each raster linebut
thats as far as the general purpose routines can go. The unpacked raster lines are passed to
your application through an event handler. Your application can print, display, or otherwise
process the line.
4
5
6
7
8
9
10
11
12
13
14
15
16
Async Professional provides additional components to perform some of the most common
operations for fax files: viewing, printing and converting to a graphics format. To view faxes,
use the TApdFaxViewer component (see page 649). Printing is performed by the
TApdFaxPrinter component (see page 674). The TApdFaxUnpacker itself can convert a fax
to a different graphics format. It can unpack a fax into a memory bitmap (i.e., a VCL
TBitmap instance), as well as a BMP, PCX, DCX, or TIFF image file. If you need to perform
any other processing on a fax file, you must implement an OnOutputLine event handler.
OnOutputLine event
When the UnpackPage or UnpackFile methods of the TApdFaxUnpacker component are
called, the data in the APF file is decompressed and passed to an OnOutputLine event
handler.
In the following example an OnOutputLine event handler writes the raw raster data to a file:
var
OutFile : File;
...
procedure Form1.ApdFaxUnpackerOutputLine(
Sender : TObject; Starting, Ending : Boolean;
Data : PByteArray; Len, PageNum : Integer);
begin
if Starting then begin
AssignFile(OutFile, 'C:\MYIMAGE.IMG');
Rewrite(OutFile, 1);
end else if Ending then begin
CloseFile(OutFile);
end else
BlockWrite(OutFile, Data^, Len);
end;
17
624 Chapter 15: Fax Components
1
1
Sender is the object instance of the TApdFaxUnpacker component that generated the event.
If Starting is True, the fax unpack process is just beginning. In this example, Starting is used
to determine when to open the output file.
If Ending is True, the fax unpack process is ending (due to successful completion of the
unpack or an error condition). In this example, Ending is used to determine when to close
the output file.
Data is a pointer to a 0-based array of bytes that contains the decompressed data. Len is the
length of the data. In this example, Len bytes are written from Data to the file OutFile.
1
2
3
4
PageNum contains the number of the page that is currently being unpacked. This can be
used to determine when a page change occurs (this is important when converting
multi-page faxes to multi-page image formats).
Memory bitmaps
The TApdFaxUnpacker can unpack a fax file (or page) to a TBitmap class. This is useful if
you want to unpack a fax and manipulate the image before using it, or if you simply want to
copy a fax to a TCanvas (or to the Picture property of a TImage component).
8
9
var
Bmp : TBitmap;
Image1 : TImage;
10
begin
ApdFaxUnpacker1.InFileName := 'D:\MYFAX.APF';
try
Bmp := ApdFaxUnpacker1.UnpackFileToBitmap;
Image1.Picture.Bitmap := Bmp;
except
MessageDlg('Unpack failed!', mtError, [mbOK], 0);
end;
end;
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
Additionally, you can use the Canvas property of the Bitmap class to place additional
graphics onto a fax image (for example, to create a custom cover page). The following
example demonstrates the technique:
Form1 = class(TForm)
Image1 : TImage;
...
procedure TForm1.BitBtn1Click(Sender : TObject);
var
Bmp1 : TBitmap;
Bmp2 : TBitmap;
begin
ApdFaxUnpacker1.InFileName := 'D:\MYFAX1.APF';
Bmp1 := ApdFaxUnpacker1.UnpackPageToBitmap(1);
ApdFaxUnpacker1.InFileName := 'D:\MYFAX2.APF';
Bmp2 := ApdFaxUnpacker1.UnpackPageToBitmap(1);
Bmp1.Canvas.Draw(0, 0, Bmp2);
Bmp2.Free;
Image1.Picture.Bitmap := Bmp1;
end;
10
This example unpacks MYFAX1.APF and MYFAX2.APF into memory bitmaps. The bitmap
of MYFAX2.APF is then placed on top of the bitmap of MYFAX1.APF by the call to Draw.
Finally, the image is drawn on the form by placing the new bitmap (in Bmp1) into the
Picture property of Image1 (a TImage component).
11
Scaling
12
13
14
The TApdFaxUnpacker component can scale (i.e., make the size larger or smaller) a fax as it
is unpacked. When you call one of the TApdFaxUnpacker UnpackXxx methods, the Scaling
property is examined to see if the output image should be scaled (Scaling equals True).
The image is scaled depending on the values of four properties. HorizMult and HorizDiv are
combined to form a fraction (HorizMult/HorizDiv) that is multiplied by the width
(horizontal aspect) of the fax to determine its new width. VertMult and VertDiv are
combined to form a fraction (VertMult/VertDiv) that is multiplied by the height (vertical
aspect) of the fax to determine its new height.
15
16
17
626 Chapter 15: Fax Components
1
1
For example, assume a standard resolution fax (200x100) is being unpacked. When the fax
is unpacked and converted into square pixels, the resulting image looks shorter than it
should (since, in the original, the height of the pixels was twice as large as width of the
pixels). To compensate for this, you can use the following:
ApdFaxUnpacker1.Scaling
ApdFaxUnpacker1.HorizMult
ApdFaxUnpacker1.HorizDiv
ApdFaxUnpacker1.VertMult
ApdFaxUnpacker1.VertDiv
:=
:=
:=
:=
:=
True;
1;
1;
2;
1;
1
2
3
4
This specifies that the unpacked fax data is to be scaled to be twice as tall (VertMult /
VertDiv = 2/1 = 2) as it normally would be. This makes the unpacked standard resolution
fax look normal.
Similarly, the following code achieves the same effect, but the resultant image is smaller:
ApdFaxUnpacker1.Scaling
ApdFaxUnpacker1.HorizMult
ApdFaxUnpacker1.HorizDiv
ApdFaxUnpacker1.VertMult
ApdFaxUnpacker1.VertDiv
:=
:=
:=
:=
:=
True;
1;
2;
1;
1;
7
8
This specifies that the width of the unpacked fax is to be halved (HorizMult / HorizDiv =
1/2). This, too, compensates for the difference in aspect ratio between a standard and high
resolution fax, but the resulting image is smaller than the one produced in the previous
example.
To make it easier to compensate for the aspect ratio of standard resolution faxes, the
AutoScaleMode property allows you to specify that the scaling should be performed
automatically. You can request either methoddoubling the height or halving the width.
The Scaling property can be used in many ways to produce a nearly unlimited range of
images. For instance, you can create an image that is 1/3 the size of the original fax with the
following code:
ApdFaxUnpacker1.Scaling
ApdFaxUnpacker1.HorizMult
ApdFaxUnpacker1.HorizDiv
ApdFaxUnpacker1.VertMult
ApdFaxUnpacker1.VertDiv
:=
:=
:=
:=
:=
True;
1;
3;
1;
3;
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
You could create a thumbnail 32x42 image of the fax (assuming an 8.5" x 11" fax) with the
following code:
ApdFaxUnpacker1.Scaling
ApdFaxUnpacker1.HorizMult
ApdFaxUnpacker1.HorizDiv
ApdFaxUnpacker1.VertMult
ApdFaxUnpacker1.VertDiv
To make it easier to view large faxes that have a lot of white space, the TApdFaxUnpacker can
compress a specified number of blank raster lines into a smaller number of blank raster
lines. This feature can be used to save paper when printing a large volume of faxes. For
example, if a page is slightly longer than 11 inches, the white space compression feature can
often make it fit nicely on an 11inch piece of paper, eliminating the need for an extra sheet of
paper.
To use the white space compression feature, set WhitespaceCompression to True. Every
occurrence of WhitespaceFrom or more consecutive blank lines is replaced with
WhitespaceTo blank lines. For example, if WhitespaceFrom is 20 and WhiteSpaceTo is 5,
then any occurrence of 20 or more consecutive blank lines is compressed to 5 blank lines.
Example
This example demonstrates the steps involved in unpacking a fax file to a memory bitmap.
Create a new project, add the following components, and set the property values as
indicated in Table 15.6.
Table 15.6: Example components and property values
Component
Property
Value
TApdFaxUnpacker
InFileName
TImage
Align
alClient
15
16
17
628 Chapter 15: Fax Components
True;
1;
54;
1;
54;
14
:=
:=
:=
:=
:=
After adding the components and setting their properties, click on the combo box at the top
of the Object Inspector and select Form1. Next, click on the Events tab at the bottom of
the Object Inspector. From the events page, double click on the OnCreate event. A shell
for an OnCreate event is generated for you. Modify the generated code to match this:
procedure TForm1.FormCreate(Sender : TObject);
var
Bmp : TBitmap;
begin
Bmp := ApdFaxUnpacker1.UnpackPageToBitmap(1);
Image1.Picture.Bitmap := Bmp;
end;
1
2
3
4
This event loads the fax specified by InFileName into the TBitmap Bmp. This TBitmap is
assigned to the Picture property of the TImage component and is automatically displayed
on the screen.
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomFaxUnpacker (AdFaxCvt)
8
9
TApdFaxUnpacker (AdFaxCvt)
10
11
12
13
14
15
16
17
TApdFaxUnpacker Component 629
1
1
1
2
3
4
5
6
7
8
Properties
AutoScaleMode
NumPages
VertMult
FaxResolution
Options
WhitespaceCompression
FaxWidth
OutFileName
WhitespaceFrom
HorizDiv
Scaling
WhitespaceTo
HorizMult
InFileName
ExtractPage
UnpackFileToPcx
UnpackPageToDcx
UnpackFile
UnpackFileToTiff
UnpackPageToPcx
UnpackFileToBitmap
UnpackPage
UnpackPageToTiff
UnpackFileToBmp
UnpackPageToBitmap
UnpackFileToDcx
UnpackPageToBmp
Events
OnOutputLine
10
11
12
13
14
15
16
17
630 Chapter 15: Fax Components
VertDiv
Methods
! Version
OnStatus
Reference Section
AutoScaleMode
property
2
property AutoScaleMode : TAutoScaleMode
TAutoScaleMode = (asNone, asDoubleHeight, asHalfWidth);
Value
Result
asNone
asDoubleHeight
asHalfWidth
8
9
10
method
11
12
13
14
15
16
17
1
1
1
2
3
4
5
The following example extracts each page in a fax to a separate fax file:
var
I : Integer;
....
ApdFaxUnpacker1.InFileName := OpenDialog1.FileName;
for I := 1 to ApdFaxUnpacker1.NumPages do begin
ApdFaxUnpacker1.OutFileName := 'PAGE' + IntToStr(I) + '.APF';
ApdFaxUnpacker1.ExtractPage(I);
end;
....
7
8
9
10
11
12
13
14
15
16
17
632 Chapter 15: Fax Components
1
1
FaxWidth
3
4
The following example examines the width of a fax and allocates a buffer large enough to
hold a line of uncompressed fax data:
ApdFaxUnpacker1.InFileName := OpenDialog.FileName;
if (ApdFaxUnpacker1.FaxWidth = fwNormal) then
GetMem(Buffer, 1728 div 8)
else
GetMem(Buffer, 2048 div 8);
6
7
8
property
Default: 1
10
11
12
13
14
15
16
17
TApdFaxUnpacker Component 633
1
1
HorizMult
property
Default: 1
5
6
7
8
9
10
InFileName
property InFileName : string
11
12
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
ApdFaxUnpacker1.UnpackFileToBmp;
13
14
15
16
17
634 Chapter 15: Fax Components
1
1
property
NumPages
If the file specified in InFileName is valid, NumPages is the number of pages in the fax.
The following example unpacks each page of a fax into individual memory bitmaps and
processes them:
3
4
var
I : Integer;
B : TBitmap;
...
ApdFaxUnpacker1.InFileName := OpenDialog.FileName;
for I := 1 to ApdFaxUnpacker1.NumPages do begin
B := UnpackPageToBitmap(I);
...process bitmap image...
B.Free;
end;
6
7
8
event
! Defines an event handler that is called to output a line of decompressed raster data.
As each line of data in an APF file is decompressed, the OnOutputLine event handler is
called to output the decompressed data. Once the data is passed to OnOutputLine, it is
discarded to make room for the next line of decompressed data. You can do anything you
like with the decompressed data: display it to the screen, write it to a file, etc.
If Starting is True, no data is passed to the eventit is simply a notification that the
unpacking process is beginning. Any resources needed for handling the unpacked data
(buffers, output files, etc.) should be allocated.
If Ending is True, no data is passed to the eventit is simply a notification that the
unpacking process is ending. Any resources that were allocated at the beginning of the
unpack process should be freed.
10
11
12
13
14
15
16
17
1
1
1
2
Data is a pointer to a zero-based array of bytes that contains the decompressed data. Each
byte in the array represents 8 pixels of raster data. The raster data is represented as one-bitper-pixel. The bits are on for black pixels and off for white pixels. Len contains the length of
the data. PageNum is the number of the page that is currently being unpacked.
The following example writes each line of decompressed data to a file:
var
OutFile : File;
...
5
6
7
8
9
10
procedure Form1.ApdFaxUnpackerOutputLine(
Sender : TObject; Starting, Ending : Boolean;
Data : PByteArray; Len, PageNum : Integer);
begin
if Starting then begin
AssignFile(OutFile, 'C:\MYIMAGE.IMG');
Rewrite(OutFile, 1);
end else if Ending then begin
CloseFile(OutFile);
end else
BlockWrite(OutFile, Data^, Len);
end;
event
11
12
TUnpackStatusEvent = procedure(
Sender : TObject; FName : string; PageNum : Integer;
BytesUnpacked, BytesToUnpack : LongInt); of object;
! Defines an event handler that is called to display the progress of an unpack operation.
13
The OnStatus event handler is called after each line of a fax is read and decompressed. You
can use the information passed to the event to create a status display for the user.
14
FName is the name of the file that is being unpacked. PageNum is the number of the page
that is currently being unpacked.
15
BytesUnpacked is the number of bytes that have been unpacked so far. BytesToUnpack is the
total number of bytes that will be unpacked in the file. You can use these two values to
determine the percent completion of the unpack operation.
16
17
1
1
The following example uses the OnStatus event to display a percent complete to the user:
procedure Form1.ApdFaxUnpacker1Status(
Sender : TObject; FName : string; PageNum : Integer;
BytesUnpacked, BytesToUnpack : LongInt) : Boolean;
begin
Label1.Caption := Format(
'Converting page %d of %s, %d%% complete',
[PageNum, FName, (BytesUnpacked * 100) div BytesToUnpack];
end;
1
2
3
4
property
Default: [uoYield]
To turn the yield option on, turn it on in the Object Inspector or use the following code:
ApdFaxUnpacker1.Options := [uoYield];
9
10
11
12
13
14
15
16
17
TApdFaxUnpacker Component 637
1
1
OutFileName
property
2
3
4
5
6
7
8
9
ApdFaxUnpacker1.OutFileName := 'C:\MYFILE.BMP';
ApdFaxUnpacker1.UnpackFileToBmp;
property
10
11
12
13
For example, assume that a fax is 1728 pixels wide and 2200 pixels tall. If HorizMult equals 1,
HorizDiv equals 2, VertMult equals 4, and VertDiv equals 3, the fax would be scaled to 864
pixels wide (1728 * 1 / 2) and 2933 pixels high (2200 * 4 / 3 = 2933).
14
15
16
17
638 Chapter 15: Fax Components
1
1
UnpackFile
method
procedure UnpackFile;
UnpackFile reads and unpacks every line of the fax file specified by InFileName and passes
the unpacked data to the OnOutputLine event handler. If Scaling is True, the data is scaled
before it is passed to the OnOutputLine event handler.
The following example unpacks a fax and writes the unpacked data to a file:
var
OutFile : File;
...
procedure Form1.ApdFaxUnpacker1OutputLine(
Sender : TObject; Starting, Ending : Boolean;
Data : PByteArray; Len, PageNum : Integer);
begin
if Starting then begin
AssignFile(OutFile, 'C:\MYIMAGE.IMG');
Rewrite(OutFile, 1);
end else if Ending then begin
CloseFile(OutFile);
end else
BlockWrite(OutFile, Data^, Len);
end;
...
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
ApdFaxUnpacker1.UnpackFile;
6
7
8
9
10
11
12
13
14
15
16
17
1
1
UnpackFileToBitmap
method
2
3
4
Since the TBitmap class does not include the concept of pages, all pages in the input APF file
are placed into the TBitmap in a single image. If the input fax contains 9 pages, those 9 pages
are placed into the TBitmap as a single image, one right after the other.
The following example unpacks a fax and puts the unpacked data in a memory bitmap:
var
Bmp : TBitmap;
...
8
9
10
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
Bmp := ApdFaxUnpacker1.UnpackFileToBitmap;
Form1.Image1.Picture.Bitmap := Bmp;
Bmp.Free;
11
12
13
14
15
16
17
640 Chapter 15: Fax Components
1
1
UnpackFileToBmp
method
procedure UnpackFileToBmp;
UnpackFileToBmp reads and unpacks every line of the fax file specified by InFileName and
writes the unpacked data to a Windows bitmap (BMP) file. The data is written to the file
specified by OutFileName. If the file name in OutFileName does not have an extension, a
default extension of BMP is appended. If Scaling is True, the data is scaled before it is written
to the file.
3
4
Since the Windows bitmap file format does not include the concept of pages, all pages in the
input APF file are placed into a single image in the BMP file. If the input fax contains 9 pages,
those 9 pages are written to a single bitmap, one right after the other.
The following example creates a bitmap file called C:\MYIMAGE.BMP:
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
ApdFaxUnpacker1.OutFileName := 'C:\MYIMAGE.BMP';
ApdFaxUnpacker1.UnpackFileToBmp;
8
method
procedure UnpackFileToDcx;
10
UnpackFileToDcx reads and unpacks every line of the fax file specified by InFileName and
writes the unpacked data to a DCX file. The data is written to the file specified by
OutFileName. If the file name in OutFileName does not have an extension, a default
extension of DCX is appended. If Scaling is True, the data is scaled before it is written to the
file.
The DCX image file format is a multi-page file format. Each page in the input APF file is
placed in a separate page in the DCX file.
The following example creates a DCX file called C:\MYIMAGE.DCX:
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
ApdFaxUnpacker1.OutFileName := 'C:\MYIMAGE.DCX';
ApdFaxUnpacker1.UnpackFileToDcx;
11
12
13
14
15
16
17
TApdFaxUnpacker Component 641
1
1
UnpackFileToPcx
method
procedure UnpackFileToPcx;
2
3
4
Since the PCX file format does not include the concept of pages, all pages in the input APF
file are placed into a single image in the PCX file. If the input fax contains 9 pages, those 9
pages are output to a single PCX image, one right after the other.
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
ApdFaxUnpacker1.OutFileName := 'C:\MYIMAGE.PCX';
ApdFaxUnpacker1.UnpackFileToPcx;
8
9
method
procedure UnpackFileToTiff;
10
11
12
13
Since the TIFF file format does not include the concept of pages, all pages in the input APF
file are placed into a single image in the TIFF file. If the input fax contains 9 pages, those 9
pages are written to a single TIFF image, one right after the other.
14
15
16
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
ApdFaxUnpacker1.OutFileName := 'C:\MYIMAGE.TIF';
ApdFaxUnpacker1.UnpackFileToTiff;
17
642 Chapter 15: Fax Components
1
1
UnpackPage
method
UnpackPage reads and unpacks the page specified by Page in the fax file specified by
InFileName. The unpacked data is passed to the OnOutputLine event handler. If Page is
invalid (i.e., if it is 0 or greater than the total number of pages in the fax file), an
EInvalidPageNumber exception is raised. If Scaling is True, the data is scaled before it is
passed to the OnOutputLine event handler.
3
4
The following example unpacks the first page of a fax and writes the unpacked data to a file:
var
OutFile : File;
...
procedure Form1.ApdFaxUnpacker1OutputLine(
Sender : TObject; Starting, Ending : Boolean;
Data : PByteArray; Len, PageNum : Integer);
begin
if Starting then begin
AssignFile(OutFile, 'C:\MYIMAGE.IMG');
Rewrite(OutFile, 1);
end else if Ending then begin
CloseFile(OutFile);
end else
BlockWrite(OutFile, Data^, Len);
end;
...
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
ApdFaxUnpacker1.UnpackPage(1);
7
8
9
10
11
12
13
14
15
16
17
TApdFaxUnpacker Component 643
1
1
UnpackPageToBitmap
method
UnpackPageToBitmap reads and unpacks the page specified by Page in the fax file specified
by InFileName and puts the unpacked data in a memory bitmap. The memory bitmap is
returned by this function in the form of a VCL TBitmap instance. If Scaling is True, the data
is scaled before the memory bitmap is created. You are responsible for freeing the bitmap
when you are finished with it.
The following example unpacks the first page of a fax and puts the unpacked data in a
memory bitmap:
6
7
8
var
Bmp : TBitmap;
...
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
Bmp := ApdFaxUnpacker1.UnpackPageToBitmap(1);
Form1.Image1.Picture.Bitmap := Bmp;
Bmp.Free;
9
10
UnpackPageToBmp
method
UnpackPageToBmp reads and unpacks the page specified by Page in the fax file specified by
InFileName and writes the unpacked data to a Windows bitmap (BMP) file. The data is
written to the file specified by OutFileName. If the file name in OutFileName does not have
an extension, a default extension of BMP is appended. If Scaling is True, the data is scaled
before it is written to the file.
The following example writes the first page of a fax file to C:\MYIMAGE.BMP:
14
15
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
ApdFaxUnpacker1.OutFileName := 'C:\MYIMAGE.BMP';
ApdFaxUnpacker1.UnpackPageToBmp(1);
16
17
644 Chapter 15: Fax Components
1
1
UnpackPageToDcx
method
UnpackPageToDcx reads and unpacks the page specified by Page in the fax file specified by
InFileName and writes the unpacked data to a DCX file. The data is written to the file
specified by OutFileName. If the file name in OutFileName does not have an extension, a
default extension of DCX is appended. If Scaling is True, the data is scaled before it is written
to the file.
3
4
The DCX file format is a multi-page file format. Since only one page is unpacked by the
UnpackPageToDcx method, the resultant DCX file contains only one page.
The following example writes the first page of a fax file to C:\MYIMAGE.DCX:
ApdFaxUnpacker1.InFileName := 'C:\MYFAX.APF';
ApdFaxUnpacker1.OutFileName := 'C:\MYIMAGE.DCX';
ApdFaxUnpacker1.UnpackPageToDcx(1);
method
8
9
10
11
12
13
14
15
16
17
TApdFaxUnpacker Component 645
1
1
UnpackPageToTiff
method
2
3
4
5
6
7
8
VertDiv
property
Default: 1
9
10
11
12
13
Default: 1
16
17
646 Chapter 15: Fax Components
1
1
property
WhitespaceCompression
property
Default: False
3
4
property
8
9
Default: 0
! Specifies the number of consecutive blank lines that are compressed if white space
compression is enabled.
10
11
The value of WhitespaceFrom must be greater than the value of WhitespaceTo. If it is not, an
EBadArgument exception is raised when an UnpackXxx method is called.
12
13
14
15
16
17
TApdFaxUnpacker Component 647
1
1
WhitespaceTo
property
Default: 0
! Specifies the number of blank lines that are substituted for every occurrence of
3
The value of WhitespaceTo must be less than the value of WhitespaceFrom. If it is not, an
EBadArgument exception is raised when any of the UnpackXxx methods are called.
7
8
9
10
11
12
13
14
15
16
17
648 Chapter 15: Fax Components
1
1
TApdFaxViewer Component
The TApdFaxViewer component makes it easy to view received faxes (or any APF file).
When the FileName property is set to the name of a fax file, the TApdFaxViewer loads the
fax into memory, converting each page into a memory bitmap which can then be displayed
on the screen. If the viewer is too small to view the fax, scrollbars are provided automatically.
The viewer has capabilities for scaling faxes, so you can implement features like zoom in
and out. It also provides the ability to rotate faxes, allowing you to adjust for faxes that are
sent upside down or sideways. The viewer can compress white space within the fax so that it
is more easily viewed. It allows drag and drop of fax files onto the viewer. And, you can
copy all or part of a fax to the Windows clipboard for use in other applications.
Scaling
The TApdFaxViewer component can scale (i.e., make the size larger or smaller) a fax that is
viewed. The fax is scaled only on the screen, not in the input file. This preserves the original
size of the fax, while making it more convenient to view. The scaling capabilities can also be
used to implement a Zoom In/Zoom Out feature of the sort found in many image viewer
and editing programs.
If Scaling is set to True (either when the fax is loaded or later), the image displayed on the
screen is immediately scaled to the new dimensions. The image is scaled depending on the
values of four properties. HorizMult and HorizDiv are combined to form a fraction
(HorizMult/HorizDiv) that is multiplied by the width (horizontal aspect) of the fax to
determine its new width. VertMult and VertDiv are combined to form a fraction
(VertMult/VertDiv) that is multiplied by the height (vertical aspect) of the fax to determine
its new height.
For example, assume a standard resolution fax (200x100) is being viewed. When the fax is
converted into a memory bitmap (which has an aspect ratio of 1:1) for viewing, the resulting
image looks shorter than it should (since, in the original, the height of the pixels was twice as
large as width of the pixels). To compensate for this, use the following:
ApdFaxViewer1.Scaling
ApdFaxViewer1.HorizMult
ApdFaxViewer1.HorizDiv
ApdFaxViewer1.VertMult
ApdFaxViewer1.VertDiv
:=
:=
:=
:=
:=
True;
1;
1;
2;
1;
7
8
9
10
11
12
13
14
15
This specifies that the viewed fax is scaled to be twice as tall (VertMult / VertDiv = 2/1 = 2)
as it normally would be. This makes the viewed standard resolution fax look normal.
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Because changes to the scaling properties cause an immediate repaint of the image displayed
on the screen, the above code would actually cause the screen image to be repainted up to
five times (and probably with some pretty weird effects). Therefore, when you are changing
the scaling properties, you should first turn off the immediate repaint of the display by
calling BeginUpdate. After you make all the necessary changes to the scaling properties, call
EndUpdate to repaint the screen. So a better version of the above code is as follows:
ApdFaxViewer1.BeginUpdate;
ApdFaxViewer1.Scaling
:=
ApdFaxViewer1.HorizMult :=
ApdFaxViewer1.HorizDiv :=
ApdFaxViewer1.VertMult :=
ApdFaxViewer1.VertDiv
:=
ApdFaxViewer1.EndUpdate;
Here is another way to deal with the problem of the standard resolution fax looking shorter
than it should:
ApdFaxViewer1.BeginUpdate;
ApdFaxViewer1.Scaling
:=
ApdFaxViewer1.HorizMult :=
ApdFaxViewer1.HorizDiv :=
ApdFaxViewer1.VertMult :=
ApdFaxViewer1.VertDiv
:=
ApdFaxViewer1.EndUpdate;
To make it easier to compensate for the aspect ratio of standard resolution faxes, the
AutoScaleMode property allows you to specify that the scaling should be performed
automatically. You can request either methoddoubling the height or halving the width.
The Scaling property can be used in many ways to produce a nearly unlimited range of
images. For instance, you can create an image that is 1/3 the size of the original fax with the
following code:
ApdFaxViewer1.BeginUpdate;
ApdFaxViewer1.Scaling
:=
ApdFaxViewer1.HorizMult :=
ApdFaxViewer1.HorizDiv :=
ApdFaxViewer1.VertMult :=
ApdFaxViewer1.VertDiv
:=
ApdFaxViewer1.EndUpdate;
True;
1;
2;
1;
1;
This specifies that the width of the fax is to be halved (HorizMult / HorizDiv = 1/2). This,
too, compensates for the difference in aspect ratio between a standard and high resolution
fax, but the resulting image is smaller than the one produced in the previous example.
17
True;
1;
1;
2;
1;
True;
1;
3;
1;
3;
Rotation
Occasionally a fax is received upside down or sideways, making it difficult to view on the
screen. To make it easier to deal with such faxes, the TApdFaxViewer can rotate the fax on
the screen.
By default, faxes are displayed as they were received (0 degree rotation). Faxes can be rotated
on the screen in 90 degree increments by setting the Rotation property. The TApdFaxViewer
updates the screen immediately to reflect the new setting.
The following example demonstrates the use of the Rotation property in viewing upside
down faxes:
procedure Form1.RotateBtnClick(Sender : TObject);
begin
ApdFaxViewer1.Rotation := vr180;
end;
2
3
4
6
7
8
9
To use the white space compression feature, set WhitespaceCompression to True. Every
occurrence of WhitespaceFrom or more consecutive blank lines is replaced with
WhiteSpaceTo blank lines. For example, if WhitespaceFrom is 20 and WhiteSpaceTo is 5,
then any occurrence of 20 or more consecutive blank lines is compressed down to 5 blank
lines.
10
The white space compression feature is active only when a fax is loaded into the viewer. If
you need to change the white space compression settings, you must change the appropriate
properties and then reload the fax from the file.
12
11
13
14
15
16
17
1
1
1
2
3
4
Your application can be notified of a dropped file if you implement an OnDropFile event
handler. When a file is dropped on the viewer and the viewer accepts the file, the
OnDropFile event is called. You can use this notification to update a status display or to
change viewer settings to reflect the new file.
When the mouse is clicked on a horizontal scrollbar arrow, the display is scrolled right or left
by HorizScroll pixels (the default is 8). Similarly, when the mouse is clicked on a vertical
scrollbar arrow, the display is scrolled up or down by VertScroll pixels (the default is 8).
When the mouse is clicked to the left or the right of the scroll thumb on a horizontal
scrollbar, the display is scrolled left or right by HorizScroll*10 pixels. Similarly, when the
mouse is clicked above or below the scroll thumb on a vertical scrollbar, the display is
scrolled up or down by VertScroll*10 pixels. The scroll thumb of a horizontal or vertical
scrollbar can also be dragged to scroll the display.
The TApdFaxViewer recognizes the keystrokes in Table 15.7 for navigation in viewed faxes.
Table 15.7: TApdFaxViewer recognized keystrokes
Key
Action
Up arrow
Down arrow
Ctrl+Up arrow
Ctrl+Down arrow
Left arrow
Right arrow
Ctrl+Left arrow
Ctrl+Right arrow
Home
17
652 Chapter 15: Fax Components
1
1
Key
Action
End
Ctrl+Home
Ctrl+End
PgDn
PgUp
Ctrl+PgDn
Ctrl+PgUp
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Example
The following example demonstrates the steps involved in viewing an APF file. Create a new
project, add the following components, and set the property values as indicated in
Table 15.8.
4
5
6
7
8
9
10
11
Component
Property
Value
TApdFaxViewer
Align
alClient
TOpenDialog
DefaultExt
APF
Filter
Click on the combo box at the top of the Object Inspector and select Form1. Next, click
Events tab at the bottom of the Object Inspector. From the events page, double-click the
OnCreate event. A shell for an OnCreate event is generated for you. Modify the generated
code to match this:
procedure TForm1.FormCreate(Sender : TObject);
begin
if OpenDialog1.Execute then
ApdFaxViewer1.FileName := OpenDialog1.FileName
else
Halt(1);
end;
This event prompts the user to enter the name of an APF file. If a file name is entered (i.e.,
Execute returns True), the file is opened in the viewer and displayed. If no file name is
entered, the program simply terminates.
12
13
14
15
16
17
654 Chapter 15: Fax Components
1
1
Hierarchy
TWinControl (VCL)
TApdCustomFaxViewer (AdFView)
TApdFaxViewer (AdFView)
Properties
AcceptDragged
HorizMult
Scaling
ActivePage
HorizScroll
VertDiv
AutoScaleMode
LoadWholeFax
VertMult
BGColor
NumPages
VertScroll
BusyCursor
PageBitmaps
WhitespaceCompression
FGColor
PageHeight
WhitespaceFrom
FileName
PageWidth
WhitespaceTo
HorizDiv
Rotation
6
7
8
Methods
BeginUpdate
FirstPage
PrevPage
CopyToClipboard
LastPage
SelectImage
EndUpdate
NextPage
SelectRegion
OnPageChange
OnViewerError
Events
OnDropFile
9
10
11
12
13
14
15
16
17
1
1
Reference Section
AcceptDragged
property
2
property AcceptDragged : Boolean
Default: True
! Determines whether files dropped onto the viewer are automatically loaded.
4
5
If AcceptDragged is True, the viewer allows APF files to be dragged and dropped on it. The
dropped file is automatically loaded into the viewer using the current scaling, white space
compression, and rotation settings.
See Drag and drop on page 651 for more information.
6
7
run-time property
8
9
10
11
12
13
14
15
16
17
656 Chapter 15: Fax Components
1
1
AutoScaleMode
property
Default: asDoubleHeight
Result
asNone
asDoubleHeight
asHalfWidth
10
method
11
procedure BeginUpdate;
12
13
14
15
16
17
1
1
1
2
3
4
5
The following example demonstrates the use of the BeginUpdate method by scaling a fax 2to-1:
procedure TForm1.ScaleImage2To1;
begin
ApdFaxViewer1.BeginUpdate;
ApdFaxViewer1.Scaling
:= True;
ApdFaxViewer1.HorizMult := 2;
ApdFaxViewer1.HorizDiv := 1;
ApdFaxViewer1.VertMult := 2;
ApdFaxViewer1.VertDiv
:= 1;
ApdFaxViewer1.EndUpdate;
end;
6
7
BGColor
property
Default: clWhite
8
9
10
BGColor changes the display color of white pixels. If BGColor is set to clBlue, the fax is
displayed with black text and images on a blue background.
11
12
BusyCursor
property
13
14
15
16
17
1
1
CopyToClipboard
method
procedure CopyToClipboard;
Fax images copied to the Windows clipboard are stored in cf_Bitmap format. A program
using the clipboard treats the fax data like a regular Windows bitmap image. For more
information about the clipboard, the cf_Bitmap format, and the SetClipboardData routine,
see the Windows API help file.
3
4
See Copying a fax to the clipboard on page 653 for more information.
See also: SelectImage, SelectRegion
EndUpdate
method
6
procedure EndUpdate;
! Indicates the end of an update of the viewers scaling properties and repaints the screen,
reflecting the new settings.
When one of the scaling properties (Scaling, HorizMult, HorizDiv, VertMult, or VertDiv) is
modified, the screen is repainted immediately. Since you will usually need to change more
than one scaling property, you can use BeginUpdate to temporarily turn off immediate
repainting. After you make all the necessary updates to the scaling properties, call
EndUpdate to repaint the display.
8
9
10
property
11
12
Default: clBlack
13
14
15
16
17
1
1
FileName
property
2
3
FileName should be a fully qualified file name. Unqualified file names are assumed to be in
the current directory, which changes frequently under Windows.
If LoadWholeFax is False, only the first page of the fax is loaded into memory and displayed.
If LoadWholeFax is True, the whole fax is loaded into memory and the first page of the fax is
displayed.
6
7
8
9
If FileName is set to an empty string, the currently loaded fax (if any) is discarded.
The following example demonstrates the use of the FileName property:
procedure Form1.OpenItemClick(Sender : TObject);
begin
if OpenDialog.Execute then
ApdFaxViewer1.FileName := OpenDialog.FileName;
end;
10
11
FirstPage
method
procedure FirstPage;
The TApdFaxViewer displays one page of the fax at a time. Calling FirstPage changes the
display to the first page in the fax.
13
If LoadWholeFax is False, calling this method causes the current page to be discarded and
the new page to be loaded into memory. This operation can take some time, depending on
the size of the page.
14
15
16
17
1
1
2
3
property
Default: 1
Attempts to set the value of HorizDiv to 0 are ignored. For a detailed explanation of scaling,
see Scaling on page 626.
property
8
9
Default: 1
10
Attempts to set the value of HorizMult to 0 are ignored. For a detailed explanation of scaling,
see Scaling on page 626.
11
property
12
13
Default: 8
! Determines the number of pixels that are scrolled during horizontal scrolling.
When the right or left arrow keys are pressed or the right or left arrows on the horizontal
scrollbar are clicked, the TApdFaxViewer scrolls the display to the left or right. HorizScroll
determines the number of pixels that are scrolled. The default HorizScroll is 8 pixels.
14
15
16
17
TApdFaxViewer Component 661
1
1
LastPage
method
procedure LastPage;
2
3
If LoadWholeFax is False, calling this method causes the current page to be discarded and
the new page to be loaded into memory. This operation can take some time, depending on
the size of the page.
6
7
8
9
LoadWholeFax
property
Default: False
10
11
12
Navigating through a fax is slower when LoadWholeFax is False, but it saves a considerable
amount of memory, especially if you are viewing large faxes.
13
14
15
16
17
662 Chapter 15: Fax Components
1
1
NextPage
method
procedure NextPage;
The TApdFaxViewer displays one page of the fax at a time. Calling NextPage changes the
display to the next page in the fax. If the current page is the last page in the fax, calling
NextPage has no effect.
If LoadWholeFax is False, calling this method causes the current page to be discarded and
the new page to be loaded into memory. This operation can take some time, depending on
the size of the page.
3
4
6
7
8
9
property NumPages : Integer
10
NumPages can be used as an upper limit when accessing the PageBitmaps property, or in a
status display (e.g., Viewing page 1 of 3).
11
The following example performs an operation on the bitmap for each page in the fax:
12
procedure Form1.ProcessPages;
var
I
: Integer;
Bmp : TBitmap;
13
begin
for I := 1 to ApdFaxViewer1.NumPages do begin
Bmp := ApdFaxViewer1.PageBitmaps[I];
...process the bitmap...
Bmp.Free;
end;
end;
14
15
16
17
TApdFaxViewer Component 663
1
1
OnDropFile
event
2
3
4
5
6
7
8
9
10
11
TViewerFileDropEvent = procedure(
Sender : TObject; FileName : string) of object;
! Defines an event handler that is called when a file is dropped on the viewer.
When a file is dropped onto a TApdFaxViewer and AcceptDragged is True, the file is loaded
into the viewer and the OnDropFile event is called. This notification is useful for updating
status displays or for viewing sessions in which the bitmaps for each page are being
manually processed and you need notification of changes in the viewer.
The following example demonstrates the use of the OnDropFile event:
procedure Form1.ApdFaxViewer1DropFile(
Sender : TObject; FileName : string);
var
I
: Integer;
Bmp : TBitmap;
begin
Label1.Caption := Format('Now viewing %s, page 1 of %d',
[FileName, ApdFaxViewer1.NumPages]);
{process bitmaps}
for I := 1 to ApdFaxViewer1.NumPages do begin
Bmp := ApdFaxViewer1.PageBitmaps[I];
...process bitmap for new fax...
Bmp.Free;
end;
end;
12
13
14
15
16
17
664 Chapter 15: Fax Components
1
1
OnPageChange
event
! Defines an event handler that is called when the active page changes.
The user of the TApdFaxViewer component can change pages by pressing the PgUp and
PgDn keys. When that happens, the TApdFaxViewer component notifies you that the active
page is changing by calling the OnPageChange event.
The following example updates a label on a form to display information about the current
page:
procedure TMainForm.ApdFaxViewer1PageChange(Sender : TObject);
begin
if (ApdFaxViewer1.FileName <> '') then
StatusPanel.Caption :=
Format(' Viewing page %d of %d in %s',
[ApdFaxViewer1.ActivePage, ApdFaxViewer1.NumPages,
ApdFaxViewer1.FileName])
else
StatusPanel.Caption := ' No file loaded';
end;
OnViewerError
event
3
4
6
7
8
9
10
11
12
ErrorCode contains the number of the error that occurred. It can be any of the ecXxx error
codes.
13
14
15
16
17
TApdFaxViewer Component 665
1
1
PageBitmaps
2
3
4
5
6
7
8
9
10
11
var
I
: Integer;
Bmp : TBitmap;
...
for I := 1 to ApdFaxViewer1.NumPages do begin
Bmp := ApdFaxViewer1.PageBitmaps[I];
...process the bitmap
Bmp.Free;
end;
12
13
14
15
16
17
666 Chapter 15: Fax Components
1
1
PageHeight
When selecting regions of faxes and processing page bitmaps, it is useful to know the
dimensions of the page currently being viewed. PageHeight is the height (in pixels) of the
current page. If no fax is currently loaded into the viewer, the value of PageHeight is 0.
The following example uses the PageHeight property to select the top half of a fax page:
var
R : TRect;
...
R.Top
:= 0;
R.Left
:= 0;
R.Bottom := (ApdFaxViewer1.PageHeight div 2) - 1;
R.Right := ApdFaxViewer1.PageWidth - 1;
ApdFaxViewer1.SelectRegion(R);
6
7
8
9
10
11
method
12
13
procedure PrevPage;
14
15
16
17
1
1
1
2
3
4
property
5
6
7
8
9
10
11
12
Default: vr0
Result
vr0
vr90
vr180
The fax is rotated 180 degrees to the right (i.e., turned upside
down).
vr270
The fax is rotated 270 degrees to the right (or 90 degrees to the
left, depending on your viewpoint).
By default, faxes are displayed as they were received (0 degree rotation, or vr0).
For more information see Rotation on page 651.
13
14
15
16
17
668 Chapter 15: Fax Components
1
1
Scaling
property
Default: False
3
4
When Scaling is changed, the display is changed immediately to reflect the new settings. If
you need to prevent this, the BeginUpdate and EndUpdate methods can be called to allow
all scaling settings to be set before the display is updated.
9
method
10
procedure SelectImage;
11
12
13
14
15
16
17
1
1
SelectRegion
method
SelectRegion selects a portion of the page being viewed. R specifies the rectangle that is to be
selected. When SelectRegion is called, the screen is immediately updated to reflect the
selection, causing the rectangle specified by R to be displayed in reverse video. The selection
can be copied to the Windows clipboard by calling CopyToClipboard. See Copying a fax to
the clipboard on page 653 for more information.
The following example selects a rectangle of 10 pixels by 10 pixels in the upper left corner of
the page:
6
7
8
9
var
R : TRect;
...
R.Top
:= 0;
R.Left
:= 0;
R.Bottom := 9;
R.Right := 9;
ApdFaxViewer1.SelectRegion(R);
10
11
12
Default: 1
13
14
15
16
17
670 Chapter 15: Fax Components
1
1
property
VertMult
property
Default: 1
property
Default: 8
! Determines the number of pixels that are scrolled during vertical scrolling.
When the up or down arrow keys are pressed or the up or down arrows on the vertical
scrollbar are clicked, the TApdFaxViewer scrolls the display up or down. VertScroll
determines the number of pixels that are scrolled. The default VertScroll is 8 pixels.
WhitespaceCompression
property
10
property WhitespaceCompression : Boolean
Default: False
11
12
If the viewer encounters WhitespaceFrom or more blank raster lines, they are replaced with
WhitespaceTo blank lines. For example, if WhitespaceFrom is 20 and WhitespaceTo is 5 and
the viewer encounters 100 blank lines, only 5 blank lines are displayed. The same thing
happens if only 20 blank lines are encountered. If, however, the viewer encounters 19 blank
lines, those lines are all displayed.
13
14
15
16
17
1
1
1
2
3
4
5
6
You can force the reload of a fax using the following code:
procedure Form1.ReloadFax;
var
SavePage : Cardinal;
SaveFile : string;
begin
SavePage := ApdFaxViewer1.ActivePage;
SaveFile := ApdFaxViewer1.FileName;
{discard the current fax}
ApdFaxViewer1.FileName := '';
{reload the fax}
ApdFaxViewer1.FileName := SaveFile;
ApdFaxViewer1.ActivePage := SavePage;
end;
7
8
WhitespaceFrom
property
Default: 0
! Specifies the number of consecutive blank lines that are compressed if white space
compression is enabled.
10
11
The value of WhitespaceFrom must be greater than the value of WhitespaceTo. If it is not, an
EBadArgument exception is raised when an attempt is made to load a fax file into the viewer.
12
13
14
15
16
17
672 Chapter 15: Fax Components
1
1
WhitespaceTo
property
Default: 0
! Specifies the number of blank lines that are substituted for every occurrence of
WhitespaceFrom or more consecutive blank lines.
The value of WhitespaceTo must be less than the value of WhitespaceFrom. If it is not, an
EBadArgument exception is raised when an attempt is made to load a fax file into the viewer.
See also: WhitespaceCompression, WhitespaceFrom
6
7
8
9
10
11
12
13
14
15
16
17
TApdFaxViewer Component 673
1
1
TApdFaxPrinter Component
The TApdFaxPrinter provides services for printing fax files to any Windows printer. Header
and Footer properties allow you to put text at the top or bottom of each page. You can scale
each fax page to fit on the requested paper size and you can print multiple fax pages on a
single sheet of paper.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
The TApdFaxPrinterStatus component provides a standard display for monitoring the print
progress, or you can use a status event handler to notify your program of status events. The
TApdFaxPrinterLog component provides automatic logging of the success or failure of a
print job, or you can intercept the log events with an event handler to provide your own
logging.
The Caption property supports replacement tags. A replacement tag is one of several
characters prefixed with $. When the header or footer is printed, the tags are replaced with
appropriate text. A header or footer can consist of any mix of tags and normal text (be
careful that your normal text doesnt happen to contain tags, though). The available
replacement tags are shown in Table 15.9.
Table 15.9: Replacement tags
Tag
Description
$D
$N
$P
$F
$T
17
674 Chapter 15: Fax Components
1
1
Note that some of the tags vary in length. For example, $P would be replaced by 1 for the
first page and 10 for the tenth page.
The default footer caption is:
1
2
This prints a footer on the first page of a six page fax as:
PAGE: 1 of 6
The Enabled property of headers and footers simply turns printing on or off. Enabled is
checked for each page printed to see if a header or footer should be printed. You can use the
OnNextPage event to turn the printing of headers and footers on and off on a page-by-page
basis. For example, you could print headers only on even-numbered pages and footers only
on odd-numbered pages.
The Font property is a TFont class and allows you to change the selected font. The default
font is MS Sans Serif.
No size adjustments are made in the header or footer for captions that are larger than the
page width. The header and footer text is printed exactly as specified in the Caption
property.
Scaling
When a fax is received or created, it is usually stored in the same size as the original
document. If you receive a fax that was originally on legal-sized paper, printing it on lettersized paper causes three inches of each page to overflow to the next page. If you set the
PrintScale property to psFitToPage, each page is scaled to fit on the requested paper size.
8
9
10
11
12
OnFaxPrintLog
procedure(Sender: TObject; FaxPLCode: TFaxPLCode) of object;
Generated at the start and end of each printed fax. This provides an opportunity to log the
status of each fax printed.
OnFaxPrintStatus
procedure(
Sender: TObject; StatusCode: TFaxPrintProgress) of object;
Generated at semi-regular intervals so that a program can display the progress of the
printing fax.
13
14
15
16
17
1
1
OnNextPage
procedure(Sender: TObject; CP, LP: Word) of object;
Generated at the start of each page. Programs can intercept this event to change the settings
of certain options on a per page basis.
4
5
Printing a fax file can take from several seconds to several minutes, depending on numerous
factors, including the size of the fax file and the number of pages to print. To allow you to
give the user an indication of the progress of the print session, the fax printer frequently
generates an OnFaxPrintStatus event.
The following example handles the OnFaxPrintStatus event:
6
7
8
9
10
11
12
13
TForm1 = class(TForm)
....
File : TLabel;
Page : TLabel;
Status: TLabel;
FP
: TApdFaxPrinter;
...
end;
procedure TForm1.ApdFaxPrintStatus(
Sender : TObject; StatusCode : TFaxPrintProgress);
const
ProgressSt: array[TFaxPrintProgress] of string[10] =
('Idle', 'Converting', 'Composing',
'Rendering', 'Submitting');
begin
File.Caption := FP.FileName;
Status.Caption := ProgressSt[StatusCode];
Page.Caption := IntToStr(FP.CurrentPrintingPage);
end;
14
15
16
17
676 Chapter 15: Fax Components
1
1
It is often desirable to automate the printing of faxes. For example, a fax server might send
and receive faxes during the night and automatically print received faxes at designated
times. In this case it would be nice to keep a record of the faxes that were successfully printed
and those that werent. The printer logging feature provides the opportunity to log
information about each printed fax.
To support logging, the fax printer generates an OnFaxPrintLog event at the start and end of
each fax printed. The event passes a parameter that identifies the current log action. The
following is an example of a simple log event:
procedure TForm1.ApdFaxPrintLog(
Sender : TObject; FaxPLCode : TFaxPLCode);
begin
case FaxPLCode of
lcStart :
CurrentFile.Caption := ApdFaxPrinter1.FileName;
lcFinish:
PrintOK.Items.Add(ApdFaxPrinter1.FileName);
lcAborted:
PrintAborted.Items.Add(ApdFaxPrinter1.FileName);
lcFailed:
PrintFailed.Items.Add(ApdFaxPrinter1.FileName);
end;
end;
This example shows every possible log value. It uses a TLabel component named
CurrentFile to display the current file being printed and updates one of three TListBox
components with the final status of the print session.
The printer logging routine is not limited to just writing status information. It can also be
used to take care of cleanup duties after a fax is printed. For example, you could conserve
disk space by automatically archiving a received fax after it is printed.
A supplied component can do automatic print logging for you. If you create an instance of a
TApdFaxPrinterLog and assign it to FaxPrinterLog, logging is done automatically. For each
OnFaxPrintLog event, the fax printer calls the UpdateLog method of TApdFaxPrinterLog to
write the information to the log file. It then calls the OnFaxPrintLog event.
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Example
This example shows how to construct and use a fax printer component. Create a new
project, add the following components, and set the property values as indicated in Table
15.10.
Property
Value
Caption
Select File
Name
FileNameButton
Caption
Name
PrintButton
Caption
File Name
Name
fnLabel
Name
FileNameEdit
TApdFaxPrinter
TApdFaxPrinterStatus
TOpenDialog
TButton
6
TButton
7
8
9
10
11
12
13
14
15
16
TLabel
TEdit
Double click on the FileNameEdits OnChange event handler within the Object Inspector
and modify the generated method to match the following code:
procedure TForm1.FileNameEditChange(Sender : TObject);
begin
ApdFaxPrinter1.FileName := FileNameEdit.Text;
end;
This event handler updates the name of the file to be printed whenever the text in the edit
control changes.
Double click on the FileNameButtons OnClick event handler and modify the generated
method to match the following code:
procedure TForm1.FileNameButtonClick(Sender : TObject);
begin
OpenDialog1.Filter := 'APF Files (*.APF)|*.APF';
if OpenDialog1.Execute then
FileNameEdit.Text := OpenDialog1.FileName;
end;
17
678 Chapter 15: Fax Components
1
1
This event handler updates the file name edit box with the selected file from the OpenDialog
call.
Double click on the PrintButtons OnClick event handler and change the generated method
to match the following code:
This tells the TApdFaxPrinter to begin printing the fax file specified by the FileName.
3
4
Compile and run the example. Click Select File to select the fax file to print.
This example is in the EXFPRN1 project in the \ASYNCPRO\EXAMPLES directory.
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomFaxPrinter (AdFaxPrn)
TApdFaxPrinter (AdFaxPrn)
Properties
Caption
FaxWidth
PrintScale
CurrentPrintingPage
FileName
StatusDisplay
FaxFooter
FirstPageToPrint
TotalFaxPages
FaxHeader
LastPageToPrint
FaxPrinterLog
MultiPage
FaxResolution
PrintProgress
! Version
10
11
12
13
Methods
PrintAbort
PrintFax
PrintSetup
15
Events
OnFaxPrintLog
14
OnFaxPrintStatus
OnNextPage
16
17
1
1
Reference Section
Caption
property
2
property Caption : string
! Used by Windows in the Print Manager and for network title pages.
4
5
6
Each document submitted to the Windows Print Manager has an associated name to
identify it in the print queue. Caption allows you to specify the name.
CurrentPrintingPage
As each page is printed, CurrentPrintingPage is updated to reflect the current page number
in the fax.
FaxFooter
property FaxFooter : TApdFaxPrinterMargin
TApdFaxPrinterMargin = class(TApdCustomFaxPrinterMargin)
published
property Caption;
property Enabled;
property Font;
end;
16
17
680 Chapter 15: Fax Components
1
1
property
FaxHeader
property
TApdFaxPrinterMargin = class(TApdCustomFaxPrinterMargin)
published
property Caption;
property Enabled;
property Font;
end;
3
4
6
7
8
property
9
10
11
If you create an instance of (or a descendant of) a TApdFaxPrinterLog (see page 695) and
assign it to FaxPrinterLog, logging is done automatically.
12
13
14
15
16
17
TApdFaxPrinter Component 681
1
1
FaxResolution
Default: frNormal
3
4
5
6
7
8
9
10
Default: fwNormal
property
11
12
13
14
15
16
17
682 Chapter 15: Fax Components
1
1
FirstPageToPrint
run-time property
FirstPageToPrint specifies the first page to print in the fax specified by FileName. This is
usually set by the PrintSetup method by selecting the starting and ending pages to print.
run-time property
property
6
7
8
Default: False
! Determines the number of fax pages that are printed on each printed page.
If MultiPage is False (the default), each fax page is printed on one printed page.
If MultiPage is True, multiple fax pages are printed on each printed page. If printing is in
Portrait mode, 4 fax pages are printed on each printed page. If printing is in Landscape
mode, 2 fax pages are printed on each printed page.
Any value of PrintScale can be used with MultiPage.
9
10
11
12
13
14
15
16
17
TApdFaxPrinter Component 683
1
1
OnFaxPrintLog
event
TFaxPLEvent = procedure(
Sender : TObject; FaxPLCode : TFaxPLCode) of object;
! Defines an event handler that is called at designated points during a fax printing session.
4
Sender is the fax printer component to be logged. FaxPLCode indicates the state of the print
job. The possible states are:
6
7
8
9
10
11
12
13
14
15
State
Meaning
lcStart
Printing started.
lcFinish
lcAborted
lcFailed
Printing failed.
No other information is passed with the event. You can use fax printer status properties such
as FileName and CurrentPrintingPage to get additional information about the print job.
See Fax printer logging on page 677 for more information.
See also: FaxPrinterLog
OnFaxPrintStatus
property OnFaxPrintStatus : TFaxPrintStatusEvent
TFaxPrintStatusEvent = procedure(
Sender : TObject; StatusCode : TFaxPrintProgress) of object;
TFaxPrintProgress = (
ppIdle, ppConverting, ppComposing, ppRendering, ppSubmitting);
16
17
684 Chapter 15: Fax Components
1
1
event
Sender is the fax printer component that is in progress. StatusCode indicates the status of the
print job. The possible values are:
Value
Meaning
ppIdle
Nothing is happening.
ppConverting
ppComposing
ppRendering
ppSubmitting
1
2
3
4
No other information is passed with the event. You can use fax printer status properties such
as FileName and CurrentPrintingPage to get additional information about the print job.
See also: StatusDisplay
OnNextPage
6
event
This event is generated for each page in the fax before it is printed. You can use OnNextPage,
for example, to abort the printing of a fax by calling PrintAbort.
CP is the current page number of the fax that is printing. TP is the total number of pages to
be printed.
10
11
method
procedure PrintAbort;
12
13
14
15
16
17
TApdFaxPrinter Component 685
1
1
PrintFax
method
procedure PrintFax;
PrintFax prints the fax specified by FileName. It is usually called after PrintSetup is called to
select the printer and the range of pages to print. Printing can be aborted by calling
PrintAbort.
PrintProgress
6
7
8
9
10
11
TFaxPrintProgress = (
ppIdle, ppConverting, ppComposing, ppRendering, ppSubmitting);
Meaning
ppIdle
Nothing is happening.
ppConverting
ppComposing
ppRendering
ppSubmitting
12
13
14
15
16
17
686 Chapter 15: Fax Components
1
1
PrintScale
property
Default: psFitToPage
PrintSetup
method
procedure PrintSetup;
property
8
9
10
11
12
13
14
15
16
17
1
1
TotalFaxPages
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
688 Chapter 15: Fax Components
1
1
TApdAbstractFaxPrinterStatus Class
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdAbstractFaxPrinterStatus (AdFaxPrn)
3
4
5
6
Properties
Display
CreateDisplay
8
9
10
11
12
13
14
15
16
17
690 Chapter 15: Fax Components
! Version
Methods
FaxPrinter
DestroyDisplay
UpdateDisplay
Reference Section
CreateDisplay
2
procedure CreateDisplay; virtual; abstract;
CreateDisplay must then assign the instance of this form to the Display property.
See also: DestroyDisplay, Display
DestroyDisplay
run-time property
10
11
12
13
FaxPrinter
14
15
16
17
1
1
UpdateDisplay
method
2
3
4
5
For all other calls to UpdateDisplay, First and Last both equal False. During these calls,
UpdateDisplay must update the various labels in the Display form. To get information about
the fax printing status, read the values of the various fax printer properties (use FaxPrinter
to find the fax printer) such as FileName and CurrentPrintingPage.
The AbortClick event handler, if provided, should call the PrintAbort method of
TApdFaxPrinter to terminate fax printing.
9
10
11
12
13
14
15
16
17
692 Chapter 15: Fax Components
1
1
TApdFaxPrinterStatus Component
7
8
9
10
11
12
Figure 15.1: TStandardFaxPrintStatusDisplay form.
13
14
15
16
17
1
1
Hierarchy
TComponent (VCL)
2
3
TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomFaxPrinterStatus (AdFaxPrn)
TApdFaxPrinterStatus (AdFaxPrn)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
694 Chapter 15: Fax Components
1
1
TApdFaxPrinterLog Component
3
4
Hierarchy
6
7
8
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomFaxPrinterLog (AdFaxPrn)
10
TApdFaxPrinterLog (AdFaxPrn)
11
Properties
FaxPrinter
LogFileName
! Version
Methods
12
13
UpdateLog
14
15
16
17
TApdFaxPrinterLog Component 695
1
1
Reference Section
FaxPrinter
2
3
4
5
6
7
8
9
10
12
Default: FAXPRINT.LOG
! Determines the name of the file used to store the fax printer log.
You should set the value of LogFileName before calling the PrintFax method of
TApdFaxPrinter. However, because the log file is opened and closed for each update, you
can change LogFileName at any time. If you set LogFileName to an empty string, automatic
logging is disabled until you assign a non-empty string.
See also: TApdFaxPrinter.PrintFax
UpdateLog
13
14
15
16
17
696 Chapter 15: Fax Components
1
1
property
11
property
method
UpdateLog creates or appends to the log file, builds and writes a text string for each event,
and closes the log file. LogCode can have the following values:
Value
Meaning
lcStart
Printing started.
lcFinish
lcAborted
lcFailed
Printing failed.
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdFaxPrinterLog Component 697
1
1
Async Professional provides components that support send and receive services for Class 1,
Class 1.0, Class 2, and Class 2.0 faxmodems. These faxmodems all provide similar
capabilities. All can connect to any other Group 3 fax device, they use the same image
transmission format, and all are capable of transferring data at the same speeds. The
differences between them are in the area of how the PC fax software interacts with the
faxmodem. When using a Class 1 or Class 1.0 faxmodem, the communication between the
PC and the modem is at a fairly low level. They exchange information and commands
through HDLC (High-level Data Link Control) packets instead of Hayes-type AT
sequences. The fax software is also responsible for negotiating the faxmodem-to-faxmodem
data transfer rate by sending and receiving training sequences.
3
4
5
6
7
8
9
10
11
12
13
When using a Class 2 or Class 2.0 faxmodem, the communication between the PC and the
modem is based on an extended set of Hayes-type AT commands and text responses. The
faxmodem itself negotiates the faxmodem-to-faxmodem data transfer rate and reports the
results back to the PC.
Because all faxmodems are used in such a similar fashion, they are supported with a single
set of components. In general, you dont need to be concerned with the class of the
faxmodem is attached to the systems that your software supports. You call the same
functions in either case.
14
15
16
17
Phase
Description
Phase A
Dial
Phase B
Pre-message
Phase C
Message
Phase D
Post-message
Phase E
Hang-up
1
1
The phase name is the term used by the TIA/EIA specification for each activity. Phase A is
associated with dialing the phone number or preparing the modem to receive a call. The
sender and receiver negotiate the parameters of the fax connection during Phase B. The
actual fax image (the message) is transferred during Phase C. During Phase D, the sender
and receiver decide whether a page must be resent, or whether more pages follow. During
Phase E, the modem disconnects from the phone line in preparation for the next call.
All phases from A through E are processed in order unless an error occurs. An OnFaxError
event can be generated in any phase. If a fax session is in progress, the OnFaxError event is
followed by an OnFaxLog event.
Class 1/1.0 and Class 2/2.0 modems differ only in their processing of Phase B and Phase D.
With Class 1/1.0 modems, the terminal software handles these two phases by transmitting
and receiving HDLC packets. With Class 2/2.0 modems, the terminal sends an AT
sequence and waits for the modem to return a text response.
1
2
3
4
Phase A: Dial
The first step in Phase A is to initialize the modem for sending or receiving faxes.
TApdSendFax continues Phase A by generating an OnFaxNext event to get the phone
number and fax file name. If a fax is queued for sending, it dials the fax recipients phone
number.
Phase B: Pre-message
Phase B starts as soon as the call is answered. The major task of Phase B is for the modems to
agree on a set of capabilities to use while transferring the fax. The modems exchange their
capabilities, then perform an iterative training procedure to find the fastest transmission
parameters that are reliable.
7
8
9
10
During training, the sender starts at the fastest modulation rate that the receiver supports. It
sends a known sequence of bytes, which the receiver attempts to read. If the receiver gets the
right pattern, it informs the sender and the transfer moves on to Phase C. If the pattern is
incorrect, the receiver informs the sender and the sender determines whether to retry at the
same rate or to step down to the next lower modulation rate. The process is then repeated.
Generally a reduction in transfer rate is required because the telephone line is too noisy. If
no available modulation rate succeeds, the connection is terminated.
11
14
12
13
15
16
17
1
1
1
2
3
4
5
6
7
8
9
Phase C: Message
During Phase C, TApdSendFax sends page image data to the faxmodem, which transmits it
to the receiving faxmodem. The receiving faxmodem sends it on to the receiver software.
During this process, the sender must honor flow control, because the transmitting
faxmodem could impose flow control to temporarily stop the data flow. The faxmodem
releases flow control when it wants to resume.
Software or hardware flow control must also be enabled at the modem. When you use TAPI
or the AWMODEM.INI database, the appropriate type of flow control is automatically
enabled. Otherwise, you must ensure that flow control is enabled at the modem.
While in Phase C, the TApdSendFax component must continuously send data to the
faxmodem, except when it is blocked by flow control. Any break in the stream generates a
data underflow error. What happens after a data underflow depends on the faxmodem,
but in most cases the fax session cannot be continued.
To avoid data underflow, the TApdComPort component must use a port baud rate that is
higher than (not just equal to) the fax bit per second transfer rate. In almost all cases this
should be 19200 baud. Theres no benefit to using higher baud rates and at least one of the
modems we tested works only at 19200.
Another possible cause of data underflow is an ill-behaved Windows 3.X program that
doesnt yield CPU time or thread starvation caused by a Win32 program that raises its
thread priority too high for too long. The best way to avoid this is to use a relatively large
TApdComPort output buffer (for example, 16384 bytes).
10
OnFaxStatus events are generated regularly during Phase C. By default they are generated
once every second (you can change the frequency by setting the StatusInterval property).
11
Phase D: Post-message
12
13
14
15
At the end of Phase C the transmitter sends an end-of-page sequence, which marks the start
of Phase D. The receiver then tells the transmitter whether or not the page was received
successfully. If it was not, the two modems can negotiate a retransfer. If it was, the
transmitter tells the receiver whether any additional pages are coming.
If there are more pages, the process can loop back to either the middle of Phase B (to retrain
the connection) or the beginning of Phase C (to keep the existing connection parameters).
The receiving modem decides which approach to use. Async Professionals receive routines
loop to the beginning of Phase C. Other software packages and fax machines can choose
either approach.
16
17
700 Chapter 15: Fax Components
1
1
Phase E: Hang-up
Phase E disconnects or hangs up the modem, terminating the fax call. When transmitting
faxes, the input file is closed and an OnFaxLog event is generated to indicate the end of this
fax. TApdSendFax then loops back to Phase A to see whether another fax should be sent.
When receiving faxes, the output file is closed and an OnFaxLog event is generated.
TApdReceiveFax then waits for another incoming call unless the OneFax property is True. If
there are no more faxes to send or receive, an OnFaxFinish event is generated.
1
2
3
4
OnFaxStatus
Generated approximately once per second during the entire fax session so that programs
can display the progress of the session. See OnFaxStatus on page 729. Also see Fax
status on page 707.
7
8
OnFaxLog
procedure(CP : TObject; LogCode : TFaxLogCode) of object;
Generated at the start and end of each fax call. This provides the opportunity to log the
status of the fax transfer. See OnFaxLog on page 729. Also see Fax logging on page 712.
9
10
OnFaxError
procedure(CP : TObject; ErrorCode : Integer) of object;
Generated when an unrecoverable error occurs. Recoverable errors do not generate this
message because they are an expected part of fax transfers and, when possible, the failed
operation is retried automatically. See the OnFaxError event on page 728. Also see Error
handling on page 705.
OnFaxFinish
procedure(CP : TObject; ErrorCode : Integer) of object;
Generated after all faxes have been transmitted or received or after the fax session terminates
due to an unrecoverable error. This event also sends the final result code of the fax session.
See the OnFaxFinish event on page 728.
11
12
13
14
15
16
17
1
1
2
3
4
5
6
ApdComPort1.DataBits := 8;
ApdComPort1.StopBits := 1;
ApdComPort1.Parity := pNone;
ApdComPort1.Baud := 19200;
ApdComPort1.InSize := 8192;
ApdComPort1.OutSize := 8192;
ApdComPort1.HWFlowOptions := [hwfUseRTS, hwfRequireCTS];
Databits, Stopbits, and Parity must be set to 8,1,none since that is the proper setting for
binary data transfer. Fax devices dont use parity checking.
Baud must be set to 19200 for a couple of reasons. First, the fax software must continuously
transmit data to the faxmodem, so that it can continuously transmit data to the receiving fax
device. A pause in a fax data stream is considered by the fax device to be a fatal error and
usually results in an immediate abort of the fax session, or an abort at the end of the current
page.
9
10
11
12
Because the highest fax bps rate is 14400 bits per second, a comport baud rate slightly higher
than that, 19200, is sufficient to assure that short pauses in the data stream from the software
do not result in pauses between the fax devices.
A baud rate higher than 19200 isnt necessary since the fax bps rate will never be greater than
14400. Selecting a baud rate higher that 19200 does little to improve pause tolerance but
increases the possibility of line errors.
13
The second reason for forcing the baud rate to 19200 is that a few older faxmodems require
that baud rate and wont operate at any other baud rate.
14
InSize is the size, in bytes, of the comport components communication input buffer. Its
forced to 8192 from the default 4096 to increase the fax softwares tolerance of ill-behaved
programs that dont yield often or that increase their thread priority for too long.
15
16
17
702 Chapter 15: Fax Components
1
1
OutSize is the size, in bytes, of the comport components communication output buffer. Its
forced to 8192 from the default 4096 to better protect against data underflows. The fax
component keeps the output buffer as full as possible. If the fax application is kept from
running due to an ill-behaved program, the Windows communication driver continues to
transmit the buffered data. As long as the fax application is allowed to run again before the
output buffer drains, no data underflows occur.
HWFlowOptions is one of the TApdComPort properties (the other is SWFlowOptions) that
determines what type of flow control, if any, is used by the comport component. The
faxmodem specifications dictate that all faxmodems support software flow control.
Faxmodems can optionally support hardware flow control, and most do. Because hardware
flow control is more reliable than software flow control, and because both the Async
Professional modem database and the Win32 TAPI modem database force hardware flow
control on by default, hardware flow control is forced on in the TApdComPort.
Flow control is a critical issue for fax sessions and it must be properly enabled, both in fax
application software and in the faxmodem, for reliable fax operation. Assuring hardware
flow control is enabled in the software is only half the battleyou must also assure that
hardware flow control is enabled at the faxmodem.
Fortunately, this is easy to do, although it isnt as automatic as the enabling of flow control
within the TApdComPort component. Fax applications must do one of the following:
1. Use TAPI to initialize the modem.
1
2
3
4
6
7
8
9
2. Use the TAdModem and modemcap database components to initialize the modem.
3. Manually send the appropriate modem commands to enable hardware flow control.
10
Number 1 is the preferred choice if it is available. The TAPI modem database is far more
extensive than the Async Professional database. 32-bit Windows users expect your program
to use TAPI rather than direct serial port access.
11
Number 2 is the preferred choice when TAPI isnt available. Although its possible that the
exact modem model isnt in the modemcap database, choosing the closest match from the
same manufacturer is usually sufficient to assure that the modem is properly configured.
Number 3 is the most difficult approach since you must figure out the appropriate modem
commands to send to the modem to enable hardware flow control. Use it only when neither
TAPI or modemcap are available.
12
13
14
15
16
17
1
1
TAPI/Fax Integration
TAPI provides several features that supplement faxing. The most obvious is that TAPI
permits selection of the modem by name instead of by port number. TAPI also preconfigures the modem to a state where APRO can re-initialize it for faxing. When sending a
fax, TAPI can apply the dialing options to the phone number, for example to automatically
add a 9 for an outside line. When receiving a fax, TAPI can passively monitor the line for
incoming calls, which allows other processes to access the port.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TAPI integration with the faxing components is determined by the TapiDevice property of
the TApdAbstractFax component (and the TApdSendFax and TApdReceiveFax
descendents). If TapiDevice is not assigned, TAPI integration will not be used. If TapiDevice
is assigned, that device will be used to select and configure the modem, provide phone
number translations, and passively answer calls.
The level of TAPI integration depends on whether a fax is being sent or received. When the
StartTransmit method of the TApdSendFax component is called, and the TapiDevice
property is assigned, the ConfigAndOpen method of the TapiDevice will be called. Internal
OnTapiXxx event handlers will be assigned to monitor the progress of the TapiDevice.
When TAPI configures the modem and opens the port, the PhoneNumber property will be
translated using the TranslateAddress method of the TapiDevice, and that translated
number will be dialed. From there, the fax will be sent in the usual manner. Once the
OnFaxFinish event is generated, the CancelCall method of the TapiDevice will be called to
close the port.
When the StartReceive method of the TApdReceiveFax component is called, and the
TapiDevice property is assigned, the AnswerOnRings property of the TapiDevice will be set
to 100 to prevent TAPI from answering the call, and the AutoAnswer method of TapiDevice
will be called. When TAPI detects AnswerOnRings ring signals, the TapiDevice will cancel
itself, and the TApdReceiveFax will answer the call. When the OnFaxFinish event is
generated, the CancelCall method of the TapiDevice will be called to close the port.
When the TapiDevice property is assigned, the event handlers of the TApdTapiDevice will
be generated as usual. These events will be generated from within the internal OnTapiXxx
event handler that the faxing components will assign. Any additional processing that your
project does within these events must be complete before your projects OnTapiXxx events
return.
To maintain backwards compatibility with previous versions of APRO that did not provide
TAPI and fax integration, set the TapiDevice property to nil.
One benefit of TAPI integration is that you can now send a fax with the TApdSendFax
component while a TApdReceiveFax component is waiting for faxes. To implement this, the
TApdSendFax component must have a TApdComPort and TApdTapiDevice component
1
1
assigned, and the TApdReceiveFax component must have a different TApdComPort and
TApdTapiDevice component assigned. The SelectedDevice property of both
TApdTapiDevice components can point to the same TAPI device. Call the StartReceive
method of the TApdReceiveFax component to begin passively answering calls. When ready
to transmit a fax, check the InProgress property of the TApdReceiveFax to make sure a fax is
not being actively received. If InProgress is False, then it is safe to call the StartTransmit
method of the TApdSendFax. When the fax has been sent, the TApdReceiveFax will still be
in passive answer mode.
1
2
3
4
6
7
8
9
10
11
12
Error handling
All fax transfers are subject to errors like line errors, file not found errors, and other file I/O
errors. The fax components handle errors internally by retrying the operation or requesting
the remote fax device to retry. If, however, the situation is unrecoverable, an OnFaxError
event is generated. Your application should include an handler for this event. Following is a
simple example:
procedure Form1.ApdSendFax1FaxError(
CP : TObject; ErrorCode : Integer);
begin
ShowMessage('Fatal fax error: ' + ErrorMsg(ErrorCode));
end;
13
14
15
16
17
1
1
1
2
This event handlers sole task is to display a message about the error. ErrorMsg is a function
from the AdExcept unit that returns an English string for any Async Professional error code.
See Error Handling and Exception Classes on page 900 for additional information about
errors. Table 15.12 contains an annotated list of error codes that apply to fax calls.
Table 15.12: Fax call error codes
Error Code
Meaning
ecFaxBadMachine
ecFaxBadModemResult
ecFaxBusy
ecFaxDataCall
ecFaxInitError
ecFaxNoCarrier
ecFaxNoDialTone
ecFaxNoFontFile
ecFaxPageError
4
5
6
7
8
9
10
11
12
13
14
15
16
17
706 Chapter 15: Fax Components
1
1
Error Code
Meaning
ecFaxSessionError
ecFaxTrainError
ecFaxVoiceCall
2
3
4
Fax status
A fax session can last a few seconds or several hours, depending on the size and speed of the
transfer. The fax session proceeds in the background without intervention from your
program. To inform you of whats happening as the transfer progresses, Async Professional
provides an event for regular notification of the progress.
During a fax session, an OnFaxStatus event is generated regularly (the default is once per
second). This gives your application the opportunity to monitor and display the progress of
the transfer. The following code fragments show how to monitor the progress.
TForm = class(TForm)
...
FN : TLabel;
PG : TLabel;
BT : TLabel;
...
end;
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
procedure TForm1.ApdSendFax1FaxStatus(
CP : TObject; First, Last : Boolean);
begin
if First then
...do setup stuff
else if Last then
...do cleanup stuff
else begin
{Show status}
FN.Caption := ApdSendFax1.FaxFile;
PG.Caption := ApdSendFax1.CurrentPage;
BT.Caption := ApdSendFax1.BytesTransferred;
end;
end;
14
CurrentPage: The number of the current page. CurrentPage is zero when transmitting a
cover page, one for the first page, two for the second page, and so on.
15
ElapsedTime: The elapsed time (in milliseconds) since the remote station ID was received.
An indicator of the elapsed time for the current fax call.
16
17
708 Chapter 15: Fax Components
1
1
FaxProgress: A code indicating the current state of the fax call. The Table 15.3 shows all of
the possible values. The usual states are fpSendPage and fpGetPage, which mean the fax
session is sending or receiving page data. Other status values indicate various start-up and
handshaking states. Fatal errors are not represented by fax states because they are first
reported via the OnFaxError event. However, it is possible that a final status message might
be sent after a fatal error occurs.
1
2
3
Status Code
Transmit
/Receive
Value
Explanation
fpInitModem
fpDialing
fpBusyWait
fpSendPage
6
7
8
9
10
11
fpSendPageStatus
fpPageError
14
12
13
fpPageOK
15
fpWaiting
20
16
17
1
1
Transmit
/Receive
Value
Explanation
fpNoConnect
21
fpAnswer
22
fpIncoming
23
fpGetPage
24
fpGetPageResult
25
fpCheckMorePages
26
fpGetHangup
27
12
fpGotHangup
28
13
fpSessionParams
T/R
40
5
6
7
8
9
10
11
14
15
16
17
710 Chapter 15: Fax Components
1
1
Status Code
Transmit
/Receive
Value
Explanation
fpGotRemoteID
T/R
41
fpCancel
T/R
42
fpFinished
43
2
3
4
FaxError: The code of the fatal error encountered in the fax session. See the error codes in
Error handling on page 705 for more information.
HangupCode: The hangup code returned by a class 2 or class 2.0 faxmodem. The hangup
code can sometimes provide additional error information for failed fax sessions.
8
9
10
PageLength: The length in bytes of the page currently being transmitted. When a fax is
being received, PageLength is zero.
11
RemoteID: The 20 character identification string returned by the remote fax device.
SessionBPS: The negotiated bps rate (bytes per second) for the current fax session.
SessionResolution: The negotiated resolution (standard or high) for the current fax session.
12
13
SessionWidth: The negotiated width (1728 or 2048 pixels) for the current fax session.
SessionECM: Indicates whether the current fax session is using error control.
14
TotalPages: The total number of pages to be transmitted. When a fax is being received,
TotalPages is zero.
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
Fax logging
Its often important to have a log of all incoming and outgoing activity on a particular fax
machine. You can use the log for billing purposes, to recover the station ID or image of a fax
whose printout was lost, or to determine which faxes were not successfully sent during an
automated transfer.
The fax logging event provides a mechanism for your program to keep an activity log.
Although the logging event is similar to the status event, it is not generated as frequently. The
status event is generated for at least 20 different send and receive states, and it is also
generated once per second during the transfer of page data. The logging event is generated
once at the beginning and once at the end of each transfer.
13
14
15
16
17
712 Chapter 15: Fax Components
1
1
The LogCode parameter is of an enumerated type that indicates the condition at the time
the logging routine is called. The TLogFaxCode values are described in Table 15.14.
Table 15.14: TLogFaxCode values
1
2
Value
Explanation
lfaxTransmitStart
lfaxTransmitOk
lfaxTransmitFail
lfaxReceiveStart
lfaxReceiveOk
lfaxReceiveSkip
lfaxReceiveFail
This example shows the logging values that could be received during a fax receive session.
The example uses a TLabel control named CurrentFile to display the name of the current fax
file. As faxes are received this method updates three TListBox components: GoodList for all
successful transfers, BadList for all failed transfers, and a SkipList of RemoteIDs for all
skipped files.
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
The logging routine isnt limited to just writing logging information. It can also take care of
file-related startup and cleanup activities. One example of this might be to delete outgoing
fax files (if successfully transmitted, of course) or moving them from the current directory
to a has been sent directory.
Async Professional includes a mechanism for providing automatic fax logging without
programming, through the FaxLog property of TApdAbstractFax:
property FaxLog : TApdFaxLog
The TApdFaxLog class is described in more detail on page 828. For each OnFaxLog event,
the fax component checks whether FaxLog is assigned. If it is, the fax calls the UpdateLog
method of TApdFaxLog to write information to the log file. It then calls the OnFaxLog
event, if one is implemented.
When a fax component is created, either dynamically or when dropped on a form, it
searches the form for a TApdFaxLog component and updates the FaxLog property with the
first one it finds. FaxLog is also filled in if a TApdFaxLog component is added to the form
later. You can also change FaxLog at design time or run time to point to a different
TApdFaxLog.
9
10
11
12
13
14
15
16
17
714 Chapter 15: Fax Components
1
1
TApdAbstractFax Component
The fax send and receive components (TApdSendFax and TApdReceiveFax) are derived
from TApdAbstractFax.This abstract fax component provides the set of properties,
methods, and events that are common to both sending and receiving, such as the Station ID
of the sender or receiver, and the status of the current fax session. TApdAbstractFax also
defines the events that allow you to log fax calls, generate files names for incoming faxes, and
report status during transmission.
If you already know how to use file transfer protocols within the Async Professional
architecture, fax transfers will seem very familiar. Just like a file transfer, a fax transfer
involves a initializing a comport component, initializing a fax component, and calling a
method to start the background fax session. The events for fax transfer are quite similar, and
in some cases identical, to those for file transfer.
There are a few differences, though, and these differences are inherent to the nature of faxes.
Unlike most file transfer protocols, where the name and size of the file are transmitted
before the files contents are sent, a fax receiver isnt given a filename in which to store an
incoming fax, and it doesnt know the size of the fax until the transmission terminates. The
fax protocol also provides no means for the receiver to detect errors in the incoming data, or
to request retransmission in the event of bad data. Fortunately, the compression technique
used for fax data is relatively tolerant of errors. Because of these differences, your program
must take on certain responsibilities that are not required when using file transfer protocols,
such as providing names for incoming faxes and being prepared for out-of-disk-space
errors when receiving faxes.
Note that certain properties that are described in the following reference section are specific
to either sending or receiving faxes, or behave differently when sending or receiving faxes.
These differences are described in the reference section of affected properties.
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomAbstractFax (AdFax)
3
4
5
6
7
8
9
10
11
12
13
14
TApdAbstractFax (AdFax)
Properties
AbortNoConnect
HangupCode
SessionECM
BytesTransferred
InitBaud
SessionResolution
ComPort
InProgress
SessionWidth
CurrentPage
ModemBPS
SoftwareFlow
DesiredBPS
ModemChip
StationID
DesiredECM
ModemECM
StatusDisplay
ElapsedTime
ModemInit
StatusInterval
ExitOnError
ModemModel
SupportedFaxClasses
FaxClass
ModemRevision
TapiDevice
FaxFile
NormalBaud
TotalPages
FaxFileExt
PageLength
FaxLog
RemoteID
FaxProgress
SessionBPS
Methods
CancelFax
ConvertToLowRes
ConvertToHighRes
StatusMsg
Events
OnFaxError
OnFaxLog
OnFaxFinish
OnFaxStatus
15
16
17
716 Chapter 15: Fax Components
1
1
! Version
Reference Section
AbortNoConnect
property
2
property AbortNoConnect : Boolean
Default: False
Defines what happens when the connection to a fax number cannot be made after the
default number of retries.
If AbortNoConnect is True, the background fax process ends and generates an OnFaxFinish
event, even if additional faxes are queued to be sent. If AbortNoConnect is False, the
background fax process moves on to the next fax to be sent, as specified by the OnFaxNext
event handler.
6
BytesTransferred
! The number of bytes received or transmitted so far for the current page.
BytesTransferred can be used by an OnFaxStatus event handler to get the number of bytes
received or transferred so far. The appropriate time to check BytesTransferred is when
FaxProgress equals fpSendPage or fpGetPage. At other times, it is either zero or a value
associated with the previous page.
9
10
method
11
procedure CancelFax;
12
CancelFax cancels the fax session, regardless of its current state. When appropriate, a cancel
command is sent to the local modem or the remote fax device. The fax component generates
an OnFaxFinish event with the error code ecCancelRequested, then cleans up and
terminates. It also attempts to put the faxmodem back onhook (i.e., ready for the next
call).
13
14
15
16
17
1
1
1
2
3
The following example shows how to cancel a fax from a fax status dialog:
procedure TStandardDisplay.CancelClick(Sender : TObject);
begin
ApdSendFax1.CancelFax;
end;
property
4
property ComPort : TApdCustomComPort
5
6
7
8
9
10
11
These values are essential for proper and reliable fax operation and should be changed only
if you are certain of the impact of your changes. See Fax sessions and the TApdComPort
on page 702 for more information.
ConvertToHighRes
method
12
procedure ConvertToHighRes(const FileName : string);
13
14
15
16
17
718 Chapter 15: Fax Components
1
1
ConvertToLowRes
method
ConvertToLowRes converts an existing APF fax file into low resolution. If the APF contains
multiple pages, ConvertToLowRes converts all pages to low resolution. Each fax page is
converted to a bitmap, converted back to a single low resolution pages APF in the Windows
temp folder, and then all pages are concatenated to recreate the original APF. If the page is
already low resolution, and exception is not raised.
3
4
7
8
9
property
10
11
Default: 9600
! Determines the highest fax bps rate to negotiate for the next fax session.
DesiredBPS limits the fax bps rate for subsequent fax sessions. Although many faxmodems
support higher bps rates (12000 and 14400), DesiredBPS defaults to 9600 for more reliable
fax sessions and higher quality faxes because the slightly lower baud rate makes lines errors
less likely.
Changing DesiredBPS during a fax session has no effect on the current session.
12
13
14
15
16
17
TApdAbstractFax Component 719
1
1
DesiredECM
property
Default: False
The fax protocol contains an optional error control facility that allows modems to detect
and correct some transmission errors. Since very few faxmodems support fax error control,
DesiredECM defaults to False, meaning the faxmodems do not attempt to negotiate error
control.
See also: ModemECM, SessionECM
ElapsedTime
6
property ElapsedTime : DWORD
ElapsedTime is the number of milliseconds that have elapsed since fax call has started. The
fax call, in this context, is considered started when the remote station ID has been received.
This will usually be less than a second or two after the call is actually answered.
ExitOnError
10
11
Default: False
! Determines what happens when an error occurs during a fax transmit or receive.
12
13
14
15
16
17
720 Chapter 15: Fax Components
1
1
property
FaxClass
property
TFaxClass = (
fcUnknown, fcDetect, fcClass1, fcClass1_0, fcClass2, fcClass2_0);
Default: fcDetect
Indicates whether the faxmodem is used as Class 1, Class 1_0, Class 2, or Class 2.0.
If FaxClass is fcDetect (the default), TApdAbstractFax determines what classes the modem
supports and enables the highest class. If you set FaxClass to a specific class, no attempt is
made to determine if the class you request is supported by the faxmodem.
property
6
7
8
9
10
11
FaxFileExt
property
12
Default: APF
13
14
15
See Naming incoming fax files on page 754 for more information.
16
17
TApdAbstractFax Component 721
1
1
FaxLog
property
2
3
If you create an instance of (or a descendant of) a TApdFaxLog class (see page 828), and
assign it to FaxLog, the fax component will call the log components UpdateLog method
automatically.
FaxProgress
! Returns a code that indicates the current state of the fax session.
This property is most useful within an OnFaxStatus event handler. See Fax status on
page 707 for more information.
9
property HangupCode : Word
10
11
12
13
14
Description
15
16
00
01
02
03
No loop current
17
722 Chapter 15: Fax Components
1
1
Hangup Code
Description
04
05
Transmit phase A
10
11
No answer
1
2
3
Transmit phase B
20
21
22
23
24
RSPREC error
25
26
27
28
40
41
42
43
44
45
46
47
6
7
Transmit phase C
10
11
12
Transmit phase D
13
50
51
RSPREC error
52
53
54
55
56
57
14
15
16
17
TApdAbstractFax Component 723
1
1
1
2
3
4
5
6
7
8
9
10
Hangup Code
Description
58
Receive phase B
70
71
RSPREC error
72
COMREC error
73
74
Receive phase C
90
91
92
93
Receive phase D
100
101
102
103
InitBaud
property
11
12
13
14
15
Default: 0
! Determines the initialization baud rate for modems that require different baud rates for
initialization and fax operations.
Some older 24/96 faxmodems (2400 data, 9600 fax), require that the initialization
commands be sent at 2400 baud, but that all fax commands and fax data be sent and
received at 19200. The fax software must constantly adjust the current baud rate depending
on the operation it is performing.
Since most faxmodems do not require a special initialization baud rate, InitBaud defaults to
zero, which means that no baud rate switches are performed. If you encounter an older
modem that requires this behavior, set InitBaud to 2400.
16
17
724 Chapter 15: Fax Components
1
1
1
2
3
4
property InProgress : Boolean
ModemBPS
9
10
11
The technique used by ModemBPS works on most Class 2 and 2.0 faxmodems. One
low-cost, no-name-clone faxmodem tested wouldnt return ERROR no matter what it was
asked to do, even though it supported only 9600 bps with no error correction.
12
13
14
15
16
17
TApdAbstractFax Component 725
1
1
ModemChip
When you reference ModemChip, commands are sent to the modem to determine the type
of chip. This works only for Class 2 and 2.0 modems. ModemChip is an empty string for a
Class 1/1.0 modem.
ModemECM
6
7
8
9
10
11
12
13
14
15
16
17
726 Chapter 15: Fax Components
1
1
property
ModemModel
When ModemModel is referenced, commands are sent to the modem to determine the
model. This works only for Class 2 and 2.0 modems. ModemModel is an empty string for a
Class 1 modem.
ModemRevision
When ModemRevision is referenced, commands are sent to the modem to determine the
revision. This works only for Class 2 and 2.0 modems. ModemRevision is an empty string
for a Class 1/1.0 modem.
NormalBaud
property
9
property NormalBaud : Integer
Default: 0
10
! Determines the normal baud to use for modems that require different baud rates for
initialization and fax operations.
11
NormalBaud isnt needed unless the faxmodem requires separate baud rates for
initialization commands and the baud rate required for normal fax operations is not 19200.
See InitBaud for a complete description of the operation of InitBaud and NormalBaud.
12
13
14
15
16
17
TApdAbstractFax Component 727
1
1
OnFaxError
event
2
3
TFaxErrorEvent = procedure(
CP : TObject; ErrorCode : Integer) of object;
! Defines an event handler that is called when an unrecoverable fax error occurs.
This event is generated only for unrecoverable errors. Most fax errors caused by line noise
are handled automatically by the fax devices and are not reported to this event handler.
CP is the fax component that generated the error. ErrorCode is a number indicating the type
of error. See Error handling on page 705 for a list of the error codes.
The OnFaxFinish event is generated soon after the OnFaxError event and passes the same
error code. The OnFaxFinish event is generated for both successful and failed transfers, so
you may want to use it instead of an OnFaxError handler.
8
9
10
11
12
13
Its important to note that a fax session may consist of more than one fax call. For example, if
you implement an OnFaxNext event to send several faxes with one call to StartTransmit, all
of those faxes are considered to be in the same fax session.
14
This handler could be used to display a completion dialog box (needed only if a fax status
event handler is not used) or to allow scheduling another fax transfer.
The following example displays a message when a fax session finishes:
15
16
procedure TForm1.ApdSendFax1FaxFinish(
CP : TObject; ErrorCode : Integer);
begin
ShowMessage('Fax finished: ' + ErrorMsg(ErrorCode));
end;
17
728 Chapter 15: Fax Components
1
1
event
OnFaxLog
event
3
4
! Defines an event handler that is called at designated points during a fax transfer.
The primary purpose of this event is to allow the logging of statistical information about fax
transfers. For example, the transfer time and whether the transfer succeeded or failed could
be logged. This event could also be used for startup and cleanup activities.
CP is the fax component to be logged. LogCode is a code that indicates the state of the fax
transfer. The possible states are listed in Fax logging on page 712. No other information is
passed with this event, but the fax status properties, such as FaxFile and PhoneNumber, can
be used to get additional information about the fax session.
See also: FaxLog
6
7
8
OnFaxStatus
event
9
property OnFaxStatus : TFaxStatusEvent
TFaxStatusEvent = procedure(
CP : TObject; First, Last : Boolean) of object;
10
11
12
13
14
15
17
16
1
1
PageLength
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
730 Chapter 15: Fax Components
1
1
SessionECM
SessionECM is True if automatic error correction is enabled for this transfer, or False if it
isnt. Error correction is enabled if both modems support it and DesiredECM is True.
SessionECM can be used by an OnFaxStatus event handler to check for automatic error
correction. The appropriate time to check SessionECM is when FaxProgress equals
fpSessionParams. Before that, it is undefined.
Session parameters can change more than once during a single session. Be sure that your
OnFaxStatus event handler updates its parameter display each time FaxProgress returns the
value fpSessionParams.
See also: DesiredECM, SessionBPS, SessionResolution, SessionWidth
SessionResolution
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdAbstractFax Component 731
1
1
SessionWidth
Default: True
If SessionWidth is True (the default), the fax is a standard width of 1728 pixels (about 8.5
inches). If SessionWidth is False, the fax width is 2048 pixels (about 10 inches).
SessionWidth can be used by an OnFaxStatus event handler to check the fax width. The
appropriate time to check SessionWidth is when FaxProgress equals fpSessionParams.
Before that, it is undefined.
Session parameters can change more than once during a single session. Be sure that your
OnFaxStatus event handler updates its parameter display each time FaxProgress returns the
value fpSessionParams.
property
8
property SoftwareFlow : Boolean
Default: False
! Determines whether the fax components enable or disable software flow control during the
10
fax session.
11
When using software flow control during a fax session, the flow control must be enabled and
disabled at various points in the session. Because hardware flow control is more reliable, it is
used by default and the fax components do not enable or disable software flow control. If
you need to use software flow control, you must set SoftwareFlow to True.
12
13
For more information regarding flow control see Fax sessions and the TApdComPort on
page 702.
14
15
16
17
732 Chapter 15: Fax Components
1
1
StationID
property
TStationID = string[20];
3
4
6
7
8
9
property
10
11
12
If you create an instance of a class derived from TApdAbstractFaxStatus or use the supplied
TApdFaxStatus component (see page 826) and assign it to StatusDisplay, the status window
is displayed and updated automatically.
13
14
15
16
17
TApdAbstractFax Component 733
1
1
StatusInterval
property
Default: 1
The OnFaxStatus event is generated for each major fax session event (connected, got station
ID, and so on) and at intervals of StatusInterval seconds.
This property also determines how frequently the StatusDisplay window is updated.
See also: OnFaxStatus, StatusDisplay
StatusMsg
6
7
method
This routine is intended primarily for use in fax status routines. It returns a status string
from the string table resource linked into your EXE. The string ID numbers correspond to
the values of the fpXxx constants (see Fax status on page 707). If the string table doesnt
contain a string resource with the requested ID, an empty string is returned.
10
SupportedFaxClasses
11
12
TFaxClass = (
fcUnknown, fcDetect, fcClass1, fcClass1_0, fcClass2, fcClass2_0);
16
Generally, applications should use the highest supported class: fcClass2_0, then fcClass2,
and finally fcClass1.
17
1
1
TapiDevice
property
This refers to a TAPI device that we may create internally when sending or receiving faxes.
We check for an Assigned TapiDevice and will use it if there is an ApdTapiDevice on the
form. EnableVoice property should be false by default and left that way.
TotalPages
TotalPages is valid only when you are sending a fax. When receiving a fax, the total number
of pages is not known in advance, so TotalPages is zero.
TotalPages can be used by an OnFaxStatus event handler to get the total number of bytes
in the current page. The appropriate time to check TotalPages is when FaxProgress equals
fpSendPage or fpGetPage. Before that, it is either zero or a value associated with the
previous page.
See also: BytesTransferred, CurrentPage, PageLength
7
8
9
10
11
12
13
14
15
16
17
1
1
TApdSendFax Component
A fax to send consists of three items: an APF file (or list of APF files), a phone number, and
an optional cover file. TApdSendFax provides a few mechanisms for specifying this
information. When sending only one fax the simplest approach is to set the FaxFile,
PhoneNumber, and CoverFile properties, then call StartTransmit. TApdSendFax dials the
specified number, transmits the fax, and generates an OnFaxFinish event to indicate that it is
finished.
When you need to send multiple fax files to the same location, you can fill the FaxFileList
property (a stringlist) with the names of the files, set the PhoneNumber and CoverFile
properties, then call StartTransmit. TApdSendFax concatenates the APF files into a single
temporary APF, dials the specified number, transmits the fax, deletes the temporary APF,
and generates an OnFaxFinish event to indicate that it is finished.
If you need to send a single fax file to multiple locations, you can use the OnFaxNext event to
specify the files and phone numbers. If an OnFaxNext event handler is specified,
TApdSendFax calls it instead of using FaxFile/FaxFileList, PhoneNumber, and CoverFile.
The event handler is expected to return the fax file, phone number, and cover file of the next
fax to send. If there are no more fax files to send, the event handler should return empty
strings. The following code fragments illustrate how:
TForm1 = class(TForm)
...
private
FaxList : TStringList;
FaxIndex : Word;
end;
...
15
16
17
736 Chapter 15: Fax Components
1
1
1
2
3
procedure TForm1.ApdSendFax1FaxNext(
CP : TObject; var APhoneNumber, AFaxFile,
AcoverFile : OpenString);
var
S : string;
CaretPos : Byte;
begin
try
S := FaxList[FaxIndex];
CaretPos := Pos('^', S);
APhoneNumber := Copy(S, 1, CaretPos-1);
AFaxFile := Copy(S, CaretPos+1, 255);
ACoverFile := '';
Inc(FaxIndex);
except
APhoneNumber := '';
AFaxFile := '';
ACoverFile := '';
end;
end;
6
7
8
9
10
This example sends two fax files to two different locations: it sends FILE1.APF to the fax
device at 260-7151 and sends FILE2.APF to 555-1212. No cover files are used.
When AddFilesClick is called (presumably from clicking the Add Files button), the two fax
files and phone numbers are added to a TStringList named FaxList. FaxIndex, which is used
to keep track of which fax file to send, is initialized to zero.
When TApdSendFax generates the OnFaxNext event, ApdSendFax1NextFax uses the next
string from FaxList to extract the fax file name and phone number, returning them in the
APhoneNumber and AFaxFile parameters. When there are no more faxes to send, FaxList
generates an EListError exception. The except block then sets the passed parameters to
empty strings, which tells TApdSendFax that there are no more faxes to send. An
OnFaxFinish event is fired at the end of the fax session (after all faxes have been sent).
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
Cover pages
Fax transmissions often include a cover page, which provides basic information about the
fax, usually consisting of the senders name, the recipients name, the total number of pages,
and perhaps the date and time. Async Professional provides several options for sending this
information. First, you can avoid a cover page altogether and put the same information on a
fax page header. See the HeaderLine property on page 748 for details.
If you want to send a cover page, you have three options. First, you can build the cover page
right into the main APF file for the document. This option applies to text documents only.
Simply store the cover page text at the beginning of the document, insert a form feed
character, and continue with the document itself. Then use the TApdFaxConverter
component to generate the APF file.
Second, you can create a separate APF file that contains the cover page. Take this approach if
the cover page contains special graphics or text that doesnt change between fax
transmissions. Create the APF file and set the CoverFile property of TApdSendFax to the
fully qualified name of the file or return the fully qualified file name in the ACoverFile
parameter of the OnFaxNext event.
The third and most flexible approach is to put the cover page in a separate text file. If the
cover file name does not have an extension of APF, it is assumed to be a text file.
TApdSendFax automatically converts this to fax format (using either the built-in standard
font or a Windows font) and transmits it to the remote machine.
What makes this approach more flexible is the fact that the text file can use replacement tags.
A replacement tag is one of several characters prefixed with $. As each line of the cover file
is converted, the tags are replaced with appropriate text. A line in the cover file can consist of
any mix of tags and normal text (be careful that your normal text doesnt happen to contain
tags, though). Blank lines and spaces can be used to format the cover page. The available
replacement tags are shown in Table 15.15.
Table 15.15: Available Replacement Tags
13
14
15
Tag
Description
$D
$I
$N
$P
$R
16
17
738 Chapter 15: Fax Components
1
1
Tag
Description
$F
$S
$T
Note that some of the tags vary in length. For example, $P would be replaced by 1 for the
first page and 10 for the tenth page.
2
3
4
By taking advantage of replacement tags, you can create a single cover page file that is used
for every fax transfer. Below is a sample cover file and sample code that sets the replacement
tags:
COVER.TXT:
DATE
TIME
FROM
TO
:
:
:
:
$D
$T
$F
$R
8
9
(form feed)
10
Program:
11
ApdSendFax.HeaderSender := 'Picabo';
ApdSendFax.HeaderRecipient := 'Elizabeth';
ApdSendFax.FaxFile := 'FILE1.APF';
ApdSendFax.CoverFile := 'COVER.TXT');
ApdSendFax.PhoneNumber := '260-7151';
ApdSendFax.StartTransmit;
12
The file FILE1.APF is sent to 260-7151 using the cover page file COVER.TXT. The date and
time tags are replaced with the current date and time. The senders name is set to Picabo
and the recipients name is set to Elizabeth.
13
14
15
16
17
1
1
2
3
4
5
procedure(
CP : TObject; var APhoneNumber : string; var AFaxFile : string;
var ACoverFile : string) of object;
Generated when it is time to transmit a fax (just after StartTransmit is called and after each
fax is sent). When transmitting multiple faxes, your program must implement an
OnFaxNext event handler to return, in sequence, each fax file to send. See EXFAXL for an
example that shows how to use a TStringList component to maintain a list of fax file names
and phone numbers.
" Caution: An OnFaxFinish event will not be fired until after empty strings are returned in
6
7
your OnFaxNext event to signal the end of the fax session (all faxes have been sent).
Example
This example shows how to construct and use a fax send component. This example includes
a TApdFaxStatus component (see page 826) so that you can see the progress of the fax
session.
Create a new project, add the following components, and set the property values as
indicated in Table 15.16.
10
11
12
13
14
15
TApdComPort
TApdSendFax
Property
ComNumber
OutSize
8192
FaxFile
PhoneNumber
Name
Send
TApdFaxStatus
TButton
The output buffer size of the comport component (the OutSize property of TApdComPort)
is raised from its default value of 4096 to 8192. TApdSendFax requires an output buffer of at
least 8192 bytes to ensure there is always enough room to add the next raster line to send,
plus keep the output buffer full enough to avoid data underflow errors.
16
17
740 Chapter 15: Fax Components
1
1
Value
Double-click on the Send buttons OnClick event handler within the Object Inspector and
modify the generated method to match this:
procedure TForm1.SendClick(Sender : TObject);
begin
ApdSendFax1.StartTransmit;
end;
1
2
This method starts a background fax transmit session, which dials the specified fax phone
number and attempts to send the specified fax file.
The form includes a TApdFaxStatus component, which is automatically displayed by the fax
and periodically updated to show the progress of the fax transfer.
3
4
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomAbstractFax (AdFax)
" TApdAbstractFax (AdFax) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715
TApdCustomSendFax (AdFax)
TApdSendFax (AdFax)
10
Properties
" AbortNoConnect
BlindDial
BufferMinimum
DialRetryWait
DialWait
" ElapsedTime
" HangupCode
HeaderLine
HeaderRecipient
" BytesTransferred
EnhFont
HeaderSender
" ComPort
EnhHeaderFont
HeaderTitle
CoverFile
EnhTextEnabled
" InitBaud
" CurrentPage
" ExitOnError
" DesiredBPS
" FaxClass
" ModemBPS
" DesiredECM
" FaxFile
" ModemChip
Detect Busy
" FaxFileExt
" ModemECM
DialAttempt
FaxFileList
MaxSendCount
" ModemInit
DialAttempts
" FaxLog
" ModemModel
DialPrefix
" FaxProgress
" ModemRevision
11
12
13
14
15
16
17
1
1
" NormalBaud
NoSoftwareFlow
" PageLength
PhoneNumber
" RemoteID
SafeMode
" SessionBPS
4
5
" CancelFax
" OnFaxError
8
9
10
11
12
13
14
15
16
17
742 Chapter 15: Fax Components
" SupportedFaxClasses
" SessionWidth
ToneDial
" SoftwareFlow
" TotalPages
" StationID
! Version
" StatusDisplay
" StatusInterval
ConvertCover
StartManualTransmit
StartTransmit
" StatusMsg
Events
" OnFaxFinish
" StatusMsg
" SessionResolution
Methods
ConcatFaxes
" SessionECM
" OnFaxLog
OnFaxNext
" OnFaxStatus
Reference Section
BlindDial
property
2
property BlindDial : Boolean
Default: False
Allows a fax to be sent regardless of whether the modem detects a dial tone.
If BlindDial is True, a different initialization sequence is sent to the modem before a fax is
sent (ATX3 is sent instead of ATX4). This initialization sequence allows the modem to use a
phone line, even if it cant detect a dial tone.
BufferMinimum
property
Default: 1000
Defines the minimum number of bytes that must be in the output buffer before
TApdSendFax yields control.
Once started, a fax transmit session must have a constant supply of data to transmit. Lack of
data to transmit is referred to as a data underflow condition and usually results in a failed fax
session. Because Windows is a multi-tasking environment, TApdSendFax tries to fill the
output buffer as full as possible before yielding control. BufferMinimum is the minimum
number of output bytes that must be in the output buffer before TApdSendFax yields.
If your program is operating among ill-behaved programs or other conditions that might
result in long periods where it isnt given a chance to run, increasing BufferMinimum
decreases the chance of a data underflow error.
9
10
11
12
13
14
15
16
17
TApdSendFax Component 743
1
1
ConcatFaxes
method
2
3
4
5
This method can be useful if you need to send a concatenated fax to multiple phone
numbers (using the OnFaxNext event) or if you want to retain the concatenated fax
following the transmission.
ConvertCover
method
9
10
11
12
13
property
If you are sending a single fax with a cover sheet, set CoverFile to the name of the text or APF
file to be used as the cover sheet. If you are sending multiple fax files, you must implement an
OnFaxNext event handler. CoverFile is automatically set to the cover file name returned by
your event handler.
16
17
744 Chapter 15: Fax Components
1
1
If the extension of the cover file is APF, the file is assumed to be an APF file and is
transmitted as-is, before FaxFile is transmitted. Otherwise the cover file is assumed to be a
text file. Each text line is read from the file, replacement tags are replaced with appropriate
text, and the line is converted to a series of raster lines and transmitted to the remote fax.
After the cover file is converted and transmitted, the FaxFile is transmitted.
1
2
CoverFile can be used by status and logging routines to return the name of the current
cover file.
property
If DetectOnBusy is True, the busy signal is detected if the receiving fax is already off hook.
An ErrorCode of ecFaxBusy will be passed in the OnFaxError event. If False, a different
initialization sequence is sent to the modem before a fax is sent (ATX2 is sent instead of
ATX4). This initialization sequence disables the modems capability to detect a busy signal.
8
9
! Indicates the number of times the current fax number has been dialed.
If the dialed fax number is busy, TApdSendFax waits briefly and calls the number again. It
tries up to DialAttempts times. The DialAttempt property returns the number of the current
attempt. DialAttempt is incremented immediately upon encountering a busy line.
10
11
12
13
14
15
16
17
TApdSendFax Component 745
1
1
DialAttempts
property
Default: 3
This is the number of times a fax session is attempted, it is not the number of retries. When
DialAttempts is one, for example, the fax number is dialed only once. If the line is busy, it is
not tried again. When DialAttempts is three, the fax number is dialed a maximum of three
times.
See also: DialAttempt, DialRetryWait
DialPrefix
property
6
property DialPrefix : TModemString
TModemString = string[40];
DialPrefix specifies an optional dial prefix that is inserted in the dial command between
ATDT and the number to dial. If your telephone system requires special numbers or codes
when dialing out, you can specify them once here rather than in every fax number.
Do not include ATD or a T or P tone/pulse modifier in the dial prefix. ATD is
automatically prefixed by StartTransmit and the T or P is controlled by ToneDial.
See also: ToneDial
11
12
DialRetryWait
property
Default: 60
13
14
15
16
! The number of seconds to wait after a busy signal before trying the number again.
After encountering a busy signal, TApdSendFax checks to see if it should try this number
again by comparing DialAttempts to DialAttempt. If more attempts are required, it first
waits DialRetryWait seconds before dialing again to give the dialed fax machine time to
complete the current session.
If no more dialing attempts are required, TApdSendFax does not wait, but immediately
progresses to the next state, which is logging the current fax session as failed.
See also: DialAttempt, DialAttempts
17
746 Chapter 15: Fax Components
1
1
DialWait
property
Default: 60
! The number of seconds to wait for a connection after dialing the number.
This property determines how many seconds to wait after dialing the receivers phone
number. If the receiver does not answer within this time, the OnFaxFinish event will fire and
return an error code of ecFaxNoAnswer.
3
4
property
8
9
10
property
11
12
13
14
15
16
17
TApdSendFax Component 747
1
1
EnhTextEnabled
property
Default: False
The converter makes no attempt to keep all text on the page when the size of the font is
changed. You must ensure that the cover page line length and document length fit on the
page in the desired font.
FaxFileList
property
8
9
10
11
12
13
HeaderLine
property
! The optional line of text that is sent at the top of each fax page.
14
15
A header line consists of normal text and replacement tags. A replacement tag is one of
several characters prefixed with $. When the header line is transmitted, the tags are
replaced with appropriate text. The available replacement tags are listed in Cover pages on
page 738.
16
17
748 Chapter 15: Fax Components
1
1
No check is made to make sure your header line fits on a page. If your header line does not
fit, it is truncated when it is transmitted. Using the default fonts, you can fit approximately
144 characters on a standard width page. If EnhTextEnabled is True, you will have to
experiment to see how many characters fit on the width of the page.
"
Caution: Recently passed United States legislation makes it unlawful to send faxes within the
United States without showing certain sender information on the fax. The new requirement
states, in part: It shall be unlawful for any person within the United States to use any
computer or other electronic device to send any message via facsimile machine unless such
message clearly contains, in a margin at the top or bottom of each transmitted page or on the
first page of the transmission, the date and time it is sent and an identification of the
business, other entity, or individual sending the message and the telephone number of the
sending machine of such business, other entity, or individual.
See also: EnhHeaderFont, EnhTextEnabled, HeaderRecipient, HeaderSender, HeaderTitle
HeaderRecipient
1
2
3
4
property
This string replaces the $R replacement tag in a cover page text file or a header line.
See Cover pages on page 738 for more information and examples.
See also: HeaderLine, HeaderSender, HeaderTitle
HeaderSender
property
10
11
12
13
14
15
16
17
TApdSendFax Component 749
1
1
HeaderTitle
property
3
4
See Cover pages on page 738 for more information and examples.
See also: HeaderLine, HeaderRecipient, HeaderSender
MaxSendCount
5
6
7
8
9
Default: 50
10
The default values for BufferMinimum and MaxSendCount provide the best combination of
cooperative multitasking and avoidance of data underflow. You should not alter these values
unless fax sessions are failing due to data underflow errors.
11
12
13
14
15
16
17
750 Chapter 15: Fax Components
1
1
property
OnFaxNext
event
! Defines an event handler that returns the phone number, fax file, and cover file for the
next fax.
If no handler is installed for this event, TApdSendFax dials the number specified by
the PhoneNumber property and sends the fax(es) specified in the FaxFile or
FaxFileList property. If the OnFaxNext event handler is installed, that event will be
generated once the faxmodem has been initialized. The PhoneNumber, FaxFile and
FaxFileList properties are ignored.
CP is the fax component that is transmitting. The event handler should return the next
number to dial in APhoneNumber, the next fax file to send in AFaxFile, and an optional
cover file name in ACoverFile. If a cover file isnt used, ACoverFile should be set to an
empty string.
The event handler should return empty strings for APhoneNumber, AFaxFile, and
ACoverFile when there are no more faxes to send.
2
3
4
6
7
8
9
An OnFaxFinish event will be fired at the end of the fax session (all faxes have been sent
and you have returned empty strings in your OnFaxNext handler to signal the end of the
session).
10
11
12
13
14
15
16
17
TApdSendFax Component 751
1
1
PhoneNumber
property
2
3
If the phone system requires prefix codes (like 9), the codes must be specified in
PhoneNumber or in DialPrefix.
PhoneNumber can be used with status and logging routines to return the phone number
dialed for the current fax session.
property
7
property SafeMode : Boolean
Default: True
At the beginning and end of every fax page, TApdSendFax performs time-critical
handshaking with the receiving fax device, where tolerance for delays is very low. Delays as
small as a few hundred milliseconds can cause the receiver to believe the page transfer failed.
When SafeMode is True (the default), TApdSendFax does not yield during these periods.
While this is the safest possible mode of operation for TApdSendFax, it will result in
apparent brief periods of unresponsiveness to the user. That is, they wont be able to switch
to another application or cancel the fax transfer until the critical handshaking is over.
Fortunately, the time-critical period lasts only 1-3 seconds, so this should rarely be a
problem.
StartManualTransmit
procedure TApdSendFax.StartManualTransmit;
17
752 Chapter 15: Fax Components
1
1
method
StartTransmit
method
procedure StartTransmit;
3. Set PhoneNumber and FaxFile or provide an OnFaxNext event handler to return this
information.
4. Write other event handlers for fax events.
5. Call StartTransmit.
StartTransmit returns immediately and transmits fax files in the background, occasionally
generating events to keep you apprised of the progress. When the fax is finished, either
successfully or with a fatal error, it generates an OnFaxFinish event.
The TAPI/Fax integration with receiving faxes will wait for incoming faxes using a passive
answering mode. If TapiDevice is assigned, the associated TApdTapiDevice will be placed in
AutoAnswer mode. When AnswerOnRing ring signals are detected, the TApdReceiveFax
will answer the call. What this means for you is that you can be waiting for incoming faxes
then go ahead and send a fax over the same device. After the fax is finished sending, TAPI
will go back to passively waiting for an incoming fax.
7
8
9
10
property
11
12
Default: True
13
14
15
16
17
1
1
TApdReceiveFax Component
The OnFaxAccept event gives your program the opportunity to accept or reject an incoming
fax. The OnFaxAccept event is generated as soon as TApdReceiveFax establishes a fax
session and determines the station ID of the sender.
There arent many reasons to refuse an incoming fax, but there might be some that are
important to your application. For example, if your automated fax receive system knows that
there is not enough disk space to hold even a small incoming fax, you can save the senders
money by refusing the fax instead of accepting part of it and failing later.
Another possibility is to reject junk faxes automatically. You could maintain a list of
known-good station IDs whose faxes you always accept, or a list of known-bad station IDs
whose faxes you always reject.
If you dont implement an OnFaxAccept event then all faxes are accepted.
The following event handler accepts faxes only from station ID 719-260-7151:
procedure TForm1.ApdReceiveFax1FaxAccept(
CP : TObject; var Accept : Boolean);
begin
Accept := ApdReceiveFax1.RemoteID = '719-260-7151';
end;
12
13
When a fax is received, a file name must be chosen for storing the incoming image. Unlike a
file transfer protocol, the fax sender does not provide any name.
14
TApdReceiveFax provides two methods for generating fax file names. The FaxNameMode
property specifies how the name should be automatically generated. The OnFaxName event
gives your program the opportunity to return a file name.
15
16
17
754 Chapter 15: Fax Components
1
1
Option
Result
fnNone
fnMonthDay
fnCount
For both fnMonthDay and fnCount, the time required to find a usable file name depends on
the number of existing files with the same name format. The time is probably not an issue as
long as there are fewer than 100 matching files. If more than 9999 files are received, the name
NONAME.APF is used.
To avoid the delay of finding the next available file name or if to use a different algorithm for
naming the fax files, write an event handler for the OnFaxName event. This event is
generated by TApdReceiveFax during a fax session as soon as the incoming fax is accepted in
the OnFaxAccept event.
The following event handler generates sequence numbers internally rather than scanning
the output directory to obtain a sequence number:
const
LastNumber : Word = 0;
2
3
4
6
7
8
9
10
procedure TForm1.ApdReceiveFax1FaxName(
CP : TObject; var Name : OpenString);
begin
if LastNumber < 10000 then begin
Inc(LastNumber);
Str(LastNumber, Name);
while Length(Name) < 4 do
Name := '0'+Name;
Name := 'FAX'+Name+'.'+ApdReceiveFax1.FaxFileExt;
end else
Name := 'NONAME.APF';
end;
This example keeps track of sequence numbers internally, using the typed constant
LastNumber. Of course, this overwrites existing files each time the program is restarted.
FaxFileExt is used to change the file extension from the default of APF. See page 736 for
more information.
11
12
13
14
15
16
17
1
1
Example
This example shows how to construct and use a fax receive component. This example
includes a TApdFaxStatus component (see on page 826) so that you can see the progress of
the fax session.
Create a new project, add the following components, and set the property values as
indicated in Table 15.18.
5
6
TApdComPort
Property
Value
ComNumber
InSize
8192
Name
Receive
TApdReceiveFax
TApdFaxStatus
7
8
9
10
11
TButton
The input buffer size of the comport component (the InSize property of TApdComPort) is
raised from its default value of 4096 to 8192. Although this is not essential, it provides a
buffer against programs that dont yield frequently.
Double-click on the Receive buttons OnClick event handler within the Object Inspector and
modify the generated method to match this:
procedure TForm1.ReceiveClick(Sender : TObject);
begin
ApdReceiveFax1.InitModemForFaxReceive;
ApdReceiveFax1.StartReceive;
end;
12
This method starts a background fax receive session, which initializes the modem and
prepares it to receive faxes, then calls StartReceive to start waiting for incoming faxes.
13
When a fax call arrives, TApdReceiveFax answers the phone, validates the call as a fax call,
and then begins receiving the fax data. The form includes a TApdFaxStatus component,
which is automatically displayed by the background fax process and periodically updated to
show the progress of the fax transfer.
14
15
16
17
756 Chapter 15: Fax Components
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomAbstractFax (AdFax)
" TApdAbstractFax (AdFax) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715
TApdCustomReceiveFax (AdFax)
2
3
4
TApdReceiveFax (AdFax)
Properties
" AbortNoConnect
AnswerOnRing
" BytesTransferred
" ComPort
" FaxFileExt
" PageLength
" FaxLog
" RemoteID
FaxNameMode
" SessionBPS
" FaxProgress
" SessionECM
" HangupCode
" SessionResolution
" CurrentPage
" InitBaud
" SessionWidth
" DesiredBPS
" ModemBPS
" SoftwareFlow
" DesiredECM
" ModemChip
" StationID
" ModemECM
" StatusDisplay
" ElapsedTime
" ModemInit
" StatusInterval
" ExitOnError
" ModemModel
" SupportedFaxClasses
" ModemRevision
" TotalPages
ConstantStatus
DestinationDir
FaxAndData
" FaxClass
" NormalBaud
" FaxFile
OneFax
InitModemForFaxReceive
OnFaxAccept
8
9
10
11
13
PrepareConnectInProgress
StartManualReceive
StartReceive
" StatusMsg
Events
" OnFaxError
12
Methods
" CancelFax
14
15
" OnFaxFinish
" OnFaxLog
OnFaxName
" OnFaxStatus
16
17
1
1
Reference Section
AnswerOnRing
property
2
property AnswerOnRing : Word
Default: 1
AnswerOnRing is the number of RING responses allowed before the incoming call is
answered. The default is one ring. Values less than or equal to zero are treated the same as
one ring.
ConstantStatus
6
7
property
Default: False
When transmitting faxes, the time to display status events is clear. While there are faxes to
transmit, status should be displayed; when there are no more faxes to transmit, the fax
session is over. The issue is less clear when receiving faxes because TApdReceiveFax is often
waiting for faxes with no real status information to display.
If ConstantStatus is False (the default), the first status event is generated when an incoming
ring is detected. The last status event is generated at the conclusion of the receipt of the fax.
While TApdReceiveFax is waiting for the next incoming call, no status events are generated.
Status events are generated again when the next incoming ring is detected. This continues
until CancelFax is called or a fatal error occurs.
12
If ConstantStatus is True, the first status event is generated as soon as StartReceive is called.
The last status event is generated only after CancelFax is called or a fatal error occurs.
13
14
15
16
17
758 Chapter 15: Fax Components
1
1
DestinationDir
property
property
3
4
6
7
8
Default: False
If FaxAndData is True, the faxmodem is configured to answer both fax and data calls. If it is
False, only fax calls are answered.
10
Not all faxmodems support this feature and there is no broad standard for enabling it. It is
available only in Class 2 and 2.0 faxmodems. The modem must claim adaptive answer or a
similar term in its list of features. It must accept the AT+FAA=1 sequence that Async
Professional sends to enable the feature.
11
To use this feature, you should first set FaxAndData to True. Then call
InitModemForFaxReceive to initialize the modem for receiving either fax or data calls. Do
not call StartReceive. Instead, wait for incoming calls in your program. When a call arrives
and you issue the ATA command, the faxmodem will detect whether the call is data or fax.
13
If the call is data, the modem responds with CONNECT. If you detect this string, your
program should proceed as it normally does for a data call.
12
14
15
16
17
1
1
If the call is fax, the modem responds with CED, FAX, or +FCON. If you detect any of
these strings, call PrepareConnectInProgress to tell TApdReceiveFax that the call has already
been answered, then call StartReceive.
This area of faxmodem behavior is not standardized. You will need to experiment with your
brand of faxmodem to find a method that works for you.
property
6
7
8
9
10
Default: fnCount
! Determines how an incoming fax is named if you dont assign an OnFaxName event
handler.
TApdReceiveFax must assign a file name to an incoming fax. If you do not assign an
OnFaxName event handler, TApdReceiveFax generates a name based on the value of
FaxNameMode. The modes are described in Naming incoming fax files on page 754.
InitModemForFaxReceive
method
procedure InitModemForFaxReceive;
This method sends appropriate AT commands to the faxmodem to prepare it for receiving
faxes. It first sends any string you have specified using ModemInit. Next it sends the DefInit
string (ATE0Q0V1X4S0=0). Then it enables Class 1, Class 1.0, Class 2, or Class 2.0
operation, either by autodetecting the highest class supported by the modem or using the
last class specified by FaxClass.
For Class 2 and 2.0 modems InitModemForFaxReceive also sends strings for setting the
station ID (see the StationID property on page 621), transfer rate (see the DesiredBPS
property on page 719), error correction options (see the DesiredECM property on page
720), and fax and data option (see the FaxAndData property on page 759). Hence, these
properties must be set before calling InitModemForFaxReceive. For Class 1 and Class 1.0
modems, these features are set while negotiating the connection, so you can set the relevant
properties any time before calling StartReceive.
17
760 Chapter 15: Fax Components
1
1
1
2
3
4
property
Default: False
If OneFax is True, the background fax process stops after receiving one fax. If OneFax is
False (the default), the background fax process waits for faxes until a fatal error occurs or
CancelFax is called.
The most likely use of one fax behavior is in conjunction with FaxAndData and
PrepareConnectInProgress. These are used when your program handles incoming calls
itself and passes control to the fax routines only after a fax call is detected.
9
10
property
11
! Defines an event handler that is called at the beginning of the receive fax session after the
12
13
14
When this event is generated, the only information known about the incoming fax is the
station ID. So, the typical application for this event is to accept or reject faxes based on the
station ID. For example, you can avoid receiving junk faxes by accepting only faxes coming
from known station IDs.
15
17
16
1
1
OnFaxName
property
TFaxNameEvent = procedure(
CP : TObject; var Name : TPassString) of object;
TPassString = string[255];
! Defines an event handler that is called to return a file name for a fax.
4
5
The fax protocol doesnt include file name information, so the receiving software must
generate file names (see FaxNameMode) or you can generate the file name in an
OnFaxName event handler.
See Naming incoming fax files on page 754 for more information.
PrepareConnectInProgress
procedure PrepareConnectInProgress;
method
PrepareConnectInProgress is intended to be used when your program answers calls that can
be either fax or data. When your program detects an incoming fax, it should call
PrepareConnectInProgress and then call StartReceive, which will start processing at the
point where an incoming call has already been answered. This approach can be used only if
your faxmodem supports adaptive answer. This term is used by modem manufacturers to
indicate the ability to discriminate between fax and data calls.
See also: FaxAndData
11
12
13
14
15
16
17
StartManualReceive
procedure TApdCustomReceiveFax.StartManualReceive(
SendATAToModem : Boolean);
1
1
method
StartReceive
method
procedure StartReceive;
The TAPI/Fax integration with receiving faxes will wait for incoming faxes using a passive
answering mode. If TapiDevice is assigned, the associated TApdTapiDevice will be placed in
AutoAnswer mode. When AnswerOnRing ring signals are detected, the TApdReceiveFax
will answer the call. What this means for you is that you can be waiting for incoming faxes
then go ahead and send a fax over the same device. After the fax is finished sending, TAPI
will go back to passively waiting for an incoming fax.
9
10
11
12
13
14
15
16
17
TApdReceiveFax Component 763
1
1
The purpose of the Fax Server Components is to provide flexible, integrated fax reception,
transmission, and queuing functionality.
The TApdFaxServer component provides the faxing engine and interfaces with the fax
modem. This component can be used by itself to receive faxes, or with a
TApdFaxServerManager to send faxes. The TApdFaxServer reproduces much of the
functionality of the TApdSendFax and TApdReceiveFax components, so many of the
properties are similar.
4
5
6
7
8
9
10
11
12
14
15
fax queue.
16
17
764 Chapter 15: Fax Components
1
1
1
2
3
Modem
Modem
Modem
4
TApdFaxServer
TApdFaxServer
TApdFaxServer
6
7
TApdFaxServerManager
8
TApdFaxClient
Monitored Directory
TApdFaxClient
9
10
TApdFaxClient
TApdFaxClient
TApdFaxClient
11
Figure 15.2: TApdFaxServerManger configuration.
In this scenario, there is one TApdFaxServer component for each modem to be used, one
TApdFaxServerManager component monitoring a single directory, and several
TApdFaxClient components feeding fax jobs to the monitored directory. The
TApdFaxClients will create fax jobs, and copy them to the monitored directory. The
TApdFaxServer will query the TApdFaxServerManager for fax jobs, the
TApdFaxServerManager will find the jobs submitted by the TApdFaxClients, and will pass
them to the TApdFaxServer. The TApdFaxServer will then process that job.
This scenario can be expanded upon in several ways to provide more flexible processing.
The only limitation is that a directory can only be monitored by a single
TApdFaxServerManager component.
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
Recipient info
...
Recipient info
Cover page text
Regular APF format
8
9
10
11
12
13
14
15
The details of this format are most likely not needed for most applications, but the format is
documented here in case you need to write APJ manipulation routines that are not provided
with Async Professional.
The APJ file begins with a fax job header, which contains information that applies to the fax
job as a whole. The TFaxJobHeaderRec adds 128 bytes to the size of the fax job file. Table
15.20 shows the fields of the TFaxJobHeaderRec.
Table 15.20: TFaxJobHeaderRec fields
Field
Purpose
ID
Status
JobName
Sender
SchedDT
NumJobs
NextJob
16
17
766 Chapter 15: Fax Components
1
1
Field
Purpose
CoverOfs
FaxHdrOfs
Padding
2
3
The TFaxRecipientRec record follows the TFaxJobHeaderRec in the APJ file. Since there can
be one, or several, recipients for a given APJ file, the space used will vary. 256 bytes are
added to the size of the APJ for each recipient. Table 15.21 shows the fields of the
TFaxRecipientRec.
Field
Purpose
Status
JobID
SchedDT
AttemptNum
LastResult
PhoneNumber
HeaderLine
HeaderRecipient
HeaderTitle
Padding
7
8
9
10
11
Following the TFaxRecipientRec structures in the APJ file is the cover page text data.
Replaceable tags are supported, and are defined by the respective fields in the
TFaxJobHeaderRec and TFaxRecipientRec records. Cover pages in APF format are not
directly supported, but you can add an APF formatted cover page to the beginning of the fax
file to have the same effect.
12
13
14
15
16
17
Fax Server Components 767
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
768 Chapter 15: Fax Components
1
1
TApdFaxJobHandler Component
2
3
Hierarchy
4
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdFaxJobHandler (AdFaxSrv)
Properties
! Version
Methods
AddRecipient
GetJobHeader
ResetAPJStatus
CancelRecipient
GetRecipient
ResetRecipientStatus
ConcatFaxes
GetRecipientStatus
RescheduleJob
ExtractAPF
MakeJob
ShowFaxJobInfoDialog
ExtractCoverFile
ResetAPJPartials
9
10
11
12
13
14
15
16
17
1
1
Reference Section
AddRecipient
method
2
3
4
5
6
7
8
9
10
11
12
13
14
procedure AddRecipient(
JobFileName : ShortString; RecipientInfo : TFaxRecipientRec);
TFaxRecipientRec = packed record
Status : Byte;
JobID : Byte;
SchedDT : TDateTime;
AttemptNum : Byte;
LastResult : Word;
PhoneNumber : String[50];
HeaderLine : String[100];
HeaderRecipient : String[30];
HeaderTitle : String[30];
Padding : Array[228..256] of Byte;
end;
15
16
17
770 Chapter 15: Fax Components
1
1
CancelRecipient
method
Use CancelRecipient to cancel a specific recipient in the fax job file. JobFileName is the name
of the fax job file to modify. JobNum is the index of the recipient to cancel.
ConcatFaxes
method
3
4
procedure ConcatFaxes(
DestFaxFile: ShortString; FaxFiles: array of ShortString);
The following example demonstrates how to use ConcatFaxes to concatenate several faxes (a
cover page in APF format, DOC1..DOC5) into a new file (FAXFILE.APF):
var
ApdFaxJobHandler : TApdFaxJobHandler;
begin
ApdFaxJobHandler := TApdFaxJobHandler.Create(Self);
try
ApdFaxJobHandler.ConcatFaxes(
'C:\FAXFILE.APF', ['C:\COVER.APF', 'C:\DOC1.APF',
'C:\DOC2.APF', 'C:\DOC3.APF', 'C:\DOC4.APF',
'C:\DOC5.APF']);
finally
ApdFaxJobHandler.Free;
end;
end;
9
10
11
12
13
14
15
16
17
1
1
In C++Builder, the syntax used is usually not apparent, the following example shows how to
do it:
{
ShortString FaxFiles[6] = {
"C:\\COVER.APF", "C:\\DOC1.APF", "C:\\DOC2.APF",
"C:\\DOC3.APF", "C:\\DOC4.APF", "C:\\DOC5.APF"};
ShortString DestFile = "C:\\FAXFILE.APF";
TApdFaxJobHandler* ApdFaxJobHandler =
new TApdFaxJobHandler(this);
// the array index is 0-based, the array declaration is 1-based
ApdFaxJobHandlerConcatFaxes(DestFile,FaxFiles,5);
delete ApdFaxJobHandler;
3
4
5
6
ExtractAPF
method
7
8
9
10
11
12
13
14
15
16
17
772 Chapter 15: Fax Components
1
1
ExtractCoverFile
method
function ExtractCoverFile(
JobFileName, CoverName : ShortString) : Boolean;
GetJobHeader
method
procedure GetJobHeader(
JobFileName : ShortString; var JobHeader : TFaxJobHeaderRec);
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
GetRecipient
14
15
16
17
774 Chapter 15: Fax Components
1
1
method
GetRecipientStatus
method
function GetRecipientStatus(
JobFileName: ShortString; JobNum : Integer) : Integer;
Value
Description
stNone
stPartial
stComplete
stPaused
MakeJob
3
4
6
method
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
JobFileName is the name of the resulting APJ file. RecipientInfo is the information about the
recipient for this fax job. The following example demonstrates how to use MakeJob to create
a fax file ready for submission to a TApdFaxServerManager:
var
ApdFaxJobHandler : TApdFaxJobHandler;
Recipient : TFaxRecipientRec;
begin
FillChar(Recipient, SizeOf(TFaxRecipientRec),#0);
Recipient.SchedDT := Now;
Recipient.PhoneNumber := '1 719 471 9091';
Recipient.HeaderLine := 'Fax to $R $D $T';
Recipient.HeaderRecipient := 'TurboPower';
Recipient.HeaderTitle := 'Info to TurboPower';
ApdFaxJobHandler := TApdFaxJobHandler.Create(nil);
ApdFaxJobHandler.MakeJob(
'C:\DEFAULT.APF','C:\COVER.TXT', 'Info to TurboPower',
'John Doe', 'C:\FAXES\INFO1.APJ', Recipient);
ApdFaxJobHandler.Free;
end;
ResetAPJPartials
method
This method is used to reset all recipients that have a status flag of stPartial. All recipient
flags that are stPartial are changed to stNone. JobFileName is the name of the APJ to modify.
ResetAPJStatus
method
This method is used to reset all recipient status flags to stNone, regardless of their current
value. JobFileName is the name of the APJ to modify.
14
15
16
17
776 Chapter 15: Fax Components
1
1
ResetRecipientStatus
method
procedure ResetRecipientStatus(
JobFileName: ShortString; JobNum, NewStatus: Byte);
Value
Description
stNone
stPartial
stComplete
stPaused
RescheduleJob
3
4
6
7
method
8
procedure RescheduleJob(JobFileName : ShortString;
JobNum : Integer; NewSchedDT : TDateTime; ResetStatus: Boolean);
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
ShowFaxJobInfoDialog
function ShowFaxJobInfoDialog(
JobFileName : ShortString) : TModalResult;
8
9
10
11
12
13
14
15
16
17
778 Chapter 15: Fax Components
1
1
method
TApdFaxServer Component
The TApdFaxServer component is the faxing engine for the Fax Server Components. It
handles the physical communication with the fax modem to send and receive faxes. Since
this component can both transmit and receive faxes, it shares many properties with the
ApdSendFax and ApdReceiveFax components. See Receiving and Sending Faxes with
TApdFaxServer in the Developers Guide for step-by-step instructions.
2
3
4
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomAbstractFax (AdFax)
TApdCustomFaxServer (AdFaxSrv)
TApdFaxServer (AdFaxSrv)
Properties
AnswerOnRing
EnhFont
ModemModel
BlindDial
EnhHeaderFont
ModemRevision
BufferMinimum
EnhTextEnabled
Monitoring
BytesTransferred
ExitOnError
NormalBaud
ComPort
FaxClass
PageLength
ConstantStatus
FaxFile
PrintOnReceive
CurrentPage
FaxFileExt
RemoteID
CurrentRecipient
FaxLog
SafeMode
CurrentJobFileName
FaxNameMode
SendQueryInterval
CurrentJobNumber
FaxPrinter
ServerManager
DelayBetweenSends
FaxProgress
SessionBPS
DesiredBPS
HangupCode
SessionECM
DesiredECM
InitBaud
SessionResolution
DestinationDir
MaxSendCount
SessionWidth
DialAttempt
ModemBPS
SoftwareFlow
DialAttempts
ModemChip
StationID
DialPrefix
ModemECM
StatusDisplay
DialWait
ModemInit
StatusInterval
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
SupportedFaxClasses
ToneDial
TapiDevice
TotalPages
Methods
CancelFax
ForceSendQuery
StatusMsg
OnFaxServerAccept
OnFaxServerName
OnFaxServerStatus
OnFaxServerFatalError
OnFaxServerPortOpenClose
OnFaxServerFinish
OnFaxServerLog
Events
6
7
8
9
10
11
12
13
14
15
16
17
780 Chapter 15: Fax Components
1
1
! Version
Reference Section
AnswerOnRing
property
2
property AnswerOnRing : Word
Default: 1
property
Default: False
Allows a fax to be sent regardless of whether the modem detects a dial tone.
If BlindDial is True, a different initialization sequence is sent to the modem before a fax is
sent (ATX3 is sent instead of ATX4). This initialization sequence allows the modem to use a
phone line, even if it cant detect a dial tone.
BufferMinimum
8
9
property
10
Default: 1000
! Defines the minimum number of bytes that must be in the output buffer before
TApdFaxServer yields control.
11
12
Once started, a fax transmit session must have a constant supply of data to transmit. Lack of
data to transmit is referred to as a data underflow condition and usually results in a failed fax
session. Because Windows is a multi-tasking environment, the server tries to fill the output
buffer as full as possible before yielding control. BufferMinimum is the minimum number of
output bytes that must be in the output buffer before the server yields.
13
14
15
16
17
1
1
If your program is operating among programs that arent functioning properly or other
conditions that might result in long periods where it isnt given a chance to run, increasing
BufferMinimum decreases the chance of a data underflow error.
BytesTransferred
5
6
7
! The number of bytes received or transmitted so far for the current page.
BytesTransferred can be used by an OnFaxStatus event handler to get the number of bytes
received or transferred so far. The appropriate time to check BytesTransferred is when
FaxProgress equals fpSendPage or fpGetPage. At other times, it is either zero or a value
associated with the previous page.
See also: CurrentPage, PageLength, TotalPages
8
9
CancelFax
method
procedure CancelFax;
CancelFax cancels the fax session, regardless of its current state. When appropriate, a cancel
command is sent to the local modem or the remote fax device. The fax component generates
an OnFaxFinish event with the error code ecCancelRequested, then cleans up and
terminates. It also attempts to put the faxmodem back onhook (i.e., ready for the next
call).
The following example shows how to cancel a fax from a fax status dialog:
procedure TStandardDisplay.CancelClick(Sender : TObject);
begin
ApdSendFax1.CancelFax;
end;
15
16
17
782 Chapter 15: Fax Components
1
1
ComPort
property
ComPort is the ApdComPort to be used by the fax engine. If the TapiMode property of the
ApdComPort is tmOn, and a TApdTapiDevice is assigned to the TapiDevice property, TAPI
will be used to configure and open the modem. If the TapiMode is tmOff, the port will be
opened directly. See the section titled Fax sessions and the TApdComPort on page 702 for
information regarding TApdComPort property settings required for faxing.
ConstantStatus
3
4
property
Default: False
7
8
9
10
11
12
13
14
! Contains the file name of the fax job file being sent.
CurrentJobFileName contains the file name of the fax job file currently being sent. You can
use this value for status or logging purposes. The value of this property will be maintained
until another fax is sent.
15
16
17
1
1
CurrentJobNumber
2
3
4
! Contains the index into the fax job file of the recipient being processed.
CurrentJobNumber contains the 0-based index into the fax job file (from the
CurrentJobName property). For single-recipient fax jobs, this value will be 0. You can use
this value for status or logging purposes. The value of this property will be maintained until
another fax is sent.
CurrentPage
5
6
CurrentPage can be used by an OnFaxStatus event handler to get the number of the page
currently being received or transmitted. The appropriate time to check CurrentPage is when
FaxProgress equals fpSendPage or fpGetPage. At other times, it is either zero or a value
associated with the previous page.
CurrentRecipient
10
11
12
13
14
15
16
! The TFaxRecipientRec containing recipient information about the current outbound fax.
CurrentRecipient contains information about the fax currently being sent. You can use the
fields of this record for status or logging purposes. The TFaxRecipientRec of the last job will
be maintained in this property until another fax is sent.
17
784 Chapter 15: Fax Components
1
1
DelayBetweenSends
property
DelayBetweenSends is the number of clock ticks to delay before beginning another fax
transmission. If the SendQueryInterval property is non-zero, the ApdFaxServerManager
will be queried for the next fax job at the end of each fax transmission. Some phone systems
require several seconds between calls to reset the line. Set this property to the tick-count
required by your phone system.
DesiredBPS
3
4
property
Default: 9600
! Determines the highest fax bps rate to negotiate for the next fax session.
DesiredBPS limits the fax bps rate for subsequent fax sessions. Although many faxmodems
support higher bps rates (12000 and 14400), DesiredBPS defaults to 9600 for more reliable
fax sessions and higher quality faxes because the slightly lower baud rate makes lines errors
less likely.
8
9
Changing DesiredBPS during a fax session has no effect on the current session.
See also: ModemBPS, SessionBPS
DesiredECM
10
property
11
Default: False
12
13
14
15
16
17
1
1
DestinationDir
property
There are two ways to indicate the directory for storing incoming fax files. If an
OnFaxServerName event handler is used, it can return the fully qualified name (i.e.,
including drive and directory). If an OnFaxServerName event handler does not return the
fully qualified name, or one of the automatic fax naming methods is used, DestinationDir
can be set to the name of the desired directory.
If DestinationDir is empty and the OnFaxServerName event handler doesnt return a fully
qualified file name, incoming files are stored in the current directory.
See also: OnFaxServerName
DialAttempt
property DialAttempt : Word
! Indicates the number of times the current fax number has been dialed.
If the dialed fax number is busy, TApdSendFax waits briefly and calls the number again. It
tries up to DialAttempts times. The DialAttempt property returns the number of the current
attempt. DialAttempt is incremented immediately upon encountering a busy line.
See also: DialAttempts, DialRetryWait
DialAttempts
16
17
786 Chapter 15: Fax Components
property
15
DialPrefix
property
TModemString = string[40];
3
4
property
6
7
Default: 60
! The number of seconds to wait for a connection after dialing the number.
This property determines how many seconds to wait after dialing the receivers phone
number. If the receiver does not answer within this time, the OnFaxServerFinish event will
fire and return an error code of ecFaxNoAnswer.
10
property
11
12
13
14
15
16
17
1
1
EnhHeaderFont
property
2
3
4
5
6
property
7
8
9
10
11
Default: False
12
13
ExitOnError
property
! Determines what happens when an error occurs during a fax transmit or receive.
14
15
16
If ExitOnError is True, all fax operations are stopped if any error occurs while sending or
receiving. Monitoring for incoming faxes and automatic querying for faxes to send is halted
until explicitly re-started. If ExitOnError is False, faxing operations will continue if nonfatal errors occur. Fatal errors, such as ecBadResponse, will still stop all fax operations and
cause the OnFaxServerFatalError event to fire.
17
788 Chapter 15: Fax Components
1
1
FaxClass
property
TFaxClass = (
fcUnknown, fcDetect, fcClass1, fcClass1_0, fcClass2, fcClass2_0);
Default: fcDetect
Indicates whether the faxmodem is used as Class 1, Class 1.0, Class 2, or Class 2.0.
If FaxClass is fcDetect (the default), TApdFaxServer determines what classes the modem
supports and enables the highest class. If you set FaxClass to a specific class, no attempt is
made to determine if the class you request is supported by the faxmodem.
6
7
8
9
10
11
FaxFileExt
property
12
Default: APF
13
14
15
See Naming incoming fax files on page 754 for more information.
16
17
TApdFaxServer Component 789
1
1
FaxLog
property
2
3
If you create an instance of (or a descendant of) a TApdFaxLog class (see page 828), and
assign it to FaxLog, the fax component will call the log components UpdateLog method
automatically.
FaxNameMode
property
Default: fnCount
TApdFaxServer must assign a file name to incoming fax files. This property differs from the
TApdReceiveFax components property somewhat. If FaxNameMode is fnNone, you must
supply an OnFaxServerName event to provide a file name for the incoming file; otherwise,
the incoming fax file will not be saved. If FaxNameMode is fnCount or fnMonthDay, the fax
name will follow the naming conventions of the TApdReceiveFax. OnFaxServerName event
will be generated only if FaxNameMode is fmNone.
See also: TApdReceiveFax.FaxNameMode
11
FaxPrinter
12
13
14
15
16
17
790 Chapter 15: Fax Components
1
1
property
FaxProgress
! Returns a code that indicates the current state of the fax session.
This property is most useful within an OnFaxServerStatus event handler. See Fax status
on page 707 for more information.
method
procedure ForceSendQuery;
7
8
9
10
11
12
13
14
Description
15
01
02
03
No loop current
16
17
1
1
1
2
Hangup Code
Description
04
05
Transmit phase A
10
11
No answer
Transmit phase B
5
6
7
8
20
21
22
23
24
RSPREC error
25
26
27
28
Transmit phase C
9
10
11
12
13
14
15
16
40
41
42
43
44
45
46
47
Transmit phase D
50
51
RSPREC error
52
53
54
55
56
57
17
792 Chapter 15: Fax Components
1
1
Hangup Code
Description
58
Receive phase B
70
71
RSPREC error
72
COMREC error
73
74
3
4
Receive phase C
90
91
92
93
6
7
Receive phase D
100
101
102
103
InitBaud
8
9
property
10
11
Default: 0
! Determines the initialization baud rate for modems that require different baud rates for
initialization and fax operations.
Some older 24/96 faxmodems (2400 data, 9600 fax) require that the initialization
commands be sent at 2400 baud, but that all fax commands and fax data be sent and
received at 19200. The fax software must constantly adjust the current baud rate depending
on the operation it is performing.
12
13
14
15
16
17
1
1
1
2
3
4
5
Since most faxmodems do not require a special initialization baud rate, InitBaud defaults to
zero, which means that no baud rate switches are performed. If you encounter an older
modem that requires this behavior, set InitBaud to 2400.
NormalBaud is a companion property to InitBaud. When InitBaud is non-zero, the fax
components switch to the specified baud rate when sending initialization commands and
switch back to the normal baud rate, 19200, when sending fax commands or fax data. If you
encounter a case where the normal baud rate should be something other than 19200, you
must change NormalBaud.
See also: NormalBaud
MaxSendCount
property
6
7
8
9
10
11
Default: 50
12
13
14
15
16
17
794 Chapter 15: Fax Components
1
1
ModemBPS
When you reference ModemBPS, commands are sent to the modem to determine its highest
bps rate. This works only for Class 2 and 2.0 modems; a Class 1 and Class 1.0 modems
cannot report this information until a fax connection has been established.
ModemBPS works by attempting to enable the most capable modem features and stepping
down if the modem returns ERROR. It starts at a 14400 bps transfer rate, then tries 12000,
9600, 7200, 4800, and 2400.
The technique used by ModemBPS works on most Class 2 and 2.0 faxmodems. One
low-cost, no-name-clone faxmodem we tested wouldnt return ERROR no matter what
was asked of it, even though it supported only 9600 bps with no error correction.
See also: ModemECM
ModemChip
6
7
9
10
11
12
13
14
The technique used by ModemECM works on most Class 2 and 2.0 faxmodems. But be
advised, one low-cost, no-name-clone faxmodem tested wouldnt return ERROR no
matter what was asked of it, even though it supported only 9600 bps with no
error correction.
15
17
16
1
1
ModemInit
property
TModemString = string[40];
If you assign a custom modem initialization string to ModemInit, Async Professional always
sends this string to the modem just before it sends its own DefInit string
(ATE0Q0V1X4S0=0). This occurs whenever you call StartTransmit, StartReceive, or
InitModemForFaxReceive.
Note that the DefInit string may override certain actions of the ModemInit string. This is
necessary for proper operation of the Async Professional fax routines.
ModemModel
7
8
9
10
11
12
13
14
15
16
17
796 Chapter 15: Fax Components
1
1
Monitoring
property
Default: False
property
Default: 0
! Determines the normal baud to use for modems that require different baud rates for
initialization and fax operations.
NormalBaud isnt needed unless the faxmodem requires separate baud rates for
initialization commands and the baud rate required for normal fax operations is not 19200.
See the InitBaud property on page 724 for a complete description of the operation of
InitBaud and NormalBaud.
8
9
10
event
11
12
TFaxAcceptEvent = procedure(
CP : TObject; var Accept : Boolean) of object;
! Defines an event handler that is called at the beginning of the receive fax session after the
13
14
15
16
17
TApdFaxServer Component 797
1
1
1
2
3
4
TFaxServerFatalErrorEvent = procedure(
CP : TObject; FaxMode : TFaxServerMode; ErrorCode,
HangupCode : Integer) of object;
event
! Defines an event handler that is called when a fatal error occurs during fax transmission or
8
reception.
This event is generated only for unrecoverable errors. Most fax errors caused by line noise
are handled automatically by the fax devices and are not reported through this event
handler.
11
CP is the TApdFaxServer that generated the event. FaxMode is the direction of the fax.
ErrorCode is a number indicating the type of error reported by the component.
HangupCode is the number indicating the reason for hang-up as reported by a Class2 or
Class 2.0 faxmodem. Class 1 and Class 1.0 modems will always return 0 for HangupCode.
12
Non-fatal errors, such as ecOK, ecFaxBusy, or ecCancelRequested will not cause this event
to be generated.
10
13
14
15
16
17
798 Chapter 15: Fax Components
1
1
OnFaxServerFinish
event
TFaxServerFinishEvent = procedure(
CP : TObject; FaxMode : TFaxServerMode;
ErrorCode : Integer) of object;
This event is generated at the end of each successful fax transmission or reception. CP is the
TApdFaxServer that generated the event. FaxMode is the direction of the fax. ErrorCode is a
number indicating the result of the fax, which could be ecOK, ecCancelRequested, or
ecFaxBusy. Further fax send and receive operations will continue based on the values of
Monitoring and SendQueryInterval.
OnFaxServerLog
event
6
7
! Defines an event handler that is called at designated points during a fax transfer.
The primary purpose of this event is to allow you to log statistical information about fax
transfers. For example, you could log the transfer time and whether the transfer succeeded
or failed. You can also use this event for start-up and cleanup activities.
CP is the fax component to be logged. LogCode is a code that indicates the state of the fax
transfer. The possible states are listed in Fax logging on page 712. No other information is
passed with this event, but you can use the fax status properties such as CurrentRecipient to
get additional information about the fax session.
10
11
12
13
14
15
16
17
1
1
OnFaxServerName
event
2
3
4
5
6
7
8
9
10
11
12
TFaxNameEvent = procedure(
CP : TObject; var Name : TpassString) of object;
! Defines an event handler that is called to return a file name for an incoming fax.
The fax receive protocol does not include file name information, so the receiving software
must generate file names (see FaxNameMode) or you can generate the file name in an
OnFaxServerName event handler. If the FaxNameMode property is fnCount or
fnMonthDay, this event will not be generated. If FaxNameMode is fnNone this event will be
generated. If this event is not defined and FaxNameMode is fnNone, the fax will not be
saved.
OnFaxServerPortOpenClose
event
! Defines an event handler that is called when the physical communications port is opened
and closed.
This event is generated when the physical communications port is opened or closed. The
primary purpose of this event is notification, but it can also be used to access the port prior
to the fax being generated. The fax will not continue until this event exits. If a TapiDevice is
defined, this event will fire when TAPI hands an open communications port to the
application.
OnFaxServerStatus
event
13
14
15
16
17
800 Chapter 15: Fax Components
1
1
CP is the TApdFaxServer component that generated the event. FaxMode is the direction of
the fax. First is True on the first call to the handler for the given FaxMode, False otherwise.
Last is True on the last call to the handler for the given FaxMode, False otherwise. Status is
the value of the FaxProgress property at the time the event was generated.
A predefined status component called TApdFaxStatus is supplied with Async Professional. If
you dont want to write an OnFaxServerStatus event handler, you can use this standard fax
status window. Just create an instance of TApdFaxStatus and assign it to the StatusDisplay
property of the TApdFaxServer.
See also: StatusDisplay, StatusInterval
PageLength
1
2
3
4
PageLength can be used by an OnFaxStatus event handler to get the total number of bytes in
the current page. The appropriate time to check PageLength is when FaxProgress equals
fpSendPage or fpGetPage. At other times, it is either zero or a value associated with the
previous page.
8
9
property
10
11
Default: False
12
13
14
15
16
17
1
1
RemoteID
TStationID = string[20];
RemoteID can be used by an OnFaxServerStatus event handler to get the station ID of the
remote fax machine. The appropriate time to check RemoteID is when FaxProgress equals
fpGotRemoteID. Before that, it returns an empty string.
See also: StationID
5
6
SafeMode
property
Default: True
8
9
10
11
12
At the beginning and end of every fax page, TApdFaxServer performs time-critical
handshaking with the receiving fax device, where tolerance for delays is very low. Delays as
small as a few hundred milliseconds can cause the receiver to believe the page transfer failed.
When SafeMode is True (the default), TApdFaxServer does not yield during these periods.
While this is the safest possible mode of operation, it will result in apparent brief periods of
unresponsiveness to the user. That is, they wont be able to switch to another application or
cancel the fax transfer until the critical handshaking is over. Fortunately, the time-critical
period lasts only 1-3 seconds, so this should rarely be a problem.
SendQueryInterval
property
13
14
15
16
Default: 30
! Determines the number of seconds between querying the TApdFaxServerManager for new
fax jobs.
When a fax is not being received or transmitted, the TApdFaxServerManager component
will be queried for fax transmission jobs that are scheduled, or in the queue to be scheduled.
Set this property to 0 to disable automatic querying. When a send or receive operation is
complete, the TApdFaxServerManager will be queried, and the interval will be reset.
17
802 Chapter 15: Fax Components
1
1
ServerManager
property
3
4
6
7
8
9
10
11
12
13
14
Session parameters can change more than once during a single session. Be sure that your
OnFaxServerStatus event handler updates its parameter display each time FaxProgress
returns the value fpSessionParams.
15
16
17
1
1
SessionResolution
2
3
4
5
Session parameters can change more than once during a single session. Be sure that your
OnFaxServerStatus event handler updates its parameter display each time FaxProgress
returns the value fpSessionParams.
SessionWidth
10
If SessionWidth is True (the default), the fax is a standard width of 1728 pixels (about 8.5
inches). If SessionWidth is False, the fax width is 2048 pixels (about 10 inches).
11
SessionWidth can be used by an OnFaxServerStatus event handler to check the fax width.
The appropriate time to check SessionWidth is when FaxProgress equals fpSessionParams.
Before that, it is undefined.
12
13
Session parameters can change more than once during a single session. Be sure that your
OnFaxServerStatus event handler updates its parameter display each time FaxProgress
returns the value fpSessionParams.
See also: SessionBPS, SessionECM, SessionResolution
14
15
16
17
804 Chapter 15: Fax Components
1
1
SoftwareFlow
property
Default: False
! Determines whether the fax components enable/disable software flow control during the fax
3
session.
When using software flow control during a fax session, the flow control must be enabled and
disabled at various points in the session. Because hardware flow control is more reliable, it is
used by default and the fax components do not enable/disable software flow control. If you
need to use software flow control, SoftwareFlow must be set to True.
For more information regarding flow control see Fax sessions and the TApdComPort on
page 702.
StationID
property
9
10
11
12
13
14
15
16
17
TApdFaxServer Component 805
1
1
StatusDisplay
property
2
3
If you create an instance of a class derived from TApdAbstractFaxStatus or use the supplied
TApdFaxStatus component (see page 826) and assign it to StatusDisplay, the status window
is displayed and updated automatically.
property
6
property StatusInterval : Word
Default: 1
The OnFaxServerStatus event is generated for each major fax session event (connected, got
station ID, and so on) and at intervals of StatusInterval seconds.
This property also determines how frequently the StatusDisplay window is updated.
10
11
12
13
This routine is intended primarily for use in fax status routines. It returns a status string
from the string table resource linked into your EXE. The string ID numbers correspond to
the values of the fpXxx constants (see Fax status on page 707). If the string table doesnt
contain a string resource with the requested ID, an empty string is returned.
14
15
16
17
806 Chapter 15: Fax Components
1
1
method
SupportedFaxClasses
6
7
8
TapiDevice
property
10
If TapiDevice is nil (the default), TAPI will not be used to select the device or open the
physical port.
11
If the TApdComPort specified in the ComPort property has its TapiMode set to tmAuto or
tmOn, and a TApdTapiDevice is assigned to the TapiDevice property, TAPI will be used to
select the device and open the physical port.
12
ToneDial
13
property
14
Default: True
15
16
17
1
1
TotalPages
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
808 Chapter 15: Fax Components
1
1
TApdFaxServerManager Component
2
3
4
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
" TApdFaxJobHandler (AdFxSrv). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769
TApdFaxServerManager (AdFxSrv)
7
8
Properties
DeleteOnComplete
MonitorDir
JobFileExt
Paused
! Version
9
10
Methods
" AddRecipient
" ConcatFaxes
" ExtractAPF
" ExtractCoverFile
GetJob
" GetJobHeader
GetNextFax
" GetRecipient
Reset
" ShowFaxJobInfoDialog
UpdateStatus
12
GetSchedTime
13
" MakeJob
Events
OnCustomGetJob
11
14
OnQueried
OnRecipientComplete
15
16
17
TApdFaxServerManager Component 809
1
1
Reference Section
GetJob
method
2
3
4
5
6
7
8
9
10
11
The GetNextFax method returns the file name of the next scheduled fax job in the directory
being monitored. If a fax job is not scheduled this method will return an empty string.
12
This method scans the directory specified by MonitorDir and consolidates scheduling
information for each fax file. Then, the fax job with the earliest scheduled time is located. If
that jobs scheduled time is less than or equal to the current time, the name of that job file is
returned. If the scheduled time has not passed, an empty string is returned.
13
14
15
16
17
810 Chapter 15: Fax Components
1
1
method
GetSchedTime
method
! Returns the TDateTime for which the first fax in the job file is scheduled.
The GetSchedTime method returns the TDateTime for which the earliest fax contained in
the APJ file is scheduled. JobName is the file name of the APJ file.
This method opens the job file, parses the embedded TFaxRecipientRec structures and
returns the scheduled date/time of the earliest scheduled fax in the file. The
TFaxJobHeaderRec.SchedDT field will be updated according to this value.
JobFileExt
3
4
property
Default: APJ
The TApdFaxServerManager uses this property to filter out files that are not APJ files when
looking for fax jobs. Files in the MonitorDir directory without this extension are not
included when the directory is scanned.
MonitorDir
property
10
property MonitorDir : ShortString
11
12
13
14
15
16
17
1
1
OnCustomGetJob
event
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
1
event
1
2
3
event
6
7
property
8
9
10
11
12
13
Default: False
14
15
16
17
TApdFaxServerManager Component 813
1
1
Reset
method
procedure Reset;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
814 Chapter 15: Fax Components
1
1
method
TApdFaxClient Component
The TApdFaxClient component provides the ability to create APJ fax job files with a
design-time interface. The MakeFaxJob method creates a single-recipient fax job; additional
recipients can be added to the job file with the AddFaxRecipient method. To submit the job
for faxing, place the APJ in the ApdFaxServerManager.MonitorDir folder. The
ApdFaxClient can be used on a remote system to provide fax capability across a network.
2
3
4
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
" TApdFaxJobHandler (AdFaxSrv). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769
TApdFaxClient (AdFaxSrv)
Properties
CoverFileName
HeaderTitle
PhoneNumber
FaxFileName
JobFileName
ScheduledDateTime
HeaderLine
Recipient
Sender
HeaderRecipient
JobName
! Version
Methods
" AddRecipient
AddFaxRecipient
" ConcatFaxes
" ExtractAPF
" ExtractCoverFile
" MakeJob
" GetJobHeader
" ShowFaxJobInfoDialog
" GetRecipient
MakeFaxJob
9
10
11
12
13
14
15
16
17
1
1
Reference Section
AddFaxRecipient
method
2
procedure AddFaxRecipient;
The AddFaxRecipient method will add the recipient information provided through the
Recipient property to the fax job file specified in the JobFileName property. See the example
under the MakeJob method for an illustration of the usage of this method.
6
7
property
CoverFileName determines the text file to include in the job file as a cover page. If a cover
page is not desired, set this property to an empty string. See Async Professional Job File
format on page 766 for details on job file cover pages.
FaxFileName
10
11
12
13
14
property
property
! The line of text that is sent at the top of each fax page.
15
16
A header line consists of normal text and replacement tags. A replacement tag is one of
several characters prefixed with $. When the header line is transmitted, the tags are
replaced with appropriate text. The available replacement tags are listed in Cover pages on
page 738.
17
816 Chapter 15: Fax Components
1
1
No check is made to make sure your header line fits on a page. If your header line does not
fit, it is truncated when it is transmitted. Using the default fonts, you can fit approximately
144 characters on a standard width page.
" Caution: Recently passed United States legislation makes it unlawful to send faxes within the
United States without showing certain sender information on the fax. The new requirement
states, in part: It shall be unlawful for any person within the United States to use any
computer or other electronic device to send any message via facsimile machine unless such
message clearly contains, in a margin at the top or bottom of each transmitted page or on the
first page of the transmission, the date and time it is sent and an identification of the
business, other entity, or individual sending the message and the telephone number of the
sending machine of such business, other entity, or individual.
See also: TApdSendFax.EnhHeaderFont, TApdSendFax.EnhTextEnabled,
TApdSendFax.HeaderSender, HeaderRecipient, HeaderTitle
HeaderRecipient
1
2
3
4
6
property
This string replaces the $R replacement tag in a cover page text file or a header line.
See Cover pages on page 738 for more information and examples.
See also: HeaderLine, TApdSendFax.HeaderSender, HeaderTitle
HeaderTitle
property
10
11
12
13
14
15
16
17
TApdFaxClient Component 817
1
1
JobFileName
property
Set the JobFileName property to the path and name of an existing APJ file to add recipients,
or to a new name to create a new APJ. The MakeFaxJob and AddFaxRecipient methods use
JobFileName to determine which APJ file to work with.
See also: AddFaxRecipient, MakeFaxJob
5
6
JobName
property
7
8
9
10
11
MakeFaxJob
method
procedure MakeFaxJob;
properties.
The MakeFaxJob method is used to create a new APJ file containing a single recipient.
MakeFaxJob, in turn, calls the TApdFaxJobHandler.MakeJob method, passing the
TApdFaxClient properties as parameters. The resulting APJ will be named according to the
FaxJobName property. A TFaxHeaderRec containing the JobName and Sender properties;
and the recipient information as defined by the Recipient property will be added. The
CoverFileName and FaxFileName properties determine which cover page text and APF file
to include. Additional recipients will need to be added using the AddFaxRecipient method.
16
17
818 Chapter 15: Fax Components
1
1
The following example demonstrates how to create a fax job using MakeFaxJob method and
how to add another recipient using the AddFaxRecipient method:
begin
{ set properties that apply to this job }
ApdFaxClient.CoverFileName := 'C:\COVER.TXT';
ApdFaxClient.FaxFileName := 'C:\TPFAX.APF';
ApdFaxClient.JobFileName := 'C:\FAXSRVR\TPFAX.APJ';
ApdFaxClient.JobName := 'Fax to TurboPower';
ApdFaxClient.Sender := 'Mike';
{ set properties that apply to first recipient }
ApdFaxClient.Recipient.PhoneNumber := '260 7151';
ApdFaxClient.Recipient.HeaderLine :=
'Fax from $F to $R, $D $T';
ApdFaxClient.Recipient.HeaderRecipient := 'TurboPower';
{ send this job immediately }
ApdFaxClient.Recipient.SchedDT := Now;
{ make the job }
ApdFaxClient.MakeFaxJob;
{ set properties that apply to second recipient }
ApdFaxClient.PhoneNumber := '555 1212';
ApdFaxClient.HeaderRecipient := 'Purchasing department';
{ send this to the second recipient at 6pm tonight }
ApdFaxClient.SchedDT := Date + 0.75;
ApdFaxClient.AddRecipient;
end;
PhoneNumber
property
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Recipient
run-time property
2
3
4
5
6
The Recipient property is a run-time only property that contains information about a fax
recipient, and recipient-specific information. This fields of this property can also be
referenced through the PhoneNumber, HeaderLine, HeaderRecipient, and HeaderTitle
properties.
ScheduledDateTime
property ScheduledDateTime : TDateTime
Default: Now
16
17
820 Chapter 15: Fax Components
1
1
read-only property
Sender
property
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdFaxClient Component 821
1
1
TApdAbstractFaxStatus Class
TApdAbstractFaxStatus is an abstract class that defines the methods and properties needed
by a component that automatically displays status while a TApdSendFax or TApdReceiveFax
component is sending or receiving a fax. You generally wont need to create a descendent
class of your own, since Async Professional supplies one, the TApdFaxStatus component
(see page 826).
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
822 Chapter 15: Fax Components
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdAbstractFaxStatus (AdFax)
Properties
Display
Fax
Visible
! Version
Methods
CreateDisplay
DestroyDisplay
UpdateDisplay
6
7
8
9
10
11
12
13
14
15
16
17
1
1
Reference Section
CreateDisplay
2
procedure CreateDisplay; dynamic; abstract;
3
4
5
6
7
8
9
10
11
Display
run-time property
12
13
14
Fax
property
15
16
17
1
1
UpdateDisplay
method
procedure UpdateDisplay(
const First, Last : Boolean); virtual; abstract;
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
TApdFaxStatus Component
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
826 Chapter 15: Fax Components
1
1
Hierarchy
TComponent (VCL)
TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdAbstractFaxStatus (AdFax) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 822
TApdFaxStatus (AdFStat)
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdFaxStatus Component 827
1
1
TApdFaxLog Class
3
4
5
TApdFaxLog creates or appends to a text file whose name is given by the FaxHistoryName
property. Each time the OnFaxLog event is generated, the associated TApdFaxLog instance
opens the file, writes a new line to it, and closes the file.
Following is a sample of the text file created by TApdFaxLog:
-----Receive skipped at 2/20/96 3:32:48 PM
9
10
11
12
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdFaxLog (AdFax)
13
Properties
14
Fax
15
Methods
16
UpdateLog
17
828 Chapter 15: Fax Components
1
1
FaxHistoryName
! Version
Reference Section
Fax
property
2
property Fax : TApdCustomAbstractFax
Fax is automatically initialized when the FaxLog property of the owning fax component is
set. Programs can change Fax to assign the log component to a different fax component.
FaxHistoryName
property
Default: APROFAX.HIS
UpdateLog
virtual method
10
11
12
13
TApdFaxLog contains a field named Fax that UpdateLog uses to obtain additional
information (FaxFile, BytesTransferred, and CurrentPage) about the fax transfer.
14
15
16
17
TApdFaxLog Class 829
1
1
An Async Professional fax printer driver is a Windows printer driver that generates APF
format fax files when printed to from any Windows application. After the appropriate fax
printer driver is installed on the users system, it shows up in the list of available printers. The
user can then choose to print to the fax printer driver rather than to a physical printer. The
fax printer driver creates a fax file that can then be transmitted using the Async Professional
fax components.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
For example, you could implement a fax server program that sends faxes when the user
prints to the fax printer driver. The user can simply print to the fax printer driver from any
Windows application. Your fax server program could run in the background, waiting to be
notified when printing to the fax printer driver begins and when it is finished. When the
OnEndDoc event occurs, your fax server program could then send the fax using the
StartTransmit method of the TApdSendFax component.
By default, when the Async Professional fax printer driver prints, it creates a
C:\DEFAULT.APF fax file. To specify a different name or location, use a
TApdFaxDriverInterface component.
The TApdFaxDriverInterface component provides control for the fax printer drivers. Async
Professional provides printer drivers for Windows 95/98/ME, Windows NT 4.0, and
Windows 2000.
Installation
A fax printer driver can be installed to your users system either through code or through
printer driver setup files (INF files). Installation can be accomplished using the provided
installation units: PDrvInst, PDrvInNT, PDrvUni, and PDrvUnNT. The following example
shows how to use these function. See the PINST example for a compilable file showing this
functionality.
var
QuietOperation : Boolean;
{ Suppresses success/failure prompts when True }
begin
QuietOperation := (ParamCount > 0) and
(pos('Q',UpperCase(paramStr(1))) <> 0) ;
if IsWinNT then
InstallDriver32('')
else
InstallDriver('APFGEN.DRV');
17
830 Chapter 15: Fax Components
1
1
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
The Async Professional fax printer drivers rely on several files supplied by Microsoft. These
are usually located on your Windows installation medium. The InstallDriver32 and
InstallDriver methods will first verify whether these files are already installed. If they are not
installed, a dialog will be displayed where the user can browse for the files. The following list
shows the required files (APF* are supplied in the APRO\Redist folder, others are supplied
by Microsoft)
Required printer driver files:
Windows 95/98/ME
APFGEN.DRV
UNIDRV.HLP
UNIDRV.DLL
ICONLIB.DLL
Windows NT 4/2000
APFPDENT.DLL
APFMON40.DLL
RASDDUI.HLP
APFAXCNV.DLL
RASDD.DLL
RASDDUI.DLL
Note: Windows 2000 Professional does not contain the RASDD* files required by our
printer driver. These files can be obtained from a Windows NT4 or Windows 2000 Server
installation CD.
13
14
15
16
17
832 Chapter 15: Fax Components
1
1
Recompiling
It is possible to rebuild the Async Professional fax printer drivers, but it is seldom required to
do so. Before undertaking the build process, first determine that the existing design is not
suitable to your application. Most developers who want to rebuild the printer drivers do so
because they want to build in functionality that is already supported by the
TApdFaxDriverInterface.
Async Professional provides two fax printer drivers: one for Windows 95/98/ME, another
for Windows NT/2000. The Windows 95/98/ME printer subsystem is 16-bit, and it requires
a 16-bit compiler (Delphi 1) to compile the APFGEN.DRV printer driver. The Windows
NT/2000 printer subsystem is 32-bit, building all three parts of the driver requires a 32-bit
Delphi compiler and Microsoft Visual C++ 4.0 or later.
For the latest information concerning rebuilding the Async Professional printer drivers,
search the TurboPower KnowledgeBase (http://www.turbopower.com/search/) for printer
driver.
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
TApdFaxDriverInterface Component
The TApdFaxDriverInterface component provides control for the fax printer drivers. Using
this component you can set the output file name that the fax printer driver uses and receive
notification when the fax printer driver has finished writing the fax file.
Hierarchy
4
5
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdFaxDriverInterface (AdFaxCtl)
6
7
8
Properties
DocName
Events
OnDocEnd
9
10
11
12
13
14
15
16
17
834 Chapter 15: Fax Components
1
1
FileName
OnDocStart
! Version
Reference Section
DocName
1
read-only, run-time property
2
property DocName : string
! Contains the name of the print job as it appears in the print spooler.
DocName is a read-only property that contains a textual description of the document that is
being printed.
FileName
property
Default: C:\DEFAULT.APF
! Contains the name of the output file used by the printer driver.
7
FileName holds the name of the file used by the printer driver to store the output. The
default file name is C:\DEFAULT.APF.
OnDocEnd
event
8
9
! Defines an event handler that is called when the printer driver finishes processing a
print job.
10
When a fax print server application receives this event, it can take some further action on the
file (e.g., send it or do some other processing on it).
The following example uses the OnDocEnd event for notification that the fax printer driver
has finished creating the fax file. When notification is received, the fax file is transmitted.
procedure TForm1.ApdFaxDriverInterface1DocEnd(Sender : TObject);
begin
{ Done printing to the fax file so send the fax }
ApdSendFax1.FaxFile := ApdFaxDriverInterface1.FileName;
ApdSendFax1.PhoneNumber := '260-7151';
ApdSendFax1.StartTransmit;
end;
11
12
13
14
15
16
17
TApdFaxDriverInterface Component 835
1
1
OnDocStart
event
! Defines an event handler that is called when the printer driver is ready to start printing a
new document.
This event is primarily used to supply an output file name for the printer driver to use.
Control does not return to the printer driver until the event handler is done.
The following example uses OnDocStart to set the output file name prior to the fax printer
driver writing the fax file:
5
6
7
procedure TForm1.ApdFaxDriverInterface1DocStart(
Sender : TObject);
begin
ApdFaxDriverInterface1.FileName := 'TEMPFAX.APF';
end;
8
9
10
11
12
13
14
15
16
17
836 Chapter 15: Fax Components
1
1
1
2
The ability to locate and send some kind of message to someone carrying a small electronic
device (a pager) has become a mainstay of modern existence. Once the province of the
wealthy and of high level business figures; one now sees pagers hanging from the belts and
purses of dock workers, secretaries, and even teenagers.
The ability to send and receive alphanumeric messages (i.e., those containing textual
information beyond the simple digits easily entered from a telephone keypad), is
increasingly common among modern paging equipment.
4
5
The desire to be able to send and receive such information has also increased, perhaps
somewhat in advance of the technology for doing so, as until recently the primary method
for entering and sending such data has been restricted to proprietary (and often expensive
and difficult to use) hardware devices or computer software provided by paging services.
The fairly recent development of new standards for preparing and sending alphanumeric
messages has made it possible to create generalized software solutions for performing these
tasks. However, these protocols remain somewhat obscure and awkward to implement at
the basic software level.
Given Async Professionals mission of providing well structured and encapsulated solutions
to serial, telephony, and basic TCP/IP communications needs; and with the new availability
of standardized means of performing the required transmissions, Async Professional now
includes paging components.
10
11
12
13
14
15
16
17
837
1
1
3
4
5
6
7
8
9
While these two protocols are fairly different in their implementations, the Async
Professional paging components provide a consistent interface to sending messages
regardless of which transmission medium is in use.
Requirements
The primary difference between TAP paging and SNPP paging from the Async Professional
programmers perspective is that TApdSNPPPager requires a TApdWinsockPort to work, as
it needs an open TCP/IP socket in order to transmit. TApdTAPPager can use either a
TApdComPort or a TApdWinsockPort using the appropriate DeviceLayer property setting.
In order to successfully send a page by either protocol, the recipients pager must be serviced
by a Paging Server that responds to the relevant protocol. A TAP server will typically have
a phone number to dial, which is almost certainly not the same number that is normally
called to access the pager directly. An SNPP server will have an IP address associated with it,
as well as a port number.
11
Values for these paging parameters must be entered into the relevant properties of a paging
component before paging may be performed. The programmer will have to gather this
information from the intended recipients (or from their paging companies) in order to send
pages successfully with the Async Professional paging components.
12
10
13
14
15
16
17
838 Chapter 16: Paging Components
1
1
TApdAbstractPager Component
All of the Async Professional paging components are descended from TApdAbstractPager.
This abstract paging component provides a set of properties and methods common to
sending a page regardless of the transmission medium, such as the Pager ID, the message
text to be sent, and a method to actually send the page.
Hierarchy
TComponent (VCL)
TapdAbstractPager (AdPager)
Properties
Message
PagerID
PagerLog
Methods
7
8
Send
9
10
11
12
13
14
15
16
17
TApdAbstractPager Component 839
1
1
Reference Section
Message
property
2
property Message : TStrings
3
4
5
PagerID
6
7
8
property
! Defines the identification string (frequently the phone number) of the pager to which the
message is being sent.
PagerLog
property
9
10
11
12
13
14
15
16
17
840 Chapter 16: Paging Components
1
1
method
TApdTAPPager Component
The TApdTAPPager Component is used to send alphanumeric pages to paging services that
support Telelocator Alphanumeric Protocol (TAP) also known as the IXO protocol and
the Motorola Personal Entry Terminal (PET) protocol. It publishes properties and methods
inherited from the TApdCustomModemPager that provide logic for call management:
dialing the telephone, detecting busy signals, redialing on an error, waiting to redial, etc.
2
3
4
Dialing events
The TApdTAPPager component goes through a number of stages in the process of sending a
page, these can be separated into broad categories of Errors in modem dialing; modem/line
states as the call progresses, and events/errors specific to the actual TAP protocol.
The TApdTAPPager component provides the mechanism for tracking the first two kinds of
event in the OnDialError and OnDialEvent event handler properties (see page 849). The
TApdTAPPager component provides a further level of status processing for TAP specific
events via the OnTAPStatus event handler. (See page 851.)
6
7
8
9
10
11
Value
Explanation
deNone
deNoDialTone
deLineBusy
deNoConnection
12
13
14
Dialing status
The Event parameter to OnDialStatus is of type TDialingStatus, which is a subrange
(dsNone..dsCleanup) of the TDialingCondition enumerated type that indicates the detected
status condition at the time OnDialStatus event is tripped. The values defined by
TDialingStatus are described in Table 16.2.
15
16
17
1
1
1
2
3
4
5
6
7
Explanation
dsNone
dsDialing
dsRinging
Line is ringing.
dsWaitForConnect
dsConnected
Line connected.
dsWaitingToRedial
dsRedialing
dsMsgNotSent
No message sent.
dsCancelling
dsDisconnect
Line disconnected.
dsCleanup
During the course of a TAP Page transmission, the TAP server returns several codes
indicating the success or failure of a particular stage in the connection. TApdTAPPager
provides an additional mechanism (over that provided by its ancestors) for tracking TAP
specific events and errors.
The Event parameter to OnTAPStatus is of an enumerated type (TTAPStatus) that indicates
the detected TAP status at the time OnTAPStatus event is tripped. Table 16.3 describes the
values which TTAPStatus defines.
Table 16.3: TTAPStatus values
13
14
15
16
17
Value
Explanation
psNone
psLoginPrompt
psLoggedIn
psLoginErr
psLoginFail
psMsgOkToSend
psSendingMsg
1
1
Value
Explanation
psMsgAck
psMsgNak
psMsgRs
psMsgCompleted
psDone
Hierarchy
TComponent (VCL)
!TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
" TApdAbstractPager (AdPager) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839
TApdCustomModemPager (AdPager)
TApdTAPPager (AdPager)
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
Properties
AbortNoConnect
ExitOnError
Port
BlindDial
MaxMessageLength
TAPStatusMsg
DialAttempt
Message
ToneDial
DialAttempts
ModemInit
UseEscapes
DialPrefix
PagerLog
DialWait
PhoneNumber
CancelCall
Disconnect
DialStatusMsg
ReSend
Events
OnDialError
OnTAPFinish
OnDialStatus
OnTAPStatus
10
11
12
13
14
15
16
17
844 Chapter 16: Paging Components
UseTapi
! Version
Methods
" PagerID
DialRetryWait
Send
Reference Section
AbortNoConnect
property
2
property AbortNoConnect : Boolean
Default: adpgDefAbortNoConnect
Defines what happens when the connection to a paging terminal number cannot be made
after the default number of retries.
If True, the paging process ends and generates an OnDialStatus event with dsCancelling. If
False, the pager re-attempts the page as defined by the DialAttempts property.
See also: DialAttempts, OnDialStatus
BlindDial
property
6
7
Default: adpgDefBlindDial
! Allows a page to be sent regardless of whether the modem detects a dial tone.
If BlindDial is True, a different initialization sequence is sent to the modem before a page is
sent (ATX3 is sent instead of ATX4). This initialization sequence allows the modem to use a
phone line, even if it cant detect a dial tone.
CancelCall
method
procedure CancelCall;
9
10
11
12
13
14
15
16
17
1
1
DialAttempt
property
! Indicates the number of times the current paging server number has been dialed.
If the dialed number is busy, TApdTAPPager waits briefly and calls the number again. It tries
up to DialAttempts times. The DialAttempt property returns the number of the current
attempt. DialAttempt is incremented immediately upon encountering a busy line.
DialAttempts
property
Default: adpgDefDialAttempts
This is the number of times a page is attempted, it is not the number of retries. When
DialAttempts is one, for example, the number is dialed only once. If the line is busy, it is not
tried again. When DialAttempts is three, the paging server number is dialed a maximum of
three times.
See also: DialAttempt, DialRetryWait
DialPrefix
property
10
property DialPrefix : TModemString
11
TModemString = string[40];
DialPrefix specifies an optional dial prefix that is inserted in the dial command between
ATDT and the number to dial. If the telephone system requires special numbers or codes
when dialing out, they can be specified once here rather than in every pager number.
Do not include ATD or a T or P tone/pulse modifier in the dial prefix. ATD is
automatically prefixed by Send and the T or P is controlled by ToneDial.
See also: Send, ToneDial
15
16
17
846 Chapter 16: Paging Components
1
1
DialRetryWait
property
Default: adpgDefDialRetryWait
! The number of seconds to wait after a busy signal before trying the number again.
After encountering a busy signal, TApdTAPPager checks to see if it should try this number
again by comparing DialAttempts to DialAttempt. If more attempts are required, it waits
DialRetryWait seconds before dialing again to give the dialed paging server time to have an
open line.
3
4
If no more dialing attempts are required, TApdTAPPager does not wait, but immediately
progresses to Canceling the call.
See also: DialAttempt, DialAttempts
DialStatusMsg
method
7
function DialStatusMsg(Status : TDialingCondition) : string;
This routine is intended primarily for use in calling status routines. It returns a status string
from the string table resource linked into your EXE. The string ID numbers correspond to
the values of the TDialingCondition enumerated type (see Dialing status on page 841). If
the string table doesnt contain a string resource with the requested ID, an empty string is
returned.
The returned string is never longer than MaxMessageLen (80) characters.
DialWait
9
10
11
property
12
Default: adpgDefDialWait
! The number of seconds to wait for a connection after dialing the number.
The default is 60 seconds.
13
14
15
16
17
1
1
Disconnect
method
procedure Disconnect;
2
3
property
Default: adpgDefExitOnError
! Determines what happens when an error occurs during an attempt to send a page.
5
6
If ExitOnError is True, no more attempts are made to send the page, regardless of the status
of DialAttempts. If ExitOnError is False (the default), the paging component continues to
try dialing the paging server.
See also: AbortNoConnect, DialAttempts
7
8
MaxMessageLength
property
9
10
11
12
13
! Defines a maximum length for message blocks sent to the paging server.
The TAP specification permits blocks of up to 256 characters (including all delimiters,
which reduces actual message data to about 250 characters). Some paging servers seem to
have trouble with blocks of over 80 characters however; thus the default.
Also, some TAP paging servers will not allow a single message to a single pager to exceed
256 characters total length.
Message
property
See UseEscapes on page 854 for how to embed control characters inside TAP messages.
15
16
17
848 Chapter 16: Paging Components
1
1
ModemInit
property
TModemString = string[40];
3
4
event
7
8
9
TDialError = deNone..deNoConnection;
! Defines an event handler that is called when an error occurs in the dialing procedure.
Sender is the pager component that generated the error. Error is a TDialError value number
indicating the type of error. See Dialing error handling on page 841 for the meaning of
these error codes.
10
11
12
13
14
15
16
17
TApdTAPPager Component 849
1
1
OnDialStatus
event
TDialStatusEvent = procedure(
Sender : TObject; Event : TDialingStatus) of object;
TDialingStatus = dsNone..dsCleanup;
5
6
7
8
9
10
11
12
13
! Defines an event handler that is called when a TAP page operation completes.
The OnTAPFinish event occurs when the TApdTAPPager component has received a
connection termination code from the TAP server. It indicates that the TAP communication
was completed (whether successfully or not). This may be used in logic for sending
multiple pages to know when a given page attempt has completed.
To determine the success vs. failure of a page attempt, use the OnPageStatus event.
See also: OnTAPStatus
14
15
16
17
850 Chapter 16: Paging Components
1
1
event
OnTAPStatus
event
! Defines an event handler that is called regularly during communication with the paging
2
3
4
server.
This event is generated after the completion of stages in connecting with the paging server
(e.g. logging in, sending the message). You can use it to update a status display that informs
the user about the progress of the page connection.
Sender is the pager component that is in progress. Event is of type TTAPStatusEvent which
indicates which phase of the communication is in progress. For a description of the stages,
see TAP paging status on page 842.
PagerLog
property
10
If you create an instance of (or a descendant of) a TApdPagerLog component (see page 862),
and assign it to PagerLog, the pager component will call the log components UpdateLog
method automatically.
11
PhoneNumber
12
property
13
! Defines the phone number to be dialed to access the Alphanumeric Paging Server.
The phone number is usually not the pagers phone number. Set PhoneNumber to the
number to dial prior to calling Send. If the phone system requires prefix codes (like 9), the
codes must be specified in PhoneNumber or in DialPrefix.
PhoneNumber can be used with status and logging routines to return the phone number
dialed for the current page.
See also: DialPrefix, Send
14
15
16
17
1
1
Port
property
2
3
4
5
6
These values are the most common requirements for TAP paging servers and should be
changed only if you are certain of the impact of those changes.
You can set these properties manually in code prior to sending a page. If you wish to make
the change permanent to the component, you will need either to alter the source code, or
create a descendant component of TApdTAPPager that overrides the SetPortOpts method.
ReSend
9
10
method
procedure ReSend;
method
11
procedure Send;
12
13
14
! Causes the paging component to dial the phone number specified in PhoneNumber.
The number may be modified by DialPrefix. If it receives a successful answer, Send calls the
protected method DoDial, which in turn (potentially) calls the virtual DoStartCall,
DoCloseCall, DoDisconnect, and DoFailedToSend methods. The programmer creating a
custom Modem pager should override these methods to provide protocol specific
processing for the call progress.
15
16
17
852 Chapter 16: Paging Components
1
1
The following example shows how to send a simple page with the TApdTAPPager
component:
2
3
4
method
ToneDial
property
10
11
Default: adpgDefToneDial
12
13
14
15
16
17
1
1
UseEscapes
property
Default: False
! Determines whether or not the paging component scans the text of Message prior to sending
3
If True, escapes are processed according to TAP 1.8. If False, escapes are stripped from the
message.
5
6
7
8
9
10
11
12
Version 1.8 of the TAP specification allows for embedding control characters in pages by use
of an escaping mechanism. Basically a special character (ASCII #26: SUB, otherwise
known as Ctrl-Z), followed by the desired character whose ASCII value has been
incremented by 64.
For example, Ctrl-H (ASCII #8, BS, or BackSpace) would be sent as #26H; and the
escape character (ASCII #27) would be sent as #26[.
TApdTAPPager allows such characters to be embedded in the Message property using the
standard Borland Pascal notations, making it easier to create such messages without
resorting to complex string constructions at run time.
You may use # style character constants with either decimal or hex numeric values; and you
may use ^ letter values. For example, the Ctrl-H character mentioned above may be
represented as #8 (decimal), #$08 (hexadecimal), or ^H in the string and
TApdTAPPageSend will convert those to the proper #26H sequences when the page is sent.
Some paging terminals are not using the TAP 1.8 specification and dont provide this
mechanism. Such terminals response to the presence of the escapes is unpredictable
(some just pass them through, converting the #26s to spaces, others freeze). Because of this,
TApdTAPPager provides the UseEscapes property. If set True the above conversion is
performed as stated; if False (the default) escape sequences of the above types are stripped
from the message before sending.
13
14
15
16
17
854 Chapter 16: Paging Components
1
1
UseTapi
property
Default: False
! UseTapi determines whether or not the Pager component uses TAPI (Telephony API) to
present dialable devices to the user.
This is desirable because it allows the user to pick the port/modem by installed name rather
than having to identify it solely by port number.
6
7
8
9
10
11
12
13
14
15
16
17
TApdTAPPager Component 855
1
1
TApdSNPPPager Component
TApdSNPPPager implements the simplest form (Level One) of SNPP transaction, and
automates sending so that even some Level One commands are irrelevant (e.g. HELP).
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomINetPager (AdPager)
7
8
9
10
TApdSNPPPager (AdPager)
Properties
CommDelay
Send
ServerResponseFailTerminate
" Message
ServerDataInput
ServerSuccessString
" PagerID
ServerDoneString
" PagerLog
ServerInitString
Port
ServerResponseFailContinue
11
Methods
12
13
14
Send
Events
OnLogin
OnSNPPError
OnLogout
OnSNPPSuccess
15
16
17
856 Chapter 16: Paging Components
1
1
! Version
Reference Section
CommDelay
property
2
property CommDelay : Integer
Default: 1
property
! Defines an event handler that is called when the TApdSNPPPager detects the
ServerInitString.
OnLogout
event
8
property OnLogout : TNotifyEvent
! Defines an event handler that is called when a SNPP page operation logs out of the paging
server.
The OnLogout event occurs when the TApdSNPPPager component has sent the SNPP
QUIT command and received a connection termination code from the SNPP server. It
indicates that the SNPP communication was completed (whether the page was sent
successfully or not) and successfully logging out of the paging server has occurred. This
may be used in logic for sending multiple pages to know when a given page attempt has
completed.
To determine the success vs. failure of a page attempt, monitor the OnSNPPError and
OnSNPPSuccess events.
9
10
11
12
13
14
15
16
17
TApdSNPPPager Component 857
1
1
OnSNPPError
property
TSNPPMessage = procedure(
Sender : TObject; Code : Integer; Msg : string) of object;
! Defines an event handler that is called whenever TApdSNPPPager detects a 400 or 500-
Sender is the TApdSNPPPager component generating the event. Code is the numeric code
of the error. Msg is the message string associated with the error as returned by the SNPP
server.
OnSNPPSuccess
property
TSNPPMessage = procedure(
Sender : TObject; Code : Integer; Msg : string) of object;
Sender is the TApdSNPPPager component generating the event. Code is the numeric code
of the success response. Msg is the message string associated with the response as returned
by the SNPP server.
10
11
Port
12
13
14
15
16
17
858 Chapter 16: Paging Components
1
1
property
Send
method
procedure Send;
When you call Send, the TApdSNPPPager component instructs its associated
TApdWinsockPort component to initiate a TCP/IP connection. The TApdWinsockPort
uses the IP address set in its wsAddress property, and the IP port defined in its wsPort
property to make the connection.
3
4
TApdSNPPPager waits for the response defined in the ServerInitString property and then
begins an SNPP transaction; first sending the desired destination for the page (in the
PagerID property), then the text of the message (in the Message property); then it instructs
the SNPP server to send. Upon receipt of a successful send TApdSNPPPager logs out of the
SNPP server.
The following example shows how to send a simple page with the TApdSNPPager
component:
ServerDataInput
8
9
10
property
11
12
! Defines the string that indicates the server is ready for multi-line input.
The ServerDataInput property is the string that the user wishes TApdSNPPPager to watch
for to indicate that the SNPP server has recognized the request to send a multi-line
command and is waiting for input. This response can vary among servers, but is generally
prefixed by a success response code in the range 300-399.
The string may contain wildcards in the form of question marks to indicate that any
character (usually a digit) is acceptable at that point.
13
14
15
16
17
1
1
ServerDoneString
property
Default: 221
The ServerDoneString property is the string that the user wishes TApdSNPPPager to watch
for to indicate that the SNPP server is responding to the SNPP QUIT command and has
logged out of the paging session. This response may vary among servers, but the common
response seems to be prefixed by a code of 221.
The string may contain wildcards in the form of question marks to indicate that any
character (usually a digit) is acceptable at that point.
ServerInitString
7
8
9
10
11
Default: 220
12
13
! Defines the string that indicates a non-fatal error in the paging transaction.
15
16
The string may contain wildcards in the form of question marks to indicate that any
character (usually a digit) is acceptable at that point.
17
860 Chapter 16: Paging Components
property
14
property
ServerResponseFailTerminate
property
! Defines the string that indicates a fatal error in the paging transaction.
The ServerResponseFailTerminate property is the string that the user wishes
TApdSNPPPager to watch for to indicate that the SNPP server has encountered a problem
with the SNPP transaction from which it is unable to recover; often the SNPP server will
shut down upon such an event.
These responses may vary among servers, but they are generally prefixed by a code in the
range 400-499. The string may contain wildcards in the form of question marks to indicate
that any character (usually a digit) is acceptable at that point.
ServerSuccessString
3
4
property
The ServerSuccessString property is the string that the user wishes TApdSNPPPager to
watch for to indicate that the SNPP server has responded that a SNPP command has been
successfully received and processed. This response can vary among servers, but is generally
prefixed by a success code in the range 250-259.
10
The string may contain wildcards in the form of question marks to indicate that any
character (usually a digit) is acceptable at that point.
11
12
13
14
15
16
17
TApdSNPPPager Component 861
1
1
TApdPagerLog Component
7
8
09/09/1999 17:03:58
09/09/1999 17:05:05
09/09/1999 17:08:42
09/09/1999 17:09:51
09/09/1999 17:14:20
09/09/1999 17:14:25
10
09/09/1999 17:27:17
09/09/1999 17:27:32
09/09/1999 17:27:17
09/09/1999 17:27:32
09/09/1999 18:06:52
11
12
13
09/09/1999 18:07:01
14
15
16
17
862 Chapter 16: Paging Components
1
1
Hierarchy
TComponent (VCL)
! TApdBaseComponent (OOMisc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdPagerLog (AdPager)
Properties
HistoryName
Pager
! Version
Methods
UpdateLog
6
7
8
9
10
11
12
13
14
15
16
17
TApdPagerLog Component 863
1
1
Reference Section
HistoryName
property
2
property HistoryName : string
! Determines the name of the file used to store the protocol log.
4
5
6
You should generally set the value of HistoryName before calling the pager components
Send method. However, because the log file is opened and closed for each update, you can
change the HistoryName at any time you wish. If you set HistoryName to an empty string,
automatic logging is disabled until you assign a non-empty string.
Pager
property
7
8
9
UpdateLog
10
11
12
13
14
15
16
17
864 Chapter 16: Paging Components
1
1
virtual method
TApdGSMPhone Component
The TApdGSMPhone component provides access to cellular phones and other GSM
compliant devices. One of the more popular uses of GSM is the sending and receiving of
SMS messages. The TApdGSMPhone component can send SMS messages through the GSM
device, provide notification when SMS messages are received, and provide access to the
GSM devices internal message store.
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
Type
Description
Address
String
Message
String
Status
TApdSMSStatus
TimeStamp
TDateTime
9
10
11
12
The TApdSMSStatus type is an enumeration of the possible status flags for an SMS message.
The Status property of the TApdSMSMessage class can be one of the following values shown
in Table 16.5.
13
14
15
Value
Description
ssUnread
ssRead
ssUnsent
ssSent
16
17
866 Chapter 16: Paging Components
1
1
1
2
3
4
6
7
8
9
Protocol implementation
The GSM Technical Specification (GTS) 07.05 version 5.1.0 dated December 1996 defines
three interface protocols to communicate between the GSM device and computer serial
port:
10
11
12
13
mode).
The TApdGSMPhone component implements the Text-mode interface. In text mode, the
TApdGSMPhone will transmit GSM AT commands to the GSM device and collect the
responses. The commands that the TApdGSMPhone uses are defined in the GTS as
mandatory for the device to support. In reality, not all GSM devices support all of the
14
15
16
17
1
1
1
2
3
mandatory commands. If your device does not support these mandatory commands, it is
unlikely that you will be able to use all of the TApdGSMPhone methods. The GSM AT
commands that the TApdGSMPhone uses are listed in Table 16.6.
Table 16.6: Supported GSM AT commands
GSM AT Command
Description
4
5
6
+CSMS
+CPMS
+CSDH
+CNMI
+CMGL
List messages.
9
10
11
12
+CMGS
Send message.
+CMSS
+CMGW
+CMGD
13
14
15
16
17
868 Chapter 16: Paging Components
1
1
The TApdGSMPhone component is designed to be functional and easy to use. The first
example will demonstrate sending a single SMS message through a GSM compliant cell
phone. The second example will demonstrate one way to display a phones message store in a
TListBox component.
When the message has been sent to the phone, the OnSessionFinish event will be generated.
The ErrorCode parameter of that event will tell you whether the message was sent
successfully (ErrorCode = ecOK) or whether it failed (ErrorCode = one of the ecSMSXxx
error codes). Create the OnSessionFinish event handler and make it look like the following:
procedure TForm1.ApdGSMPhone1SessionFinish(Pager:
TApdCustomGSMPhone;
ErrorCode: Integer);
begin
ShowMessage('Message status: ' + ErrorMsg(ErrorCode));
end;
Compile and run your project. Enter a destination address in the first edit control and a
short message in the second edit control, and then click the button. The Message status
dialog box will be displayed once the phone responds to the commands.
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
To expand upon this example, you can send multiple messages in the same session. To do
this, add the OnNextMessage event handler. This event is generated when the response to
the previous message has been received. If another message is ready to be sent, set the
Address and Message properties to the appropriate values for the new message and set the
NextMessageReady parameter to True. If another message is not ready to be sent, set the
NextMessageReady parameter to False. Once all messages have been sent (after you set
NextMessageReady to False), the OnSessionFinish event will be generated.
16
17
870 Chapter 16: Paging Components
1
1
In this example we will be displaying the details of the message when the list box is double
clicked. Add the OnDblClick event handler for the TListBox and add the following code:
procedure TForm1.ListBox1DblClick(Sender: TObject);
var
I : Integer;
Msg : TApdSMSMessage;
begin
if ListBox1.ItemIndex > 0 then begin
I := ListBox1.ItemIndex;
Msg := ApdGSMPhone1.MessageStore.Messages[I];
edtAddress.Text := Msg.Address;
edtTimestamp.Text := Msg.TimeStampStr;
edtStatus.Text := ApdGSMPhone1.StatusToStr(Msg.Status);
MemoMessage.Text := Msg.Message;
end;
end;
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
TApdSMSMessage Class
The TApdGSMPhone component uses the TApdSMSMessage class to defines SMS messages
contained in the MessageStore of the component. The TApdSMSMessage class descends
from TObject and encapsulates an SMS message.
Hierarchy
4
5
6
7
TObject (VCL)
TApdSMSMessage (AdGSM)
Properties
Address
MessageIndex
TimeStamp
Message
Status
TimeStampStr
8
9
10
11
12
13
14
15
16
17
872 Chapter 16: Paging Components
1
1
Reference Section
Address
1
property
2
property Address : string
Address is the SMS address of the SMS message. For received messages, Address is the
address of the sender. For outbound message, Address is the address of the destination.
Message
property
Message is the text of the SMS message. SMS text messages are usually limited to 160
characters, including the address and the text of the message. No validation is performed on
the size of the message through the components.
MessageIndex
property
10
11
12
13
14
15
16
17
1
1
Status
property
Status is the phones flag for the message. Status can be one of the following:
Value
Description
ssUnread
ssRead
ssUnsent
ssSent
property
8
property TimeStamp : TDateTime
9
10
11
12
13
14
15
16
17
874 Chapter 16: Paging Components
1
1
property
TApdMessageStore Class
The TApdGSMPhone maintains a list of messages which reflects the message store on the
cell phone. TheTApdMessageStore class defines the interface with the cell phones message
store.
2
3
Hierarchy
4
TStringList (VCL)
TApdMessageStore (AdGSM)
Properties
Capacity
6
Messages
Methods
AddMessage
Clear
Delete
8
9
10
11
12
13
14
15
16
17
1
1
Reference Section
AddMessage
method
2
function AddMessage(const Dest, Msg : string) : Integer;
3
4
5
6
Capacity
Different cell phones will have internal message stores with different capacities. The
Capacity property indicates the number of messages that the phones message store can
contain. This property is valid once the Synchronize method of the TApdGSMPhone has
been called.
Clear
method
procedure Clear;
10
11
12
13
14
! Deletes a single message from the TApdMessageStore and the cell phone.
Delete is an indexed property that deletes the specified message from both the cell phones
message store and the TApdMessageStore. Index is the index of the message to delete.
15
16
17
876 Chapter 16: Paging Components
1
1
method
Messages
run-time property
The Messages property of the TApdMessageStore class is an indexed property that provides
access to the SMS messages contained in the class. Use Messages the same way the Strings
and Objects properties of the TStringList are used. The return value will be the
TApdSMSMessage stored in the location determined by Index.
3
4
6
7
8
9
10
11
12
13
14
15
16
17
TApdMessageStore Class 877
1
1
TApdGSMPhone Component
TApdGSMPhone forms the foundation for accessing cell phones or other GSM devices and
provides a set of properties and methods to control TApdSMSMessage class and
TApdMessageStore.
Hierarchy
4
5
TComponent (VCL)
! TApdBaseComponent (OOMISC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
TApdCustomGSMPhone (AdGSM)
6
7
8
9
10
11
12
TApdGSMPhone (AdGSM)
Properties
ComPort
MessageStore
Connected
NotifyOnNewMessage
ErrorCode
QuickConnect
GSMState
SMSAddress
Methods
Connect
SendMessage
SendAllMessages
Synchronize
Events
OnGSMComplete
13
14
15
16
17
878 Chapter 16: Paging Components
1
1
SMSMessage
! Version
OnNewMessage
OnNextMessage
Reference Section
ComPort
property
2
property ComPort : TApdCustomComPort
A comport component must be assigned to this property before connecting to the phone
with the AutoOpen set to True (default). If the AutoOpen property of ComPort is False, the
port must be explicitly opened before use.
Connect
method
procedure Connect;
10
property
11
12
13
14
15
16
17
TApdGSMPhone Component 879
1
1
ErrorCode
property
2
3
4
5
6
7
8
9
10
11
12
13
Description
0127
128255
300
ME failure.
301
302
303
304
305
310
311
312
313
SIM failure.
314
SIM busy.
315
SIM wrong.
316
317
318
320
Memory failure.
14
15
16
17
880 Chapter 16: Paging Components
1
1
Error Code
Description
321
322
Memory full.
330
331
No network service.
332
Network timeout.
340
500
Unknown error.
512
Manufacturer specific.
1
2
3
4
GSMState
property
7
8
The GSMStates are used internally primarily to determine that state of the GSM state
machine. GSMState will be set when one of the TApdGSMPhone public methods is called to
indicate what the TApdGSMPhone is doing.
The following table shows the TApdGSMStates values:
9
10
Value
Description
gsNone
Idle.
gsConfig
gsSendAll
gsListAll
gsSend
gsWrite
11
12
13
14
15
16
17
TApdGSMPhone Component 881
1
1
MessageStore
property
The MessageStore property contains a list of SMS messages. The MessageStore property is a
TApdMessageStore, which is a TStringList descendent. See the TApdMessageStore and
TApdSMSMessage definitions earlier in this section for details.
NotifyOnNewMessage
6
7
8
9
10
11
12
13
14
15
16
17
882 Chapter 16: Paging Components
event
! Defines an event handler that is called when the GSM operation is complete.
property
OnNewMessage
event
! Defines an event handler that is called when there is a new SMS message in the
memory store.
If the NotifyOnNewMessage property is True, and the device supports it, the device will
send notification to the TApdGSMPhone component when a new message is received.
When this notification is received, the newly received message is stored in the MessageStore
property and this event is generated.
Pager is the TApdCustomGSMPhone component that generated the event. Index is the
position in the MessageStore property where the new message was placed. Message is a
string containing the text of the received message.
OnNextMessage
event
9
10
11
If another message is ready to be sent, change the SMSAddress and SMSMessage properties
to reflect the new message to send, and set the NextMessageReady parameter to True. If
another message is not ready, set the NextMessageReady parameter to False. The
OnGSMComplete event handler will be generated once NextMessageReady is set to False.
13
12
14
15
16
17
1
1
QuickConnect
property
Default: False
When the Connect method of the TApdGSMPhone component is called, the device is
initialized and the GSM capabilities of the device are verified. If the QuickConnect property
is False (the default), the MessageStore property is synchronized with the message store of
the device. If QuickConnect is True, the operation terminates once the device has been
connected.
Set QuickConnect to True if your device does not support an internal message store, or if
you do not want to synchronize the message stores.
See also: Connect
SendAllMessages
procedure SendAllMessages;
! This procedure sends all the SMS messages in the memory store.
SendAllMessages iterates through all of the messages contained in the MessageStore
property and sends all messages with a Status of ssUnsent.
SendMessage
procedure SendMessage;
! This routine will send a message without placing the message in memory.
14
15
13
16
17
884 Chapter 16: Paging Components
method
This method is used to send a single message, or to start sending a series of messages,
without accessing the GSM devices message store. Set the SMSAddress property to the SMS
address of the recipient for the message, and the SMSMessage property to the message that
you want to send, then call the SendMessage method. If the OnNextMessage event handler is
assigned, that event will be generated once SendMessage sends the message. The
OnNextMessage event handler can be used to send a sequence of messages.
12
method
SMSAddress
property
The SMSAddress property determines where the SMS message will be sent. This property is
used with the SendMessage method to transmit a single message, or a series of messages.
The message determined by SMSMessage is sent to the address determined by SMSAddress.
The SMSAddress and SMSMessage properties, and the SendMessage method, do not access
the message store of the GSM device or the MessageStore property of the component.
3
4
property
6
property SMSMessage : string
The SMSMessage property determines the message to send. This property is used with the
SendMessage method to transmit a single message, or a series of messages. The message
determined by SMSMessage is sent to the address determined by SMSAddress.
The SMSAddress and SMSMessage properties, and the SendMessage method, do not access
the message store of the GSM device or the MessageStore property of the component.
10
Synchronize
method
11
procedure Synchronize;
! This routine will synchronize the message store of the GSM device.
The Synchronize method is used to synchronize the messages contained in the
MessageStore property with the messages contained in the GSM devices internal message
store. This method is called internally during a Connect sequence if the QuickConnect
property is False.
See also: Connect, MessageStore, QuickConnect
12
13
14
15
16
17
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
886 Chapter 16: Paging Components
1
1
1
2
The routines described in this chapter come from a few units that Async Professional uses
internally. These routines may also prove useful in your applications and therefore are
documented here.
The first section documents procedures and functions that manage event timers. These
non-object-oriented routines are used to provide tick-resolution (18.2 ticks/second) timing
services for the rest of the library.
The second section documents a few functions that return strings for numeric codes: serial
port names, error messages, and protocol names from the corresponding numeric type used
by Async Professional.
5
6
The third section documents the IsPortAvailable method, which can be used to determine
whether a specific serial port is available.
7
8
9
10
11
12
13
14
15
16
17
887
1
1
Timers
The OoMisc unit provides the timer routines used internally by Async Professional. You
might find these routines handy for your programs as well. In almost all cases you will find it
more convenient to use timer triggers with a TApdComPort component (see page 22) rather
than working with the timer routines directly. If you dont want to use OoMisc timers
directly then you dont need to read this section.
3
4
5
6
7
OoMiscs basic time unit is the BIOS clock tick. One clock tick is approximately 55
milliseconds. Put another way, there are about 18.2 clock ticks per second. This means that
55 milliseconds is the smallest interval that you can time and the timing of any event has an
uncertainty of 55 milliseconds.
Unless otherwise specified, all Async Professional routines that have time-out parameters
the Ticks parameter to the TApdComPort SetTimerTrigger method, for examplerequire a
value expressed in clock ticks. OoMisc also offers routines to convert between ticks and
seconds in case you prefer to work with seconds.
10
11
12
13
14
15
16
17
1
1
This example uses a simple WinCrt-based interface because the EventTimer is user-interface
independent.
This program loops continuously, displaying the elapsed ticks and the remaining ticks, until
the timer expires or a key is pressed.
It is perfectly legal to use the ElapsedTime routines even after a timer has expired. If the
example program called ElapsedTime after the timer had expired, it would still return the
number of ticks since the timer was started.
A timer is good for 24 hours at most. If you reference a timer after 24 hours, the results are
modulo 24 hours.
Routines
DelayTicks
NewTimerSecs
Ticks2Secs
ElapsedTime
RemainingTime
TimerExpired
ElapsedTimeInSecs
RemainingTimeInSecs
NewTimer
Secs2Ticks
6
7
8
9
10
11
12
13
14
15
16
17
Timers 889
1
1
Reference Section
DelayTicks
2
function DelayTicks(Ticks: LongInt; Yield : Bool) : LongInt;
3
4
5
6
Even with Yield set to True, DelayTicks should not be used to delay for periods of time
longer than a few seconds. For longer delays you should set up an EventTimer or a timer
trigger and continue the execution of your program until the timer expires.
ElapsedTime
9
10
11
12
13
14
15
16
17
890 Chapter 17: Low-level Facilities
1
1
ElapsedTimeInSecs
This routine returns the same result as ElapsedTime, but converted to seconds. Partial
seconds are truncated.
The following example shows how to use an EventTimer within a simple WinCrt
application. Async Professional uses timers internally, without direct connection to the user
interface.
3
4
This example displays the elapsed time until a key is pressed or 20 seconds have elapsed:
var
ET : EventTimer;
begin
WriteLn('You have 20 seconds to press a key:');
NewTimerSecs(ET, 20);
repeat
Write(^M, ElapsedTimeInSecs(ET));
until KeyPressed or TimerExpired(ET);
WriteLn;
if not KeyPressed then WriteLn('Time is up.');
end.
6
7
8
9
10
NewTimer
11
! Initializes a timer that will expire in the specified number of clock ticks.
This routine initializes an EventTimer record, which is used to measure elapsed time or to
schedule an event. NewTimer does two things: 1) it stores the current time in the StartTicks
field of ET, and 2) it calculates what the time will be when Ticks number of clock ticks expire
and stores that value in ExpireTicks. Ticks must be less than or equal to TicksPerDay
(1,573,040). The timer handles rollover at midnight when needed.
12
13
14
15
16
17
Timers 891
1
1
1
2
3
4
The following example initializes a timer and then loops until the timer expires in 20
seconds.
var
ET : EventTimer;
...
NewTimer(ET, Secs2Ticks(20));
repeat
...
until TimerExpired(ET);
NewTimerSecs
This routine is identical to NewTimer except that the time-out period is expressed in terms
of seconds rather than clock ticks.
RemainingTime
function RemainingTime(ET : EventTimer) : LongInt;
10
! Returns the amount of time remaining, in clock ticks, until the specified timer expires.
If the timer has already expired, RemainingTime returns zero.
11
12
RemainingTimeInSecs
function RemainingTimeInSecs(ET : EventTimer) : LongInt;
13
14
15
16
17
892 Chapter 17: Low-level Facilities
1
1
Secs2Ticks
The conversion uses long integer arithmetic to do the conversion, which does not throw
away any accuracy given that an integer number of ticks is being returned.
Ticks2Secs
function Ticks2Secs(Ticks : LongInt) : LongInt;
The following example gets the elapsed time in ticks from a timer and displays it to the
nearest number of seconds.
var
ET : EventTimer;
...
WriteLn(Ticks2Secs(ElapsedTime(ET)));
8
9
10
TimerExpired
function TimerExpired(ET : EventTimer) : Bool;
11
12
13
14
15
16
17
Timers 893
1
1
Name Routines
2
3
Async Professional provides several routines that are useful in message boxes, status dialogs,
and logging reports. These routines simply convert a numeric value such as an error code
into a string that describes the meaning of the number. These routines are described in this
section.
Routines
ComName
5
6
7
8
9
10
11
12
13
14
15
16
17
894 Chapter 17: Low-level Facilities
1
1
ErrorMsg
ProtocolName
Reference Section
ComName
2
function ComName(const ComNumber : Word) : string;
The error code you pass to ErrorMsg is usually obtained from the ErrorCode property of
any exception class derived from EAPDException. All Async Professional exceptions
initialize this property. In fact, when the EAPDException Create constructor is called, it
passes the string returned by ErrorMsg on to the Create constructor of the VCL Exception
class.
The error code can also be obtained from the TApdProtocol components ProtocolError
property when a protocol is terminated abnormally, or from the ErrorCode parameter
passed to the OnProtocolError event handler. Because protocols run in the background,
they do not generate exceptions but instead pass error codes.
9
10
11
A complete list of error codes, exceptions, and error messages is given in Error Handling
and Exception Classes on page 900.
12
13
14
15
16
17
Name Routines 895
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
The following example shows an exception handler that takes specific action for some error
codes and shows an error message for all others:
try
ApdComPort.Open := True;
...work with comport component
except
on E : EAPDException do
case E.ErrorCode of
...handle specific errors
else
{show error message for all errors not handled above}
ShowMessage(ErrorMsg(E.ErrorCode));
end;
end;
IsPortAvailable
function IsPortAvailable(ComNum : Cardinal) : Boolean;
17
896 Chapter 17: Low-level Facilities
1
1
The following example will populate a TListBox with a list of all ports that are available and
not in use. ComName is interfaced in the AdPort unit.
uses
AdSelCom, AdPort;
procedure TForm1.Button1Click(Sender: TObject);
var
I : Integer;
begin
ApdShowPortsInUse := False;
for I := 1 to 50 do
if IsPortAvailable(I) then
ListBox1.Items.Add(ComName(I) + ' is available');
end;
1
2
3
4
ProtocolName
function ProtocolName(const ProtocolType : TProtocolType) : string;
TProtocolType = (
ptNoProtocol, ptXmodem, ptXmodemCRC, ptXmodem1K, ptXmodem1KG,
ptYmodem, ptYmodemG, ptZmodem, ptKermit, ptAscii, ptBPlus);
7
8
9
10
11
12
13
14
15
16
17
Name Routines 897
1
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
898 Chapter 17: Low-level Facilities
1
1
18
2
This chapter contains a discussion of error handling, a description of the Async Professional
conditional defines, a glossary of communications terms, and some general tips on
debugging asynchronous communications programs in the Windows environment.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
899
1
1
18
2
3
4
5
6
7
8
9
11
All Async Professional exceptions descend from a class named EAPDException, itself
descended from the VCL Exception class. EAPDException has a read/write, run-time
property named ErrorCode. This property returns an integer status code that can be tested
to determine the cause for a particular exception. In special cases, a new value can be
assigned to ErrorCode to update the meaning of an error or to cause other error handlers to
disregard the error.
12
Further descended from EAPDException are eight exception classes that encompass error
groups as shown in Table 18.1.
13
10
14
15
16
Exception
Group Description
EGeneral
EOpenComm
ESerialIO
EModem
ETrigger
EPacket
17
900 Chapter 18: Appendices
1
1
Group Description
EProtocol
EINI
EFax
ETapi
18
2
3
4
Additional exception classes derived from these groups correspond to particular error
conditions and numeric error codes. The Table 18.2 shows the most specific Async
Professional exception classes in alphabetical order.
Ancestor
Error Code(s)
EAlreadyDialing
EModem
ecAlreadyDialing
EAlreadyOpen
EOpenComm
ecAlreadyOpen
EApdSocketException
Exception
EBadArgument
EGeneral
ecBadArgument
EBadFieldForIndex
EINI
ecBadFieldForIndex
EBadFieldList
EINI
ecBadFieldList
EBadGraphicsFormat
EFax
ecBadGraphicsFormat
EBadId
EOpenComm
ecBadId
EBadTriggerHandle
ETrigger
ecBadTriggerHandle
EBaudRate
EOpenComm
ecBaudRate
EBufferIsEmpty
ESerialIO
ecBufferIsEmpty
EBufferTooBig
EGeneral
ecBufferTooBig
EByteSize
EOpenComm
ecByteSize
ECannotUseWithWinsock
EGeneral
ecCannotUseWithWinsock
ECantMakeBitmap
EFax
ecCantMakeBitmap
ECommNotOpen
EOpenComm
ecCommNotOpen
EConvertAbort
EFax
ecConvertAbort
EDatabaseEmpty
EINI
ecDatabaseEmpty
7
8
9
10
11
12
13
14
15
16
17
1
1
18
2
3
4
5
6
7
8
9
10
11
12
13
Ancestor
Error Code(s)
EDatabaseFull
EINI
ecDatabaseFull
EDataTooLarge
EINI
ecDataTooLarge
EDefault
EOpenComm
ecDefault
EFaxBadFormat
EFax
ecFaxBadFormat
EFaxBadMachine
EFax
ecFaxBadMachine
EFaxBadModemResult
EFax
ecFaxBadModemResult
EFaxBusy
EFax
ecFaxBusy
EFaxDataCall
EFax
ecFaxDataCall
EFaxInitError
EFax
ecFaxInitError
EFaxNoCarrier
EFax
ecFaxNoCarrier
EFaxNoDialTone
EFax
ecFaxNoDialTone
EFaxPageError
EFax
ecFaxPageError
EFaxSessionError
EFax
ecFaxSessionError
EFaxTrainError
EFax
ecFaxTrainError
EFaxVoiceCall
EFax
ecFaxVoiceCall
EFontFileNotFound
EFax
ecFontFileNotFound
EGetBlockFail
ESerialIO
ecGetBlockFail
EGotQuitMsg
EGeneral
ecGotQuitMsg
EHardware
EOpenComm
ecHardware
EIniRead
EINI
ecIniRead
EIniWrite
EINI
ecIniWrite
EInternal
EGeneral
ecInternal,
ecNoFieldsDefined,
ecNoIndexKey,
ecDatabaseNotPrepared
EInvalidPageNumber
EFax
ecInvalidPageNumber
EInvalidProperty
EPacket
ecStartStringEmpty,
ecPacketTooSmall,
ecNoEndCharCount,
ecEmptyEndString,
ecZeroSizePacket
EKeyTooLong
EINI
ecKeyTooLong
14
15
16
17
1
1
Ancestor
Error Code(s)
ELoggingNotEnabled
ESerialIO
ecLoggingNotEnabled
EMemory
EOpenComm
ecMemory
EModemBusy
EModem
ecModemBusy
EModemNotAssigned
EGeneral
ecModemNotAssigned
EModemNotDialing
EModem
ecModemNotDialing
EModemNotResponding
EModem
ecModemNotResponding
EModemNotStarted
EModem
ecModemNotStarted
EModemRejectedCommand
EModem
ecModemRejectedCommand
EModemStatusMismatch
EModem
ecModemStatusMismatch
ENoHandles
EOpenComm
ecNoHandles
ENoImageBlockMarked
EFax
ecNoImageBlockMarked
ENoImageLoaded
EFax
ecNoImageLoaded
ENoPortSelected
EOpenComm
ecNoPortSelected
ENotDialing
EModem
ecNotDialing
ENoTimers
EOpenComm
ecNoTimers
ENullApi
ESerialIO
ecNullApi
EOutputBufferTooSmall
ESerialIO
ecOutputBufferTooSmall
EPhonebookNotAssigned
EGeneral
ecPhonebookNotAssigned
EPortNotAssigned
EGeneral
ecPortNotAssigned
EPutBlockFail
ESerialIO
ecPutBlockFail
ERecordExists
EINI
ecRecordExists
ERecordNotFound
EINI
ecRecordNotFound
ERegisterHandlerFailed
ESerialIO
ecRegisterHandlerFailed
ESequenceError
EProtocol
ecSequenceError
EStringSizeError
EPacket
ecPacketTooLong
ETapi16Disabled
ETapi
ecTapi16Disabled
ETapiAddressBlocked
ETapi
ecAddressBlocked
ETapiAllocated
ETapi
ecAllocated
ETapiBadDeviceID
ETapi
ecBadDeviceID
18
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Ancestor
Error Code(s)
ETapiBearerModeUnavail
ETapi
ecBearerModeUnavail
ETapiBillingRejected
ETapi
ecBillingRejected
ETapiBusy
ETapi
ecTapiBusy
ETapiCallUnavail
ETapi
ecCallUnavail
ETapiCompletionOverrun
ETapi
ecCompletionOverrun
ETapiConferenceFull
ETapi
ecConferenceFull
ETapiDialBilling
ETapi
ecDialBilling
ETapiDialDialtone
ETapi
ecDialDialtone
ETapiDialPrompt
ETapi
ecDialPrompt
ETapiDialQuiet
ETapi
ecDialQuiet
ETapiGetAddrFail
ETapi
ecTapiGetAddrFail
ETapiIncompatibleApiVersion
ETapi
ecIncompatibleApiVersion
ETapiIncompatibleExtVersion
ETapi
ecIncompatibleExtVersion
ETapiIniFileCorrupt
ETapi
ecIniFileCorrupt
ETapiInUse
ETapi
ecInUse
ETapiInvalAddress
ETapi
ecInvalAddress
ETapiInvalAddressID
ETapi
ecInvalAddressID
ETapiInvalAddressMode
ETapi
ecInvalAddressMode
ETapiInvalAddressState
ETapi
ecInvalAddressState
ETapiInvalAppHandle
ETapi
ecInvalAppHandle
ETapiInvalAppName
ETapi
ecInvalAppName
ETapiInvalBearerMode
ETapi
ecInvalBearerMode
ETapiInvalCallComplMode
ETapi
ecInvalCallComplMode
ETapiInvalCallHandle
ETapi
ecInvalCallHandle
ETapiInvalCallParams
ETapi
ecInvalCallParams
ETapiInvalCallPrivilege
ETapi
ecInvalCallPrivilege
ETapiInvalCallSelect
ETapi
ecInvalCallSelect
ETapiInvalCallState
ETapi
ecInvalCallState
ETapiInvalCallStatelist
ETapi
ecInvalCallStatelist
17
904 Chapter 18: Appendices
1
1
Ancestor
Error Code(s)
ETapiInvalCard
ETapi
ecInvalCard
ETapiInvalCompletionID
ETapi
ecInvalCompletionID
ETapiInvalConfCallHandle
ETapi
ecInvalConfCallHandle
ETapiInvalConsultCallHandle
ETapi
ecInvalConsultCallHandle
ETapiInvalCountryCode
ETapi
ecInvalCountryCode
ETapiInvalDeviceClass
ETapi
ecInvalDeviceClass
ETapiInvalDeviceHandle
ETapi
ecInvalDeviceHandle
ETapiInvalDialParams
ETapi
ecInvalDialParams
ETapiInvalDigitList
ETapi
ecInvalDigitList
ETapiInvalDigitMode
ETapi
ecInvalDigitMode
ETapiInvalDigits
ETapi
ecInvalDigits
ETapiInvalExtVersion
ETapi
ecInvalExtVersion
ETapiInvalFeature
ETapi
ecInvalFeature
ETapiInvalGroupID
ETapi
ecInvalGroupID
ETapiInvalLineHandle
ETapi
ecInvalLineHandle
ETapiInvalLineState
ETapi
ecInvalLineState
ETapiInvalLocation
ETapi
ecInvalLocation
ETapiInvalMediaList
ETapi
ecInvalMediaList
ETapiInvalMediaMode
ETapi
ecInvalMediaMode
ETapiInvalMessageID
ETapi
ecInvalMessageID
ETapiInvalParam
ETapi
ecInvalParam
ETapiInvalParkID
ETapi
ecInvalParkID
ETapiInvalParkMode
ETapi
ecInvalParkMode
ETapiInvalPointer
ETapi
ecInvalPointer
ETapiInvalPrivSelect
ETapi
ecInvalPrivSelect
ETapiInvalRate
ETapi
ecInvalRate
ETapiInvalRequestMode
ETapi
ecInvalRequestMode
ETapiInvalTerminalID
ETapi
ecInvalTerminalID
ETapiInvalTerminalMode
ETapi
ecInvalTerminalMode
18
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Ancestor
Error Code(s)
ETapiInvalTimeout
ETapi
ecInvalTimeout
ETapiInvalTone
ETapi
ecInvalTone
ETapiInvalToneList
ETapi
ecInvalToneList
ETapiInvalToneMode
ETapi
ecInvalToneMode
ETapiInvalTransferMode
ETapi
ecInvalTransferMode
ETapiLineMapperFailed
ETapi
ecLineMapperFailed
ETapiLoadFail
ETapi
ecTapiLoadFail
ETapiNoConference
ETapi
ecNoConference
ETapiNoDevice
ETapi
ecNoDevice
ETapiNoDriver
ETapi
ecNoDriver
ETapiNoMem
ETapi
ecNoMem
ETapiNoMultipleInstance
ETapi
ecNoMultipleInstance
ETapiNoRequest
ETapi
ecNoRequest
ETapiNoSelect
ETapi
ecTapiNoSelect
ETapiNotOwner
ETapi
ecNotOwner
ETapiNotRegistered
ETapi
ecNotRegistered
ETapiNotSet
ETapi
ecTapiNotSet
ETapiOperationFailed
ETapi
ecOperationFailed
ETapiOperationUnavail
ETapi
ecOperationUnavail
ETapiRateUnavail
ETapi
ecRateUnavail
ETapiReinit
ETapi
ecReinit
ETapiRequestOverrun
ETapi
ecRequestOverrun
ETapiResourceUnavail
ETapi
ecResourceUnavail
ETapiStructureTooSmall
ETapi
ecStructureTooSmall
ETapiTargetNotFound
ETapi
ecTargetNotFound
ETapiTargetSelf
ETapi
ecTargetSelf
ETapiTranslateFail
ETapi
ecTapiTranslateFail
ETapiUnexpected
ETapi
ecTapiUnexpected
ETapiUninitialized
ETapi
ecUninitialized
17
906 Chapter 18: Appendices
1
1
Ancestor
Error Code(s)
ETapiUserUserInfoTooBig
ETapi
ecUserUserInfoTooBig
ETapiVoiceNotSupported
ETapi
ecTapiVoiceNotSupported
ETapiWaveFail
ETapi
ecTapiWaveFail
ETimeout
EProtocol
ecTimeout
ETooManyErrors
EProtocol
ecTooManyErrors
ETracingNotEnabled
ESerialIO
ecTracingNotEnabled
ETriggerTooLong
ETrigger
ecTriggerTooLong
EUnpackAbort
EFax
ecUnpackAbort
As you can see, there is largely a one-to-one correspondence between exceptions and error
codes.
In some cases, Async Professional catches and either handles or re-raises standard VCL
exceptions. Examples include EOutOfMemory (when a memory allocation call fails),
EInOutError (when an attempt to open, read, or write a file fails), and EInvalidOperation
(when an improperly initialized form is used).
The ErrorMsg function of Async Professional (see page 895) can be used to generate an
English-language string for each error code. The strings are stored in a string table in
APW.RC, which has been compiled to APW.R32. This file is linked to your applications EXE
file so that the error message text is available to your application. The following table shows
the default string for each error code. These strings provide additional explanation of each
error.
The ErrorMsg function of Async Professional (see page 895) can be used to generate an
English-language string for each error code. The strings are stored in a string table in
APW.STR, which has been compiled to either APW.R16 (Delphi 1.0) or APW.R32 (32-bit
Delphi). The resources are then linked to your applications EXE file.
18
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
The Table 18.3 shows the default string for each error code. These strings provide additional
explanation of each error. The error codes are shown here as absolute values. Note that the
values may be positive or negative at different points during code execution.
Table 18.3: Error code default strings
Error Code
Value
Error Message
ecOK
OK
ecFileNotFound
ecPathNotFound
ecTooManyFiles
ecAccessDenied
ecInvalidHandle
ecOutOfMemory
Insufficient memory
ecInvalidDrive
15
Invalid drive
ecNoMoreFiles
18
No more files
ecDiskRead
100
ecDiskFull
101
Disk is full
ecNotAssigned
102
ecNotOpen
103
ecNotOpenInput
104
ecNotOpenOutput
105
ecWriteProtected
150
Disk is write-protected
ecUnknownUnit
151
ecDriveNotReady
152
ecUnknownCommand
153
Unknown command
ecCrcError
154
Data error
ecBadStructLen
155
ecSeekError
156
Seek error
ecUnknownMedia
157
ecSectorNotFound
158
ecOutOfPaper
159
ecDeviceWrite
160
17
908 Chapter 18: Appendices
1
1
Value
Error Message
ecDeviceRead
161
ecHardwareFailure
162
General failure
ecBadHandle
1001
ecBadArgument
1002
ecGotQuitMsg
1003
ecBufferTooBig
1004
ecPortNotAssigned
1005
ecInternal
1006
ecModemNotAssigned
1007
ecPhonebookNotAssigned
1008
ecCannotUseWithWinsock
1009
ecBadId
2001
ecBaudRate
2002
ecByteSize
2003
ecDefault
2004
ecHardware
2005
ecMemory
2006
ecCommNotOpen
2007
ecAlreadyOpen
2008
ecNoHandles
2009
ecNoTimers
2010
No timers available
ecNoPortSelected
2011
ecNullApi
3001
ecNotSupported
3002
ecRegisterHandlerFailed
3003
EnableCommNotification failed
ecPutBlockFail
3004
ecGetBlockFail
3005
18
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
18
2
3
4
5
6
7
8
9
10
Value
Error Message
ecOutputBufferTooSmall
3006
ecBufferIsEmpty
3007
Buffer is empty
ecTracingNotEnabled
3008
ecLoggingNotEnabled
3009
ecBaseAddressNotSet
3010
ecModemNotStarted
4001
ecModemBusy
4002
ecModemNotDialing
4003
ecNotDialing
4004
ecAlreadyDialing
4005
ecModemNotResponding
4006
ecModemRejectedCommand
4007
ecModemStatusMismatch
4008
ecNoMoreTriggers
5001
ecTriggerTooLong
5002
ecBadTriggerHandle
5003
ecStartStringEmpty
5501
ecPacketTooSmall
5502
ecNoEndCharCount
5503
ecEmptyEndString
5504
ecZeroSizePacket
5505
ecPacketTooLong
5506
ecBadFileList
6001
ecNoSearchMask
6002
ecNoMatchingFiles
6003
ecDirNotFound
6004
ecCancelRequested
6005
Cancel requested
11
12
13
14
15
16
17
910 Chapter 18: Appendices
1
1
Value
Error Message
ecTimeout
6006
ecProtocolError
6007
ecTooManyErrors
6008
ecSequenceError
6009
ecNoFilename
6010
ecFileRejected
6011
ecCantWriteFile
6012
ecTableFull
6013
ecAbortNoCarrier
6014
ecBadProtocolFunction
6015
ecKeyTooLong
7001
ecDataTooLarge
7002
ecNoFieldsDefined
7003
ecIniWrite
7004
ecIniRead
7005
ecNoIndexKey
7006
ecRecordExists
7007
ecRecordNotFound
7008
ecMustHaveIdxVal
7009
ecDatabaseFull
7010
ecDatabaseEmpty
7011
No records in database
ecDatabaseNotPrepared
7012
ecBadFieldList
7013
ecBadFieldForIndex
7014
ecFaxBadFormat
8001
ecBadGraphicsFormat
8002
ecConvertAbort
8003
ecUnpackAbort
8004
18
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Value
Error Message
ecCantMakeBitmap
8005
ecNoImageLoaded
8050
ecNoImageBlockMarked
8051
ecFontFileNotFound
8052
ecInvalidPageNumber
8053
ecBmpTooBig
8054
ecEnhFontTooBig
8055
ecFaxBadMachine
8060
ecFaxBadModemResult
8061
ecFaxTrainError
8062
ecFaxInitError
8063
ecFaxBusy
8064
ecFaxVoiceCall
8065
ecFaxDataCall
8066
ecFaxNoDialTone
8067
No dial tone
ecFaxNoCarrier
8068
ecFaxSessionError
8069
ecFaxPageError
8070
ecFaxGDIPrintError
8071
ecFaxMixedResolution
8072
ecFaxConverterInitFail
8073
ecUniAlreadyInstalled
8080
ecUniCannotGetSysDir
8081
ecUniCannotGetWinDir
8082
ecUniUnknownLayout
8083
ecUniCannotParseInfFile
8084
ecUniCannotInstallFile
8085
ecNotNTDriver
8086
ecDrvCopyError
8087
17
912 Chapter 18: Appendices
1
1
18
Error Code
Value
Error Message
ecCannotAddPrinter
8088
ecDrvBadResources
8089
ecDrvDriverNotFound
8090
ecUniCannotGetPrinterDir
8091
ecInstallDriverFailed
8092
ADWSERROR
9001
ADWSLOADERROR
9002
ADWSVERSIONERROR
9003
ADWSNOTINIT
9004
ADWSINVPORT
9005
ADWSCANTCHANGE
9006
ADWSCANTRESOLVE
9007
WSAEINTR
10004
WSAEBADF
10009
WSAEACCES
10013
Permission denied
WSAEFAULT
10014
Unknown error
WSAEINVAL
10022
Invalid argument
WSAEMFILE
10024
WSAEWOULDBLOCK
10035
WSAEINPROGRESS
10036
WSAEALREADY
10037
WSAENOTSOCK
10038
14
WSAEDESTADDRREQ
10039
15
WSAEMSGSIZE
10040
WSAEPROTOTYPE
10041
WSAEPROTOTYPE
2
3
4
6
7
8
9
10
11
12
13
16
17
1
1
18
Value
Error Message
WSAENOPROTOOPT
10042
WSAEPROTONOSUPPORT
10043
WSAESOCKTNOSUPPORT
10044
WSAEOPNOTSUPP
10045
WSAEPFNOSUPPORT
10046
WSAEAFNOSUPPORT
10047
WSAEADDRINUSE
10048
WSAEADDRNOTAVAIL
10049
WSAENETDOWN
10050
WSAENETUNREACH
10051
WSAENETRESET
10052
WSAECONNABORTED
10053
WSAECONNRESET
10054
12
WSAENOBUFS
10055
13
WSAEISCONN
10056
WSAENOTCONN
10057
WSAESHUTDOWN
10058
WSAETOOMANYREFS
10059
WSAETOOMANYREFS
WSAETIMEDOUT
10060
WSAECONNREFUSED
10061
WSAELOOP
10062
2
3
4
8
9
10
11
14
15
16
17
1
1
18
Error Code
Value
Error Message
WSAENAMETOOLONG
10063
WSAEHOSTDOWN
10064
WSAEHOSTUNREACH
10065
WSAENOTEMPTY
10066
WSAENOTEMPTY
WSAEPROCLIM
10067
WSAEPROCLIM
WSAEUSERS
10068
WSAEUSERS
WSAEDQUOT
10069
WSAEDQUOT
WSAESTALE
10070
WSAESTALE
WSAEREMOTE
10071
WSAEREMOTE
WSASYSNOTREADY
10091
WSAVERNOTSUPPORTED
10092
WSANOTINITIALISED
10093
WSAEDISCON
10101
WSAEDISCON
WSAHOST_NOT_FOUND
11001
WSATRY_AGAIN
11002
WSANO_RECOVERY
11003
WSANO_DATA
11004
WSANO_ADDRESS
11004
No address
ecAllocated
13801
Already allocated
ecBadDeviceID
13802
Bad device ID
ecBearerModeUnavail
13803
ecCallUnavail
13805
Call unavailable
ecCompletionOverrun
13806
Completion overrun
ecConferenceFull
13807
Conference full
ecDialBilling
13808
Dial failed
ecDialDialtone
13809
ecDialPrompt
13810
Dial failed
2
3
4
9
10
11
12
13
14
15
16
17
1
1
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Value
Error Message
ecDialQuiet
13811
Dial failed
ecIncompatibleApiVersion
13812
ecIncompatibleExtVersion
13813
ecIniFileCorrupt
13814
ecInUse
13815
Resource in use
ecInvalAddress
13816
Invalid address
ecInvalAddressID
13817
Invalid address ID
ecInvalAddressMode
13818
ecInvalAddressState
13819
ecInvalAppHandle
13820
ecInvalAppName
13821
ecInvalBearerMode
13822
ecInvalCallComplMode
13823
ecInvalCallHandle
13824
ecInvalCallParams
13825
ecInvalCallPrivilege
13826
ecInvalCallSelect
13827
ecInvalCallState
13828
ecInvalCallStatelist
13829
ecInvalCard
13830
Invalid card
ecInvalCompletionID
13831
Invalid completion ID
ecInvalConfCallHandle
13832
ecInvalConsultCallHandle
13833
ecInvalCountryCode
13834
ecInvalDeviceClass
13835
ecInvalDeviceHandle
13836
ecInvalDialParams
13837
ecInvalDigitList
13838
ecInvalDigitMode
13839
17
916 Chapter 18: Appendices
1
1
Value
Error Message
ecInvalDigits
13840
Invalid digits
ecInvalExtVersion
13841
ecInvalGroupID
13842
Invalid group ID
ecInvalLineHandle
13843
ecInvalLineState
13844
ecInvalLocation
13845
Invalid location
ecInvalMediaList
13846
ecInvalMediaMode
13847
ecInvalMessageID
13848
Invalid message ID
ecInvalParam
13850
Invalid parameter
ecInvalParkID
13851
Invalid park ID
ecInvalParkMode
13852
ecInvalPointer
13853
Invalid pointer
ecInvalPrivSelect
13854
ecInvalRate
13855
Invalid rate
ecInvalRequestMode
13856
ecInvalTerminalID
13857
Invalid terminal ID
ecInvalTerminalMode
13858
ecInvalTimeout
13859
Invalid timeout
ecInvalTone
13860
Invalid tone
ecInvalToneList
13861
ecInvalToneMode
13862
ecInvalTransferMode
13863
ecLineMapperFailed
13864
ecNoConference
13865
No conference
ecNoDevice
13866
No device
ecNoDriver
13867
No driver
ecNoMem
13868
No memory
ecNoRequest
13869
No request
18
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
1
1
18
2
3
4
5
6
7
8
9
10
Value
Error Message
ecNotOwner
13870
Not owner
ecNotRegistered
13871
Not registered
ecOperationFailed
13872
Operation failed
ecOperationUnavail
13873
Operation unavailable
ecRateUnavail
13874
Rate unavailable
ecResourceUnavail
13875
Resource unavailable
ecRequestOverrun
13876
Request overrun
ecStructureTooSmall
13877
ecTargetNotFound
13878
ecTargetSelf
13879
Target is self
ecUninitialized
13880
Uninitialized
ecUserUserInfoTooBig
13881
ecReinit
13882
Reinit failed
ecAddressBlocked
13883
Address blocked
ecBillingRejected
13884
Billing rejected
ecInvalFeature
13885
Invalid feature
ecNoMultipleInstance
13886
No multiple instance
ecTapiBusy
13928
ecTapiNotSet
13929
ecTapiNoSelect
13930
ecTapiLoadFail
13931
ecTapiGetAddrFail
13932
ecTapi16Disabled
13933
ecTapiUnexpected
13934
ecTapiVoiceNotSupported
13935
ecTapiWaveFail
13936
ecTapiCIDBlocked
13937
Caller ID blocked
ecTapiCIDOutOfArea
13938
ecTapiWaveFormatError
13939
11
12
13
14
15
16
17
1
1
Value
Error Message
ecTapiWaveReadError
13940
ecTapiWaveBadFormat
13941
ecTapiTranslateFail
13942
ecTapiWaveDeviceInUse
13943
ecTapiWaveFileExists
13944
ecTapiWaveNoData
13945
18
2
3
4
The ie_ designations refer to error codes returned by the Windows communications API.
All of the Async Professional error codes are defined in numeric order in the source file
OOMISC.PAS. All of the exception classes are declared in ADEXCEPT.PAS.
6
7
8
9
10
11
12
13
14
15
16
17
1
1
18
Conditional Defines
Before using Async Professional, you need to understand and perhaps modify various
conditional defines in AWDEFINE.INC. This file is included into all Async Professional
units. To modify it, load it into a text editor and find the appropriate conditional symbol.
Insert a period between the { and the $ of a conditional define to deactivate it. With the
period in place, the compiler sees the line as a plain comment, which has no effect on
compilation.
After modifying AWDEFINE.INC, save it to disk and use the compiler to rebuild all affected
files. To be sure the library is rebuilt properly follow these steps:
1. Delete all *.OBJ, *.HPP, and *.DCU files in the \ASYNCPRO directory. Be careful not
to delete any other files.
2
3
3. After modifying AWDEFINE.INC, save it to disk and use the compiler to rebuild all
affected files.
The following paragraphs describe the options that can be controlled through
AWDEFINE.INC. The default state of each define is also shown.
{.$DEFINE EnableTapi16}
10
11
12
13
14
15
This define enables TAPI components in 16-bit applications. Typically TAPI cant be used in
16-bit environments due to a lack of service providers (notably, the lack of UNIMDM.TSP)
in Windows 3.XX, and due to a bug in Windows 95 that prevents obtaining a 16-bit comm
handle to a TAPI port. Therefore this define is off by default. You can enable it to use TAPI in
16-bit environments, but only if you are certain that environment properly supports TAPI.
{.$DEFINE Prot16OpenStrings}
This define activates an Async Professional 1.0 behavior for Async Professional 2.0
programs. When this define is active, Async Professional 2.0 uses OpenString (the same
type used by Async Professional 1.0) for string parameters passed in the TApdProtocol
component OnProtocolNextFile and OnProtocolAccept events. When this define is not
active, Async Professional 2.0 uses TPassString for those events. This define is off by default
and is intended only to provide backward compatibility with existing Async Professional 1.0
programs.
16
17
920 Chapter 18: Appendices
1
1
18
Glossary
This glossary contains a combination of industry accepted definitions and, where noted,
definitions that are unique to Async Professional.
ANSI
6
7
8
9
10
11
12
Bell 212A
The AT&T modem standard for asynchronous communication at speeds up to 1200 bps on
dial-up telephone lines.
13
bps
14
Bits per second, a measure of raw communications speed, which quantifies how fast the bits
within a character are being transmitted or received. It is not a measure of overall
throughput, but rather a measure of the speed with which a single character can be
processed.
15
16
17
Glossary 921
1
1
18
2
break
A signal that can be transmitted or received over serial communication links. A break is not
a character, but rather a condition in which the serial line is held in the 0 state for a least
one character-time.
client
3
4
5
6
7
8
9
10
11
12
13
This term is used to mean the amount of time between the start bit and stop bit of a serial
byte (inclusive). This is the smallest period of time between successive received or
transmitted characters (of course, the elapsed time between characters can be longer than
one character-time).
checksum
A byte, or bytes, appended to the end of a block of data that is used to check the integrity of
that block. A checksum is the sum of all the bytes in the block.
comport
In this manual, refers to a TApdComport component, or a component derived from
TApdCustomComport (such as TApdWinsockPort). This convention is used to reduce
confusion between the physical port and the comport component. Outside of Async
Professionals documentation, it is not uncommon to see comport, com port and serial
port being used synonymously.
COMM.DRV
The Windows device driver that performs all of the low-level work required to send and
receive using the PCs UART chip in 16-bit Windows.
CRC
14
15
A byte, or bytes, appended to the end of a block of data that is used to check the integrity of
the data. CRC is short for cyclical redundancy check, a data checking algorithm that
provides a much higher level of protection than a simple checksum.
16
17
922 Chapter 18: Appendices
1
1
CTS
Clear to send. This is a modem control signal that is raised by the modem when it is ready to
accept characters. The modem may lower this line when it cannot accept any more
characters (this usually means that its receive buffer is nearly full). This behavior is called
hardware handshaking or hardware flow control.
18
2
data bits
The bits in a serial stream of data that hold data as opposed to control information. The
number of data bits is one of the line parameters needed to describe a serial port
configuration. The acceptable values are 5 through 8.
data compression
Refers to the ability of some modems to compress data before passing it to the remote
modem. There are two standards that describe data compression methods, MNP and
V.42bis.
DCB
Device control block. A structure passed from a Windows program to the communications
driver. It contains the line parameters and other configuration information that the
communication driver uses to configure the UART.
6
7
8
DCD
Data carrier detect. A signal provided by a modem to indicate that it is currently connected
to a remote modem.
9
10
DCE
Data communications equipment. Generally, this refers to a modem.
device layer
11
This layer of Async Professional provides the physical connection between the software and
the hardware.
12
DNS
A remote database that contains a list of host names and their corresponding IP addresses.
dot notation
13
14
15
16
17
Glossary 923
1
1
18
DTR
Data terminal ready. This is a modem control signal raised by a UART to notify the remote
(usually a modem) that it is active and ready to transmit.
error correction
Refers to the ability of some modems to check the integrity of data received from a remote
modem. There are two standards that describe error correction protocols, MNP and V.42.
4
5
6
7
8
9
10
11
FIFO mode
A mode of operation for 16550 UARTs that takes advantage of the UARTs first-in-first-out
buffers.
flow control
A facility that allows either side of a serial communication link to request a temporary pause
in data transfer. Typically, such pauses are required when data is being transferred faster
than the receiver can process it. Hardware flow control is implemented via changes in the
CTS and RTS signals. Software flow control is implemented via the exchange of XOn and
XOff characters.
full duplex
1. A mode of communication in which the receiving computer automatically echoes all data
it receives back to the transmitter. 2. A communications link that can pass data both
directions (receive and transmit) at the same time.
half duplex
1. A mode of communication in which the receiving computer does not echo any data back
to the transmitter. 2. A communications link that can pass data in only one direction at a
time.
handshaking
12
13
Refers to the initial transfers of data between two processes. Usually this term is used to
describe the start of a protocol file transfer or the exchange of data that occurs when two
modems first connect.
host name
14
15
The layer of Async Professional that contains the majority of the applications programming
interface (API). This layer is implemented by the TApdComPort component.
16
IP address
The 32-bit address of a network computer. All IP addresses are unique.
17
924 Chapter 18: Appendices
1
1
IRQ
One of the lines on the PC or PS/2 bus that is used to request a hardware interrupt. Any
device that needs to interrupt the CPU (such as a UART) does so via an IRQ line.
18
ITU-TSS
LAP M
An error-correction protocol included with the most recent CCITT communications
standard V.42.
line error
Refers to one of the following errors: UART overrun, parity error, or framing error. Such
errors are due either to interference picked up by the physical connection (cable, phone line,
etc.) or to a mismatch in line parameters between the two ends of a serial link.
lookup
An action that Winsock performs to retrieve the IP address for a host name, or to retrieve
the port number for a service name (and vice versa).
MNP
Microcom Networking Protocol. A communications protocol designed by Microcom, Inc.
and placed in the public domain. MNP defines several service levels that provide error
control and data compression facilities between two modems. MNP is of interest only if you
are using modems that support it. See the modem manual for more information about the
details of MNP.
9
10
modem
11
A device that facilitates serial communication over phone lines. The term is derived from the
phrase MOdulation/DEModulation device.
12
13
14
parity
A bit that is used to check the integrity of a byte. The parity bit is set by the transmitter and
checked by the receiver. If present, the parity bit is set so that the sum of the bits in the
character is always odd or always even. The parity bit can also be set to a constant value
(always on or always off).
15
16
17
Glossary 925
1
1
18
2
3
4
port (Winsock)
A number from 0 to 32767 that, along with the IP address, is used to create a socket.
protocol
Generally, an agreed upon set of rules that both sides of a communications link follow. This
term crops up in two places in Async Professional: file transfer protocols and modem
protocols. A file transfer protocol is a set of rules that two computers use to transfer one or
more files. A modem protocol describes the modulation technique as well as the error
control and data compression rules.
remote device
5
6
7
8
9
10
11
12
13
14
In Async Professional this term is used to describe whats attached to your serial port. Since
it can be another PC, a different kind of computer, a modem, an instrument, or another
device, we often just say remote or remote device.
RI
Ring indicator. A signal provided by the modem to indicate that a call is coming in (i.e., the
phone is ringing).
RS-232
An EIA (Electronic Industries Association) standard that provides a physical description
(voltages, connectors, pin names, and purposes) of a serial asynchronous communications
link. This is the standard used by the IBM PCs Asynchronous Communications Adapter
(and compatibles). The original intent of RS-232 was to describe the link between a
computer and a modem. However, many devices other than modems (printers, plotters,
laboratory instruments, and so on) have adopted some of the conventions of RS-232.
RTS
Request to send. This is a modem control signal that the UART uses to tell the modem that it
is ready to receive data.
S-registers
A register in a Hayes-compatible modem that stores configuration information. Lower
numbered S-registers are somewhat standardized, but higher numbered S-registers are
generally used for different purposes by different modem manufacturers.
serial data
15
Refers to data transmitted over a single wire where bits are represented as either high or low
signals over a specified period of time. This is in contrast to parallel data, where each bit is
represented by its own wire.
16
server
An application that listens on a socket for client connection attempts.
17
926 Chapter 18: Appendices
1
1
socket
A Windows object that is created using a combination of an IP address and port number. A
socket is used to make a network connection between two computers.
18
start bit
The bit in a serial stream that indicates a data byte follows. This value cannot be changed;
UART communications always uses one start bit.
stop bits
The bits in a serial stream that indicate all data bits were sent. One or two stop bits can be
used. The number of stop bits is one of the line parameters needed to describe a serial link.
streaming protocol
A file transfer protocol that doesnt require an acknowledgement for each block. Such
protocols are usually much faster than non-streaming protocols because the transmitter
never pauses to wait for an acknowledgement.
Telnet
terminal emulator
Software that interprets special sequences of characters as video control information (for
setting colors, positioning the cursor, etc.) rather than data. This process is referred to as
emulation because it emulates the behavior built into serial terminals (such as the DEC
VT100 terminal).
terminal
A device (or software) that displays received data to a CRT and transmits keyboard
characters to a host computer. A dumb terminal is one that does no local processing of the
data it receives from the host. A smart terminal is capable of interpreting special escape
sequences, allowing the host to move the terminals cursor, change the colors used to
display text, etc.
9
10
11
12
13
trigger
An Async Professional term describing an event or condition noted by the internal
dispatcher and passed to an application through a VCL event handler.
14
UART
15
An acronym for Universal Asynchronous Receiver Transmitter. This is the device (usually
one integrated circuit) that serializes and deserializes data between the CPU and the serial
data line.
16
17
Glossary 927
1
1
18
2
3
V.17
CCITT 7200, 9600, 12000, and 14400 bps faxmodem standard.
V.21
CCITT 300 bps faxmodem standard.
V.22
CCITT 1200 bps modem standard.
V.22bis
CCITT 2400 bps modem standard.
V.25bis
8
9
10
11
12
13
14
15
V.34
CCITT 28800 bps communication standard which describes a standard modem
modulation technique. V.34 includes several advanced features designed to get as much
performance as possible out of a given telephone connection. The top speed of 28800 bps
occurs only under optimal conditions; normal telephone conditions usually yield lower
throughput, but still substantially higher than V.32.
V.42
CCITT error correcting protocol standard. Includes both MNP-4 and LAP-M error
correction protocols.
16
17
928 Chapter 18: Appendices
1
1
V.42bis
CCITT 4:1 data compression protocol. This data compression scheme generally achieves a
much higher degree of compression than is possible with MNP.
18
V.FC/V.Fast
An early unratified version of the V.34 specification. V.34 modems can usually connect to
V.FC and V.Fast modems, but usually at lower rates than with other V.34 modems.
3
4
6
7
8
9
10
11
12
13
14
15
16
17
Glossary 929
1
1
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
930 Chapter 18: Appendices
1
1
Async Professional provides another auditing tool called dispatch logging, which works at a
much lower level than tracing. Dispatch logging provides an exact chronology (with
millisecond timestamps) of all events processed by the internal dispatcher. Its handy for
figuring out problems with hardware flow control and other control signal situations (e.g.,
why isnt my program answering a ringing phone?). See page 33 for more information on
this facility.
18
2
3
6
7
8
9
10
11
12
13
14
15
16
17
1
1
18
Common problems
Heres a brief discussion of some of the common problems that popped up during
development and testing of Async Professional. They are organized in a question and
answer format.
Nothing works, not even the supplied test programs. Whats wrong?
Probably a hardware or cabling problem that youll need to figure out before you go any
further. Common problems are two or more UARTs using the same IRQ, another board
(e.g., a mouse or network board) using a serial port IRQ, or two or more UARTs using the
same I/O address.
5
6
7
8
9
Another possibility is misnamed ports if there is a gap in the serial ports in your machine.
For example, if your machine has serial ports COM1, COM2, and COM4, Windows names
these ports COM1, COM2, and COM3. If a Windows communication program attempts to
open COM4, it will fail since Windows doesnt recognize that COM4 exists.
The simplest solution to this problem is to accept the Windows name for the port and add
appropriate COMXBASE and COMXIRQ statements to SYSTEM.INI to reflect the actual
hardware configuration. To make Windows use COM3 in the above example, you would add
COM3BASE = 2E8
COM3IRQ = 4
to SYSTEM.INI.
10
11
A UART overrun occurs when a character is received at the serial port before the Windows
communications driver has a chance to process the previous character. That is, characters
are coming too fast for the driver to handle them.
12
13
14
15
16
There is a finite limit to the speed at which a given machine can receive data. Because of the
extra layers of overhead in Windows, this limit is substantially lower than under DOS. A
baud rate that worked under DOS simply may not be achievable under Windows.
A more likely cause, however, is that another Windows task is leaving interrupts off for too
long. While interrupts are off, the communications driver isnt notified of incoming
characters. If interrupts are left off for more than one character-time, its very likely that you
will lose characters due to UART overruns.
One known cause of long interrupts-off time is virtual machine creation and destruction.
The only solution is to avoid opening or closing DOS boxes during critical communication
processes.
Interrupts could also be left off by other Windows device drivers or virtual device drivers.
17
932 Chapter 18: Appendices
1
1
18
2
3
My Zmodem file transfer program generates lots of psBlockCheckError errors and psLongPacket errors, but other protocols work fine. Whats going on?
The answer in this case is almost always lack of hardware flow control. The problem shows
up in Zmodem but not other protocols because Zmodem is a streaming protocol. Data is
sent in a continuous stream without pauses for acknowledgements. Flow control is required
to prevent the sender from overflowing the modem or the receiver. And remember, flow
control must be enabled at four places: your software, your modem, the remote software,
and the remote modem. Consult your modem manual for the hardware flow control enable
command for your modem.
6
7
8
9
10
11
12
13
14
15
16
17
1
1
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
934 Chapter 18: Appendices
1
1
Identifier Index
AsciiCharDelay 527
AsciiCRTranslation 527
AsciiEOFTimeout 528
AsciiEOLChar 528
AsciiLFTranslation 529
AsciiLineDelay 529
AsciiSuppressCtrlZ 529
AskAreaCode 352
AskForDate 360
AskForDateEx 360
AskForExtension 361
AskForExtensionEx 362
AskForList 362
AskForListEx 363
AskForPhoneNumber 363
AskForPhoneNumberEx 364
AskForSpelling 365
AskForSpellingEx 365
AskForTime 366
AskForTimeEx 366
AskForYesNo 367
AskForYesNoEx 367
AskLastFour 352
AskNextThree 353
asXxx 631, 657
Attempt 409
Attributes 277
AudioInDevice 302
AudioOutDevice 302
AutoAnswer 410, 464
AutoEnable 138
AutoOpen 52
AutoRepeat 266
AutoScaleMode 631, 657
AvailableTerminalDevices 302
AvgWaveInAmplitude 410
Identifier Index
Abort 562
AbortNoCarrier 526
AbortNoConnect 717, 845
AcceptDragged 656
AcceptSocket 117
Account 562
ActivateDeviceLayer 49
Active 181, 276
ActiveColor 181
ActivePage 656
ActualBPS 526
Add 241, 248
AddDataTrigger 49
AddFaxRecipient 816
AddMessage 876
AddModem 457
AddRecipient 770
Address 104, 873
AddStatusTrigger 50
AddTimerTrigger 51
AddTraceEntry 52
AdXxx 4
aetXxx 520, 527, 529
Age 315
ANSIMode 265
AnswerOnRing 409, 464, 758, 781
apFirstCall 489
ApiVersion 409
apLastCall 489
AppKeyMode 265
AppKeypadMode 265
AproReg 6
APW_XXX 70
Argument 230, 235
ArgumentCount 230
Identifier Index
10
11
14
12
15
13
16
17
1
i
15
12
16
13
CallBackNumber 374
CallerID 412
CallerIDName 412
CallInfo 303
Cancel 173
CancelCall 303, 413, 465, 845
CancelFax 717, 782
Cancelled 413
CancelProtocol 533
CancelRecipient 771
CancelScript 157
Identifier Index
Identifier Index
14
11
10
17
1
1
ii Identifier Index
Capacity 876
Caption 480, 680
Capture 278
CaptureFile 279
ChangeDir 563
CharHeight 280
CharReady 54
CharSet 205, 280, 338
CharSetMapping 256
CharWidth 281
CheckLoaded 118
Clear 231, 241, 249, 281, 876
ClearAll 282
ClearAllHorzTabStops 205
ClearAllVertTabStops 206
ClearHorzTabStop 206
ClearVertTabStop 206
CloseFile 604
CloseSocket 118
Col 206
Col132Mode 266
ColCount 207
Columns 282
Command 231
CommDelay 857
ComName 895
ComNumber 55
ComPort 138, 157, 173, 193, 283, 413, 466,
533, 718, 783, 879
CompressionMode 374
CompressRasterLine 604
ConcatFax 771
ConcatFaxes 744
Conditions 182
ConfigAndOpen 414, 466
Connect 304, 879
Connected 304, 563, 879
Connection 374
ConnectSocket 118
ConnectState 374
ConnectTimeout 563
ConstantStatus 758, 783
Data 174
DataBits 56
DataSize 174
DataString 174
DCD 56
DCDLight 191
DCDMask 68
dcXxx 299
DefBackColor 207
DefCharSet 208
DefForeColor 208
Identifier Index
DefUserExtension 608
DelayBetweenSends 785
DelayTicks 890
Delete 564, 876
DeleteChars 208
DeleteFailed 584
DeleteLines 208
DeleteModem 458
DeleteModemRecord 458
DeletePhonebookEntry 375
DeltaCTS 56
DeltaCTSMask 68
DeltaDCD 57
DeltaDCDMask 68
DeltaDSR 57
DeltaDSRMask 68
DeltaRI 57
DeltaRIMask 68
Description 119
DesiredBPS 719, 785
DesiredECM 720, 785
DestinationDir 759, 786
DestinationDirectory 533
Destroy 284
DestroyDisplay 441, 580, 691, 824
DestroyWnd 284
DetectBusy 745
DeviceClass 299
DeviceCount 415
DeviceInUse 299
DeviceLayer 58, 109
DeviceName 300, 375
DeviceType 376
deXxx 841
dfXxx 584
Dial 376, 415, 467
DialAttempt 745, 786, 846
DialAttempts 746, 786, 846
DialDlg 377
Dialect 316, 325
Dialing 416
DialMode 377
Identifier Index
Convert 605
ConvertBitmapToFile 607
ConvertCover 744
ConvertToFile 607
CopyCallInfo 415
CopyToClipboard 283, 659
Count 241, 249, 315, 325
CoverFile 744
CoverFileName 816
coXxx 619
Create 207, 231, 283
CreateDisplay 441, 580, 691, 824
CreateNewDetailFile 457
CreatePhonebookEntry 375
CreateSocket 119
CreateWnd 284
CTS 55
CTSLight 191
CTSMask 68
CurrentEngine 325
CurrentJobName 783
CurrentJobNumber 784
CurrentPage 719, 784
CurrentPrintingPage 680
CurrentRecipient 784
CurrentState 174
CurrentVoice 316
10
11
14
12
15
13
16
17
1
1
Identifier Index
Identifier Index
10
14
11
15
12
16
13
17
DialOptions 378
DialPrefix 746, 787, 846
DialRetryWait 746, 847
DialStatusMsg 847
DialTimeout 467
DialWait 747, 787, 847
Dictation 338
Disconnect 848
Display 441, 580, 691, 824
DisplayToTerminal 157
dlXxx 58, 109
DoBackHorzTab 209
DoBackspace 209
DoBackVertTab 209
DoCarriageReturn 209
DocName 835
DocumentFile 608
DoHorzTab 210
DoLineFeed 210
Domain 378
DoVertTab 210
DSR 58
DSRLight 191
DSRMask 68
dsXxx 842
DTR 59
E
ecXxx 706, 901
EditPhonebookEntry 378
ElapsedTicks 534
ElapsedTime 890
ElapsedTimeInSecs 891
Emulator 284
Enabled 138
EnableVoice 417
EndCond 139
EndString 140
EndUpdate 659
EngineFeatures 316, 326
1
iv Identifier Index
F
FailureCode 468
FailureCodeMsg 468
Fax 824, 829
FaxAndData 759
FaxClass 721, 789
FaxFile 721, 789
FaxFileExt 721, 789
FaxFileList 748
FaxFileName 816
FaxFooter 680
FaxHeader 681
FaxHistoryName 829
FaxLog 722, 790
FaxNameMode 760, 790
FaxPrinter 691, 696, 790
Gender 320
GenDevConfig 419
GenerateDrawScript 249
Get 242
GetBlock 61
GetChar 62
GetCharAttrs 213
Identifier Index
GetCursorPos 257
GetDefCharAttrs 213
GetDevConfig 468
GetDialParameters 379
GetErrorText 379
GetInvalidRect 214
GetJob 810
GetJobHeader 773
GetLineAttrPtr 214
GetLineBackColorPtr 215
GetLineCharPtr 215
GetLineCharSetPtr 215
GetLineForeColorPtr 215
GetModem 458
GetModems 459
GetNextDrawCommand 250
GetNextFax 810
GetRasterLine 610
GetRecipient 774
GetSchedTime 811
GetStatusText 379
Glyph 182, 189
GlyphCells 183
GPOMode 266
Grammars 328
GSMState 881
gsXxx 881
Identifier Index
FaxPrinterLog 681
FaxProgress 722, 791
FaxResolution 632, 682
FaxWidth 633, 682
fcXxx 59, 721, 734, 789
Features 317, 326
ffXxx 610
FGColor 659
FileDate 535
FileLength 536, 564
FileMask 536
FileName 536, 660, 682, 835
FileType 565
FilterUnsupportedDevices 419
Find 318
FinishWait 537
FirstPage 660
FirstPageToPrint 683
FlowState 59
FlushInBuffer 60
FlushOutBuffer 60
fnXxx 755, 760
FontFile 609
FontType 610
ForceSendQuery 791
ForeColor 212, 285
fpXxx 709
frXxx 621, 632, 682
FtpLog 565
fwXxx 633, 682
fwXxx (fax converter) 623
10
11
14
12
15
HalfDuplex 286
Handle 119
HandshakeRetry 538
HandshakeWait 538
Hangup 380
HangupCode 722, 791
HangupOnDestroy 380
HasCursorMoved 216
HasDisplayChanged 216
HeaderLine 748, 816
HeaderRecipient 749, 817
13
16
17
1
Identifier Index v
Identifier Index
Identifier Index
10
14
11
15
12
16
13
17
HeaderSender 749
HeaderTitle 750, 817
Help 353, 566
Help2 353
HighVersion 119
HistoryName 584, 864
HonorDirectory 538
HorizDiv 633, 661
HorizMult 634, 661
HorizScroll 661
htonl 120
htons 120
HWFlowOptions 62
hwXxx 62
I
idXxx 608, 611
IgnoreCase 140
InactiveColor 183
InBuffFree 63
InBuffUsed 64
IncludeDirectory 539
IncludeStrings 140
InFileName 634
InitBaud 724, 793
InitialPosition 539
InitModemForFaxReceive 760
InProgress 158, 540, 566
InputDocumentType 611
InsertLines 216
InSize 64
Interfaces 320, 329
Interlace 266
InterruptWave 420
InVT52Mode 236
itXxx 339
J
1
JobFileExt 811
1
vi Identifier Index
JobFileName 818
JobName 818
K
KermitCtlPrefix 540
KermitHighbitPrefix 540
KermitLongBlocks 541
KermitMaxLen 541
KermitMaxWindows 541
KermitPadCharacter 542
KermitPadCount 542
KermitRepeatPrefix 542
KermitSWCTurnDelay 543
KermitTerminator 543
KermitTimeoutSecs 544
KermitWindowsTotal 544
KermitWindowsUsed 544
KeyboardMapping 257
KeyDown 258
KeyPress 258
L
LanguageID 321, 329
LastError 120
LastErrorCode 175
LastPage 662
LastPageToPrint 683
LazyByteDelay 286
LazyPaint 259
LazyTimeDelay 286
lcXxx 684, 696, 697
LEDs 267
LeftMargin 613
leXxx 65
lfaxXxx 713, 729
lfXxx 547
Lights 193
Line 287
LineBreak 64
Main 354
Main2 354
MakeDir 568
MakeEndOfPage 614
MakeFaxJob 818
MakeJob 775
MaxAttempts 420
MaxMessageLength 420, 848
MaxSendCount 750, 794
MaxSockets 124
MaxWordsState 329
Identifier Index
MaxWordsVocab 330
mdXxx 300
MediaDirection 300
MediaType 300
Message 840, 848, 873
MessageIndex 873
Messages 877
MessageStore 882
MfgName 321, 330
mlXxx 474
ModeID 321, 330
ModemBPS 725, 795
ModemCapFolder 459, 469
ModemChip 726, 795
ModemECM 726, 795
ModemInit 726, 796, 849
ModemLogToString 469
ModemModel 727, 796
ModemRevision 727, 796
ModemState 469
ModemStatus 68
ModeName 322, 331
MonitorDir 811
MonitorDlg 381
Monitoring 194, 797
MoveCursorDown 217
MoveCursorLeft 217
MoveCursorRight 217
MoveCursorUp 218
msXxx 88, 470
MultiPage 683
Identifier Index
LineError 65
LinesPerPage 613
ListConnections 380
ListDir 566
Listen 338
ListenSocket 121
ListEntries 381
Lit 189
LitColor 189
LoadFromFile 242, 250
LoadFromRes 243, 252
LoadWholeFax 662
LocalAddress 121
LocalHost 121
LogFileName 696
Logging 66
LogHex 67
Login 567
LogName 67
Logout 568
LogSize 67
LookupAddress 122
LookupName 122
LookupPort 123
LookupService 124
lsXxx 89
ltapiXxx 399, 446
10
11
14
12
15
13
16
17
NeedsUpdate 259
NegotiationResponses 470
NetAddr2String 124
NewLineMode 267
NewTimer 891
NewTimerSecs 892
NextPage 663
1
Identifier Index vii
Identifier Index
NoAnswerMax 368
NoAnswerTime 368
NormalBaud 727, 797
NotifyOnNewMessage 882
NotLitColor 190
ntohl 125
ntohs 125
Number 421
NumDigits 368
NumPages 635, 663
Identifier Index
10
14
11
15
12
16
13
17
OnCloseUserFile 614
OnConnect 304
OnConnected 382
OnDialError 382, 849
OnDialStatus 383, 850
OnDisconnect 305
OnDisconnected 383
OnDocEnd 835
OnDocStart 836
OnDropFile 664
OneFax 761
OnFail 305
OnFaxAccept 761
OnFaxError 728
OnFaxFinish 728
OnFaxLog 729
OnFaxName 762
OnFaxNext 751
OnFaxPrintLog 684
OnFaxPrintStatus 684
OnFaxServerAccept 797
OnFaxServerFatalError 798
OnFaxServerFinish 799
OnFaxServerLog 799
OnFaxServerName 800
OnFaxServerPortOpenClose 800
OnFaxServerStatus 800
OnFaxStatus 729
1
viii Identifier Index
OnFtpError 568
OnFtpLog 569
OnFtpReply 569
OnFtpStatus 569
OnGSMComplete 882
OnIncomingCall 306
OnInterference 339
OnLogin 857
OnLogout 857
OnModemCallerID 471
OnModemConnect 472
OnModemDisconnect 472
OnModemFail 473
OnModemLog 473
OnModemStatus 474
OnNewMessage 883
OnNextMessage 883
OnNextPage 685
OnOpenUserFile 615
OnOutputLine 616, 635
OnPacket 141
OnPageChange 665
OnPhraseFinish 340
OnPhraseHypothesis 340
OnProtocolAccept 545
OnProtocolError 545
OnProtocolFinish 546
OnProtocolLog 546
OnProtocolNextFile 547
OnProtocolStatus 548
OnReadUserLine 617
OnScriptCommandFinish 158
OnScriptCommandStart 159
OnScriptDisplay 159
OnScriptFinish 160
OnScriptParseVariable 160
OnScriptUserFunction 161
OnSNPPError 858
OnSNPPSuccess 858
OnSpeakStart 340
OnSpeakStop 340
OnSRError 341
Identifier Index
P
PacketSize 142
PageBitmaps 666
PageHeight 667
PageLength 730, 801
Pager 864
PagerID 840
PagerLog 851
PageWidth 667
Paint 260
Parity 82
Parser 260
Password 104, 383, 571
Paused 813
PauseListening 343
PauseSpeaking 343
Phonebook 384
PhonebookDlg 384
PhoneNumber 384, 752, 819, 851
PlatformID 385
PlayWaveFile 427
Port 104, 852, 858
ppXxx 685, 686
PrepareConnectInProgress 762
PrepareScript 161
PrevPage 667
PrintAbort 685
Identifier Index
OnSRWarning 341
OnSSAttributeChanged 341
OnSSError 342
OnSSWarning 342
OnStateActivate 184
OnStateChange 175
OnStateFinish 184
OnStateMachineFinish 176
OnStatus 617, 636
OnStringPacket 142
OnTAPFinish 850
OnTapiCallerID 422
OnTapiConnect 422
OnTapiDTMF 423
OnTapiFail 423
OnTapiLog 424
OnTapiPortClose 424
OnTapiPortOpen 425
OnTapiStatus 425
OnTapiWaveNotify 426
OnTapiWaveSilence 427
OnTAPStatus 842, 851
OnTimeout 141
OnTrainingRequested 342
OnTrigger 26, 69
OnTriggerAvail 71
OnTriggerData 73
OnTriggerLineError 73
OnTriggerModemStatus 74
OnTriggerOutbuffFree 75
OnTriggerOutbuffUsed 76
OnTriggerOutSent 77
OnTriggerStatus 25, 78
OnTriggerTimer 79
OnViewerError 665
OnVUMeter 343
OnWsAccept 109, 126
OnWsConnect 110, 126
OnWsDisconnect 111, 126
OnWsError 111, 127, 571
OnWsRead 127
OnWsWrite 127
10
11
14
12
15
13
16
17
1
Identifier Index ix
ReplyCode 572
ReSend 852
Reset 219
Resolution 621
RestartAt 572
ResumeListening 343
ResumeSpeaking 344
Retrieve 572
RetryWait 428
RevScreenMode 268
RI 86
RIMask 68
RingCount 474
RINGLight 191
RingOffTimeout 194
RingWaitTimeout 475
Rotation 668
Row 219
RowCount 219
Rows 287
RS485Mode 86
RTS 86
RTSLowForWrite 550
RXDLight 191
RXDOffTimeout 194
15
12
QuickConnect 884
16
13
17
ReadSocket 127
Recipient 820
RelOriginMode 267
RemainingTime 892
RemainingTimeInSecs 892
RemoteID 730, 802
RemoveAllTriggers 85
RemoveTrigger 85
Rename 571
Identifier Index
Identifier Index
PrintFax 686
PrintOnReceive 801
PrintProgress 686
PrintScale 687
PrintSetup 687
ProcessChar 232, 236
ProcessCommunications 82
ProcessWideChar 233
ProductName 322, 331
PromptForPort 83
Prompts 369
Protocol 162, 580, 585
ProtocolError 549
ProtocolLog 549
ProtocolName 897
ProtocolStatus 549
ProtocolType 550
prXxx 356
psXxx 369, 491, 687, 842
ptXxx 550
ptXxx (protocol type) 897
PutBlock 84
PutChar 84
PutString 84
pXxx 82
10
14
11
1
1
x Identifier Index
ShowConfigDialogEdit 431
ShowFaxJobInfoDialog 778
ShowGeneralDlg 344
ShowLexiconDlg 344
ShowMediaSelectDialog 306
ShowPorts 431
ShowTapiDevices 432
ShowTrainGeneralDlg 345
ShowTrainMicDlg 345
SilenceThreshold 432
SmoothScrollMode 268
SMSAddress 885
smXxx 575
SocksVersion 104
SoftwareFlow 732, 805
Speak 345, 369
Speaker 322
SpeakerMode 385
SpeakFile 346
SpeakFileToFile 347
SpeakStream 347
SpeakToFile 348
SRAmplitude 349
SRAutoGain 349
SREngines 338, 349
SSVoices 349
ssXxx 332, 866, 874
Start 176
StartCond 143
Started 480
StartManualReceive 762
StartManualTransmit 752
StartReceive 551, 763
StartScript 163
StartState 176
StartString 143
StartTransmit 551, 753
StartWaveRecord 432
StateNames 177
StationID 621, 733, 805
Status 574, 874
StatusDialog 481
Identifier Index
Identifier Index
SelectImage 669
SelectModem 459
SelectRegion 670
Send 840, 852, 859
SendAllMessages 884
SendBreak 87
SendCommand 476
Sender 821
SendFtpCommand 573
SendMessage 884
SendQueryInterval 802
SendTone 429
Sequence 233
Sequencing 331
ServerAddress 574
ServerDataInput 859
ServerDoneString 860
ServerInitString 860
ServerManager 803
ServerResponseFailContinue 860
ServerResponseFailTerminate 861
ServerSuccessString 861
SessionBPS 730, 803
SessionECM 731, 803
SessionResolution 731, 804
SessionWidth 732, 804
SetAsyncStyles 128
SetCharAttrs 220
SetCursorPosition 220
SetDefCharAttrs 221
SetDevConfig 430, 477
SetDialParameters 385
SetHorzTabStop 221
SetRecordingParams 430
SetScrollRegion 221
SetStatusTrigger 88
SetTimerTrigger 90
SetVertTabStop 221
sfXxx 327
sgXxx 328
ShowAboutDlg 344
ShowConfigDialog 430
10
11
14
12
15
13
16
17
1
Identifier Index xi
Identifier Index
Identifier Index
10
14
11
15
12
16
13
17
T
TabStop 622
TAdCharSetMapping 245
TAdKeyboardMapping 238
TAdKeyString 241, 248
TAdModem 461
TAdModemStatus 478
TAdParserCmdType 232, 233
TAdTerminal 269
TAdTerminalBuffer 201
TAdTerminalCharAttr 213, 220
TAdTerminalCharAttrs 213, 220
TAdTerminalEmulator 253
TAdTerminalParser 224, 229
TAdTTYEmulator 262
TAdVT100Emulator 263
TAdVT100Parser 225, 234
TApdAbstractFax 715
TApdAbstractFaxPrinterStatus 689
1
xii Identifier Index
TApdAbstractFaxStatus 822
TApdAbstractPager 839
TApdAbstractStatus 578
TApdAbstractTapiStatus 440
TApdAudioInDevice 324
TApdAudioOutDevice 314
TApdBaseComponent 8
TApdBaseDispatcher 49
TApdBaseXxx 8
TApdComPort 22
TApdCustomModemPager 841
TApdCustomSapiEngine 333
TApdCustomSapiPhone 356
TApdDataPacket 132
TApdFaxClient 815
TApdFaxConverter 594
TApdFaxDriverInterface 834
TApdFaxJobHandler 769
TApdFaxLog 828
TApdFaxPrinter 674
TApdFaxPrinterLog 695
TApdFaxPrinterMargin 680, 681
TApdFaxPrinterStatus 693
TApdFaxServerManager 809
TApdFaxStatus 826
TApdFaxUnpacker 624
TApdFaxViewer 649
TApdFtpClient 559
TApdGSMPhone 865, 878
TApdLibModem 449
TApdMessageStore 875
TApdPagerLog 862
TApdProtocol 523
TApdProtocolLog 583
TApdProtocolStatus 582
TApdRasCompressionMode 374
TApdRasConnectedEvent 382
TApdRasDialer 372
TApdRasDialMode 377
TApdRasErrorEvent 382
TApdRasSpeakerMode 385
TApdRasStatus 387
Identifier Index
Identifier Index
TApdRasStatusEvent 383
TApdReceiveFax 754
TApdSapiEngine 337
TApdSapiPhone 359
TApdSapiPhonePrompts 351
TApdSendFax 736
TApdSLController 191
TApdSMSMessage 872
TApdSNPPPager 856
TApdSocket 115
TApdState 178
TApdStateMachine 172
TApdStatusLight 188
TApdTapiDevice 407
TApdTapiLog 445
TApdTapiStatus 443
TApdTAPPager 841
TApdVoIP 301
TApdVoIPTerminal 298
TApdWinsockPort 106
TapiDevice 441, 446, 735, 807
TapiHistoryName 446
TapiLog 434
TapiMode 92
TapiState 435
TapiStatusMsg 436
TAPStatusMsg 853
TApxScript 146
TAsciiEOLTranslation 527, 529
TAutoScaleMode 631, 657
TBlockCheckMethod 530
TCallInfo 415
TDeleteFailed 584
TDeviceLayer 58, 109
TDialError 841, 849
TDialErrorEvent 849
TDialingCondition 841, 847, 849, 850
TDialingStatus 841, 850
TDialStatusEvent 850
Terminal 163, 261
TerminalState 177
Terminate 185
10
11
14
12
15
13
16
17
1
1
Identifier Index
Identifier Index
10
14
11
15
12
16
13
17
TimeOut 144
TimerExpired 893
TimeStamp 874
TimeStampStr 874
TLightSet 191
TLineDialParams 415
tlXxx 35, 45, 66, 94
TModemString 746, 787, 796, 846, 849
tmXxx 92
ToneDial 753, 807, 853
TooFewDigits 354
TooManyDigits 354
TopMargin 623
TotalErrors 553
TotalFaxPages 688
TotalPages 735, 808
TPacketEndSet 139
TPacketStartCond 143
TParity 82
TProtocolAcceptEvent 545
TProtocolErrorEvent 545
TProtocolFinishEvent 546
TProtocolLogEvent 546
TProtocolNextFileEvent 547
TProtocolStatusEvent 548
TProtocolType 550, 897
TraceHex 93
TraceName 93
TraceSize 94
Tracing 94
TransferTimeout 576
TranslateAddress 437
TransmitTimeout 553
TrimSeconds 437
TStationID 730, 733, 802, 805
TStringPacketNotifyEvent 142
TSWFlowOptions 91
tsXxx 315, 435
TTapiLogCode 446
TTapiLogEvent 424
TTapiMode 92
TTapiState 435
1
xiv Identifier Index
TTapiStatusEvent 425
TTAPStatus 842, 851
TTAPStatusEvent 851
TTraceLogState 66, 94
TTriggerAvailEvent 71
TTriggerDataEvent 73
TTriggerEvent 69
TTriggerLineErrorEvent 73
TTriggerStatusEvent 78
TTriggerTimerEvent 79
TTSOptions 350
TUnpackerOptions 637
TUnpackOutputLineEvent 635
TUnpackStatusEvent 636
TurnDelay 554
TViewerErrorEvent 665
TViewerFileDropEvent 664
TViewerRotation 668
TWriteFailAction 555
TWsAcceptEvent 109
TWsErrorEvent 111
TWsNotifyEvent 126, 127
TWsSocketErrorEvent 127
TXDLight 191
TXDOffTimeout 194
TZmodemFileOptions 556
U
UnpackFile 639
UnpackFileToBitmap 640
UnpackFileToBmp 641
UnpackFileToDcx 641
UnpackFileToPcx 642
UnpackFileToTiff 642
UnpackPage 643
UnpackPageToBitmap 644
UnpackPageToBmp 644
UnpackPageToDcx 645
UnpackPageToPcx 645
UnpackPageToTiff 646
VER_PLATFORM_WIN32_NT 385
VER_PLATFORM_WIN32_WINDOWS
385
Version 8
VertDiv 646, 670
VertMult 646, 671
VertScroll 671
VideoInDevice 307
VideoOutDevice 307
VoIPAvailable 307
vrXxx 668
W
WaitingForCall 308
WantAllKeys 290
WaveFileName 438
Identifier Index
WaveState 439
waXxx 426
wfXxx 555
Where 355
Where2 355
WhitespaceCompression 647, 671
WhitespaceFrom 647, 672
WhitespaceTo 648, 673
Width 623
WordList 350
WrapAround 268
WriteChar 223, 291
WriteFailAction 555
WriteSocket 129
WriteString 223, 291
WsAddress 112
WsMode 113
WsPort 114
WsTelnet 114
WsVersion 129
wsXxx 439
Identifier Index
Unrecognized 355
uoXxx 637
UpcaseFileNames 554
UpdateDisplay 442, 481, 581, 692, 825
UpdateLog 446, 585, 696, 829, 864
UpdateStatus 814
UseAutoWrap 222
UseEscapes 854
UseEventWord 95
UseLazyDisplay 289
UseNewLineMode 222
UserCode 105
UserLoggedIn 576
UserName 386, 577
UseScrollRegion 223
UseSoundCard 438
UseTapi 855
UseWideChars 223
10
XOffChar 97
XOnChar 97
XYmodemBlockWait 555
11
14
12
15
13
16
17
1
Identifier Index xv
Identifier Index
Identifier Index
10
14
11
15
12
16
13
17
1
1
xvi Identifier Index
Subject Index
AcceptFile processing 495
accepting connection 126
accessing terminal parser 260
adding
commands 162
data trigger 49
keyboard mapping instance 241
recipient to job file 770
AddModemRecord 457
AdLibMdm 447
AdMdm 447
AdMdmDlg 447
Alphanumeric pager See Pager
ANSI, definition of 921
answering
call 464, 759
data calls 759, 762
APF file format 591
APJ See Async Professional Job File
APRO.HLP 4
APRO.XXX 4
APROBCB.HLP 4
ASCII protocol
See also protocol
delay settings 527, 529
end of file settings 529
end of line character 528
end of line translation 519, 527, 529
overview 519
timeout settings 528
ASCII text documents 594
assigning pager port 858
Async Professional Job File (APJ) 766
asynchronous serial communication 921
AT commands 921
AWDEFINE.INC 920
Subject Index
Identifier Index
cancelling
fax session 782
pager call 845
protocol transfer 533
script 157
state machine 173
CCITT 922
character map
adding new instance 248
clearing 249
count 249
data source 246
emulator and 256
loading from file 250
loading from resource 252
overview 245
storing to file 252
character quoting 513
character set
glyph 202
10
11
14
Subject Index
12
15
13
16
17
1
xvii
Identifier Index
Subject Index
10
11
Subject Index
15
12
16
13
17
mapping 199
special graphics 199
USASCII 199
character-time 922
checking
CTS signal 55
DCD signal 56
DSR signal 58
DTR signal 59
for received data 95
for syntax errors 161
checksum 922
client
connecting to server 109
defined 922
clock tick 888
collecting data 138, 748
COMM.DRV 922
command
list of 162
script 162
common problems 932
component hierarchy 8
comport
activating triggers 88, 90
adding triggers 49, 50, 51
baud rate 53
buffer space 64
character ready 54
CTS signal 55
data bits 56
DCD signal 56
defined 922
DeltaCTS signal 56
DeltaDCD signal 57
DeltaDSR signal 57
DeltaRI signal 57
determining number of stop bits 91
device layer 49
device type 58
DSR signal 58
DTR signal 59
1
xviii Subject Index
10
11
14
12
15
Subject Index
data
adding trigger 49
answering calls 759
bits 923
checking for received 95
Subject Index
Identifier Index
13
16
17
1
1
Identifier Index
Subject Index
10
11
Subject Index
15
12
16
13
17
DeltaDCD signal 57
DeltaDSR signal 57
DeltaRI signal 57
demonstration programs 6
deprecated components 3
destination directory 533
detecting
active protocol 540
batch transfers 530
dial tone 743, 845
DTMF tone 423
determining
data packet size 142
default fax font 788
emulator display width 266
fax error action 720
fax font 747, 787
fax header font 788
fax job file directory 811
fax port used 783
fax send count 750
fax serial port 718
logging state 66
media terminal device to use 307
modem serial port 466
number of dial attempts 786
number of glyph cells 183
number of mappings 241
number of rings 758, 781
number of stop bits 91
port 138
protocol log file name 584, 585
script protocol 162
serial port 173
state color when not active 183
state component color 181
terminal component 163
whether state is active 181
device layers
defined 923
setting 58, 109
dial status of pager 850
1
xx Subject Index
E
EAPDException 900
editing commands 162
emulator
accessing parser 260
auto repeat 266
character set map 256
cursor position 257, 265, 267
defined 927
defining terminal component 261
defining terminal display status 259
Subject Index
9
10
11
14
12
15
Subject Index
FAQs 932
fax
See also fax server, fax server manager, fax
job handler, fax engine
accepting 761
answering data calls 759, 762
assigning file extension 721
bps 719, 725, 730
cancelling 717
classes supported 734
combining files 744
connecting files 748
converting font 609
cover file name 744
current page number 719
detecting busy signal 745
detecting dial tone 743
determing number of rings 758
determing send count 750
determining error action 720
determining font 747
determining serial port 718
dial retry 746
dialing 745, 746, 747
directory 759
error 728
file format 591
file name 721, 760, 789
hangup code 722
header line 748, 816
indicating class 721
initialization baud rate 724
initialization string 726
initializing modem 760
log 729
log component 829
Identifier Index
13
16
17
1
Subject Index xxi
Identifier Index
Subject Index
10
11
Subject Index
15
12
16
13
17
1
xxii Subject Index
10
11
14
12
15
Subject Index
Subject Index
Identifier Index
13
16
17
1
1
Identifier Index
Subject Index
10
11
Subject Index
15
12
16
13
17
XOn character 97
font
file 609
size 610
specifying size 610
footers 674
FTP
account information 562
active session 576
bytes transferred 562
changing directory 563
client 559
client support 521
closing port 568
commands supported 566
connecting 563
controlling connection 521
deleting file 564
error codes 522
file format 565
file length 564
help 566
list of files 566
log auditing 569
log in 567
log out 568
logging component 565
making new directory 568
opening port 567
operation in progress 566
overview 521
password 571
protocol error 568
renaming file 571
restarting byte location 572
resuming start 572
retrieving file 572
returning a reply 569
sending command 573
sending file 575
server address 574
server status 574
1
xxiv Subject Index
status 569
status codes 570
store mode 575
terminating transfer 562
timeout value 576
user name 577
full duplex 924
G
generating end of page code 614
glossary 921
glyph, in character set 202
H
half duplex 924
handshaking 499, 924
headers 674
host name 924
I
image file, opening 615
including start and end strings 140
initializing modem 760
installation 4
interface layer 924
Internet communications 99
IP address 99, 924
IRQ 925
ISDN
overview 29
support 30
K
Kermit protocol
See also protocol
character quoting 513
10
11
14
12
15
Subject Index
LAP M 925
large block support 512
lazy paint, processing request 259
left margin, specifying width 613
libmodem 448
line
break signal 64
error 65, 925
number per page 613
outputting 616
Subject Index
Identifier Index
13
16
17
1
Subject Index xxv
Identifier Index
Subject Index
10
11
Subject Index
15
12
16
13
17
1
xxvi Subject Index
N
naming conventions 18
network address 112
network shared-modem pool 925
newsgroups 19
NextFile processing 494
O
on-line help 18
opening image file 615
option
for conversion 619
setting 619
output
line 616
request trigger 26, 77
unpacked line 635
P
packet
end condition 135
10
11
14
12
15
Subject Index
Subject Index
Identifier Index
13
16
17
1
1
Identifier Index
Subject Index
10
11
Subject Index
15
12
16
13
17
1
xxviii Subject Index
10
11
14
12
15
Subject Index
Subject Index
RAS
active connections 380
asynchonous dialing 377
authenticate access 383, 386
authentication 378
callback number 374
compression mode 374
connecting 382
connection handle 374
connection status 374
connection status dialog 381
connection status text 379
create phonebook entry 375
delete phonebook entry 375
device name 375
device type 376
dial 376
dial dialog 377
dial error 382
dial mode 377
dial options 378
dial status 383
dialer overview 372
dialing parameters 379, 385
disconnecting 383
domain 378
edit phonebook entry 378
entry name 378
entry names 381
error text 379
establish connection 376
hangup 380
override phonebook entry 384
overview 371
password 383
phone number 384
phonebook dialog 384
phonebook path 384
platform supported 385
release resources 380
Identifier Index
13
16
17
1
1
Identifier Index
Subject Index
10
11
Subject Index
15
12
16
13
17
1
xxx Subject Index
S
SAPI
components 309
overview 310
scaling
fax printer 675
fax unpacker 626
fax viewer 649
script
active 158
adding commands 162
cancelling 157
checking for syntax errors 161
command finish event 158
command start event 159
commands 146, 162
comport 157
debugging 154
defined 145
definition 145
determining protocol 162
determining terminal component 163
display event 159
displaying data 157
editing commands 162
encountering user function 161
error handling 160
example 155
executing 153, 158, 163
file 162
list of commands 162
options 149
parsing variable 160
preparing 161
protocol component 154
receiving data 157
required components 154
sending data 157
starting 163
syntax 146
syntax error handling 161
10
11
14
12
15
Subject Index
Subject Index
Identifier Index
13
16
17
1
1
Identifier Index
Subject Index
10
11
Subject Index
15
12
16
13
17
1
xxxii Subject Index
T
tab, specifying size 622
TAPI
answering calls 402
auto answer 410
bps rate 411
call info 415
caller ID 412
closing port 424
comport 413
configuration record 431
connect event 422
connect fail 423
connect fail event 423
connecting 422
create status display 441
destroy status display 441
determining an instance 735
device 441
device configuration 419, 430
device selection 429
dial 415, 416
dial attempts 409
dial retry 420
disconnect 413
disconnect check 413
display comports 431
DTMF 406
fax server device 807
log 424
log event 424
log file name 446
logging 400, 434, 446
logging overview 397
making calls 400
number of devices 415
opening port 425
overview 389
passthrough mode 414
phone number 421
port close event 424
10
11
14
12
15
Subject Index
Subject Index
Identifier Index
13
16
17
1
1
Identifier Index
Subject Index
10
11
Subject Index
15
12
16
13
17
1
xxxiv Subject Index
status 25
timer 79
TTY
nil properties 262
overview 253
Subject Index
9
10
11
14
12
15
Subject Index
UART 927
unpacking
all pages 639
auto scaling 631
file name 634
number of pages 635
options 637
output file name 638
output line event 635
page 643
resolution 632
scaling 633, 634, 638, 646
status 636
status event 636
to APF 631
to bitmap 640, 644
to BMP 641, 644
to DCX 641, 645
to PCX 642, 645
to TIF 646
to TIFF 642
white space compression 647, 648
width 633
updating printer log 696
using fax error control 720
Identifier Index
13
16
17
V
V.17 928
V.21 928
V.22 928
V.22bis 928
V.25bis 928
1
Subject Index xxxv
Identifier Index
Subject Index
10
11
Subject Index
15
12
16
13
17
V.27 928
V.29 928
V.32 928
V.42 928
variable parsing 160
viewer
active page 656
auto scaling 657
background color 658
bitmaps 666
copying to clipboard 659
cursor 658
displaying first page 660
displaying last page 662
drag and drop 656
dropping file 664
error 665
file name 660
foreground color 659
loading entire fax 662
next page 663
number of pages 663
page change 665
page height 667
page width 667
previous page 667
rotation 668
scaling 661, 669, 670, 671
scrolling 661, 671
selection 669, 670
updating scaling properties 657, 659
white space compression 671, 672, 673
voice telephony 311
VT100 927
See also terminal
ASCII value 202
escape sequence responses 264
parser 225
standard 196
1
1
xxxvi Subject Index
W
wave file
current state 439
interrupting 420
name 438
playing 427
sound card 438
status 426, 427
stop recording 434
stopping 434
supported 417
wave, average relative amplitude 410
white space compression
fax unpacker 628
fax viewer 651
Windows printer driver 830
Winsock
disconnecting 111
error 111
overview 99
Winsock port
connecting to server 109
definition of 106
device type 109
disconnecting 111
error 111
establishing connection 110
mode 113
network address 112
opening 112
port number or name 114
telnet 114
Winsock socket
attaching client to listening socket 117
bind 117
close 118
connecting 126
creating 119
disconnecting 126
DLL description 119
DLL loaded 118
Xmodem protocol
See also protocol
Y
Ymodem protocol
See also protocol
extensions 506
overview 504
Z
Zmodem protocol
See also protocol
block size control 511
control character escaping 508
file management options 510
long blocks 512, 556
overview 507
overwriting files 556, 557, 558
protocol options 509
resume transfer 510, 558
retry settings 557
Subject Index
extensions 503
overview 501
timeout settings 555
XOff character 97, 924
XOn character 97, 924
Identifier Index
10
11
14
Subject Index
12
15
13
16
17
1
Subject Index xxxvii
For over fifteen years youve depended on TurboPower to provide the best
tools and libraries for your development tasks. Now try SysTools 3 and
XMLPartner Professionaltwo of TurboPowers best selling products
risk free. Both are fully compatible with Borland Delphi and C++Builder,
and are backed with our expert support and 60-day money back guarantee.
SYSTOOLS 3
D E V E LO P, D E B U G , O P T I M I Z E
TM
H E L P S YO U B U I L D YO U R B E S T
F R O M S TA RT TO F I N I S H , T U R B O P O W E R
Async
Professional
Async Professional
TM
Our new XSL Processor with XPath support, filter set, and EXMLPro utility
make it easy to add XML capabilities to your applications.
www.turbopower.com
Async Professional 4 requires Microsoft Windows (9x,Me,NT,2000 or XP) and Borland Delphi 3 and above,or C++Builder 3 and above
Reference Guide
XMLPARTNER PROFESSIONAL
REFERENCE GUIDE
The comprehensive guide to using Async Professional