{short description of image}

Async Professional

Home
Project Home

Manuals
Delveoper's Guide
Reference Guide
Activex

FAQ
Downloads

Frequently Asked Questions

General FAQ

  • Why don't all of the forms in your demo programs show up in the project manager?

For the Delphi project manager to display the forms belonging to a project, the project must have the unit listed in an "in" clause in the main project file's uses statement (e.g., XXX in 'XXX.PAS'). However, the "in 'XXX.PAS'" clause will not search the directories declared in the project options; a path to these files must be present if the units forms are not in the current directory. Our choice was to leave the statements commented out and have the units forms not appear in the project manager rather than have path assumptions hard-coded into the project. If you wish to see these units in the project manager, uncomment the hard-coded paths in the .DPR file and reload the project.

  • What's the best way to use APRO in multiple compilers?

This is usually only an issue when using APRO with different versions of C++Builder, but the same technique can also be used for different versions of Delphi, or mixing Delphi and C++Builder. As usual, there are a few ways to do it.

The simplest way to handle this is to install APRO in a single folder, and all of your compilers would use that folder. The problems start when you switch from one compiler to another one. The compiler will generate DCUs, OBJs, and/or HPPs specific to that compiler, which can't be used by other compilers. With Delphi, simply rebuilding your project should rebuild all of the DCUs, but you may have to delete the DCUs from your source trees first. (Don't delete the DCUs unless you have the associated PAS files). With C++Builder, things get a little trickier. The HPPs will not be regenerated unless you rebuild the package. The easiest way to rebuild the HPPs for the other compiler is to open the APRO design-time package and do a Build on it.

If you don't want to go through this hassle, then install APRO separately for each compiler you want to support.

  • Can I use APRO in non-Borland compilers?

No, not directly. You can encapsulate the portions of APRO that you want to use in a DLL, which can then be used in other compilers. A better choice would be to use Async Professional – ActiveX (APAX). APAX wraps the TApdComPort, TApdWinsockPort, TAdTerminal (and emulators), TApdProtocol, basically everything except the fax components, into an ActiveX control that you can use in other compilers, even in a web page.

  • What's the best way to debug a communications session?

The ApdComPort's Dispatcher log is the best resource for finding out what is happening.

The dispatcher log records just about everything that APRO does with the port. Anything that is sent or received is recorded, as well as some property and internal state changes.

The dispatcher log is invaluable as a debugging tool, you can easily see exactly what is sent and received and how APRO handles it.

The dispatcher log is created when the ApdComPort.Logging property is set to tlOn. If you set that property at design-time, the log will be started when the port is opened. The log is kept in memory until the Logging property is set to tlDump, tlOff, or tlAppend, or when the port is closed. If Logging is set to tlDump or tlAppend, the log buffer will be flushed to the file specified by the LogName property. Set LogName to an explicit path/filename, otherwise the log will be written to whatever directory Windows thinks is the current directory. The size of the dispatcher log is set with the LogSize property. LogSize should be large enough to capture the data you want to inspect. The maximum value for LogSize is 16000000, which is large enough to capture several complete fax sessions.

For most purposes, setting Logging to tlOn, LogSize to 16000000 and LogName to an explicit path/filename at design-time is enough to capture the data requested by a tech support engineer. They will be able to find the information buried in the log that they need.

To make the log a bit easier to read, you can add some customized entries using the ApdComPort.AddStringToLog method. This will add your own text to the log buffer, which can indicate where you think the problem starts or when events are generated.

Once you have the log, you can post it to the newsgroup. We like to keep attachments and message sizes down to 5K (some of our international customers pay by the minute for Internet access, and they don't appreciate downloading large messages). If your log is larger than 5K, you can email it to mailsupport@turbopower.com or post it to the turbopower.public.support.binaries newsgroup. Be sure to include some background information when you do this, otherwise we may not make the association between the log and the problem.

  • After loading APRO, I get a "Cannot load package" error when starting the IDE.

This error occurs if your IDE cannot locate the package, or a file that the package needs. In most cases, the IDE cannot locate the appropriate run time package. The easiest way to fix this is to copy the runtime package to a directory where the IDE can locate it.

When you get the error message, it should also display the name of the design time package that the IDE was attempting to load, for example A400_D50.bpl. The 'A' indicates APRO. The '400' is the version level. The 'D' indicates that this is a design time package and the '50' identifies the compiler. To get the name of the run time package, convert the 'D' to an 'R'. In the above example, the run time package would be A400_R50.bpl.

The run time packages that you will need to copy are located in the REDIST subdirectory underneath where you installed APRO. If you are running Windows 9.x or ME, copy the file to your \Windows\System directory. For NT or 2000, copy the file to your \WinNT\System32 directory. Once this is done, restart the IDE and things should behave normally.

  • After loading APRO, the icons on the palette are corrupted.

This problem has been seen even when no TurboPower products are involved. It is generally caused when too many icons are present on the component palette. The resolution usually involved one or both of the following:

If running Active Desktop from IE4 under Win95, uninstall it. Using Active Desktop causes a new version of a DLL to be installed that may have problems.

Switch to a different screen and/or color resolution using the current set of video drivers or, preferably, switch to a default video driver supplied with Windows. If the latter solves the problem, contact the card's manufacturer about updated drivers. The easiest way to test this is to boot into Safe Mode, which will load the default VGA drivers.

Hardware FAQ

  • Why do I get a "Function not Supported by Driver" error when using a Shiva NetModem or LanRover under Windows 3.x?

The Shiva NetModem series and the Shiva LanRover series of network modems have a 5 buffer limitation under Windows. Async Professional (as well as other communications software) allows for numerous modem settings to be updated at any time. When more than four settings are updated sequentially, the buffers become full and therefore the next setting update returns this error because there are no more buffers free, until they are released by the network operating system.

You can work around this limitation by adding a yield (processcommunications, processmessages) between setting changes.

  • What 3rd Party products have been tested with Async Professional?

Communications driver replacement sources

Although it is possible for Async Professional or an application program to work around all known communications driver problems, replacement drivers are available which also work around these problems. Some replacements also offer higher performance or additional features.

Below is a list of replacement 16-bit communications drivers that we have tested with Async Professional for Delphi. Pacific ComWare has also released a replacement driver for Windows95 (TurboCom-95 Pro).

Pacific Commware (TURBOCOM.DRV, and TURBOCOM/95 PRO),
voice: 541-482-2744 (800-856-3818), fax: 541-482-2627,
www.turbocom.com

Multi-port communication board sources

For applications requiring more than two or three standard com ports, multi-port communication boards with 8, 16, or more ports are available. These multi-port boards are available both in both non-intelligent and intelligent varieties. Non-intelligent boards appear as standard UARTS to Windows, and the Windows comm driver is responsible for handling the interrupts for characters received on each port. Intelligent boards include on-board management of the UART and free Windows from having to process each character interrupt, reducing the chance that characters will be lost when Windows is busy. For highest performance and reliability, intelligent communications boards are the better solution.

Below is a list of multi-port communication boards that we have tested with Async Professional.

DigiBoard Incorporated (PC/X, PC/Xe),
voice: 612-912-3444 (800-344-4273),
fax: 612-912-4952,
www.dgii.com,
email: sales@digi.com

GTEK Incorporated (BlackBoard-8, SmartCard-8),
voice: 601-467-8048 (800-282-GTEK), fax: 601-467-0935,
www.gtek.com,
email: spot@gtek.com

Comtrol (RocketPort, RocketModem),
voice: (800) 926-6876 or (763) 494-4100
fax: (763) 494-4199
ftp.comtrol.com
www.comtrol.com
info@comtrol.com

High-speed serial port board sources

High-speed serial port boards are available for applications in which the standard 16550 is not fast enough and multi-port boards solutions are not necessary. These optimized boards can handle transfer rates of 115kbps and greater.

Below is a list of high speed serial port boards which will work with Async Professional.

Telcor Systems Corporation (T/Port) [115kbps, 16kB on-board buffer],
voice: 508-881-1664, fax: 508-881-0994.

Pacific CommWare (TurboExpress Port 920) [920kbps, 64 byte FIFO, 16750 UART],
voice: 541-482-2744 (800-856-3818), fax: 541-482-2627,
www.turbocom.com

Differences with replacement port drivers in 32-bit applications

Although the Win32 SDK documents that direct manipulation of modem control register lines (i.e., RTS and DTR) is not allowed when hardware flow control is enabled using those lines, the standard Microsoft port driver allows the application to change the state of these lines (for example, when lowering the RTS line before writing to disk). Replacement port drivers for multi-port boards such as DigiBoard or Equinox follow the Win32 SDK and do not allow this behavior. If hardware flow control is enabled and you need to manually change the state of a line, it is not guaranteed that the underlying drivers will allow it. It is also not possible to reliably check the state of the lines to see if the call succeeded.

  • What kind of modem should I buy?

You should buy a modem that supports the features that you use. There are literally hundreds of modem manufacturers, each with many different models. It is nearly impossible to say that modem X will do what you want, since modem X may have several minor changes throughout the manufacturing cycle. The short list of things to look for are: a major manufacturer (they have been in business longer, and that usually means their products have been tested more); don't try to use something with 'new' technology until the bugs are worked out.

ApdComPort/ApdWinsockPort FAQ

  • Why, when I call RemoveAllTriggers, does my program stop responding to communications events?

Calling RemoveAllTriggers does exactly that; it removes all triggers from the com port. The triggers removed are not only the ones that you set up for your own use, but also those that APD allocates for the communications events. The correct approach is to call RemoveTrigger individually for each trigger that you have added.

  • Why am I able to capture only a partial data match sometimes when I set a data trigger?

When a data trigger is set in Async Professional to report a particular string match, the trigger will report that a match has been found. However, this data trigger does not guarantee that the notification will be synchronized with the actual occurrence of the data match. OnTriggerAvail events may not allow you to capture a complete data match if the data match string is received over multiple ReadCom functions although you do get notification that the trigger match has occurred.

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 these characters in an OnTriggerAvail event immediately following the OnTriggerData event for that string.

Refer to the TApdDataPacket component in the manual and AproXX.HLP files for an alternate method of detecting specific data in the data stream.

In the example code below, the variable "s" would not be guaranteed to contain the complete data trigger "MYDATA" after the ApdComPort1TriggerData event fires notifying you of the match.

unit Unit1;

interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, AdTerm, AdPort;

type
  TForm1 = class(TForm)
    ApdComPort1: TApdComPort;
    Button1: TButton;
    Button2: TButton;
    AdTerminal1: TAdTerminal;
    Memo1: TMemo;
    procedure ApdComPort1TriggerData(CP:     TObject; TriggerHandle: Word);
    procedure ApdComPort1TriggerAvail(CP: TObject; Count: Word);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
  public
end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
var
  Collecting : Boolean = False;
  MyHandle : Word;
  MyDataTrigger : String = 'MYDATA';

procedure TForm1.ApdComPort1TriggerData(CP: TObject; TriggerHandle: Word);
begin
  if Triggerhandle = MyHandle then
    Collecting := True;
end;

var
  s : string = '';
  CollectCount : Byte = 0;

procedure TForm1.ApdComPort1TriggerAvail(CP: TObject; Count: Word);
var
  i : integer;
  c : char;
begin
  for i := 1 to Count do begin
    c := ApdComPort1.GetChar;
    if Collecting then begin
      s:= s + c;
      inc(CollectCount);
      if CollectCount = Length(MyDataTrigger) then begin
        Collecting := False;
        Memo1.Lines.Add(s+' [Count is '+inttostr(Count)+']');
      end;
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  MyHandle := ApdComPort1.AddDataTrigger(MyDataTrigger,True);
  AdTerminal1.SetFocus;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ApdComPort1.PutString('This is a test sending MYDATA within a string.'#13);
end;

end.

  • In what order are data trigger events generated?

Triggers are generally executed in the order that they were added (first to last). There are exceptions to this however. First we will discuss the general order. If you added the following 3 triggers to your program:

Trigger1 := ApdComPort1.AddDataTrigger('DATA', True);
Trigger2 := ApdComPort1.AddDataTrigger('DATA', True);
Trigger3 := ApdComPort1.AddDataTrigger('DATA', True);

If the incoming data stream contains the string 'DATA' then Trigger1 would fire first, then Trigger2 and finally Trigger3.

Suppose you then called:

ApdComPort1.RemoveTrigger(Trigger2);
Trigger4 := ApdComPort1.AddDataTrigger('DATA', True);
Trigger5 := ApdComPort1.AddDataTrigger('DATA', True);
Trigger2 := ApdComPort1.AddDataTrigger('DATA', True);

Now the order of the triggers firing would be:

Trigger1, Trigger4, Trigger3, Trigger5, Trigger2.

The trigger that was removed (Trigger2), left a gap in the trigger array. When the next trigger was added, it filled this gap, then when the next two were added, they were placed at then end.

Note that this issue applies only to triggers that match on the same received character. In the above example, all of the data triggers are contrived; a real program would never do this. A more realistic example would be program that added two data triggers: 'DATA' and 'GOTDATA' and the incoming data stream contained 'GOTDATA', then both of these data triggers would match on the same character (the last 'A') and two data trigger events would be generated.

For data triggers that do not match on the same character, the order of the data triggers is the same as the order of the incoming data.

  • Why am I getting calls to OnTriggerXxx when I haven't activated any triggers yet?

APRO uses triggers internally for modem, terminal and protocol processing. Your event handlers must check the passed TriggerHandle of OnTriggerData, OnTriggerTimer or OnTriggerStatus to determine which trigger generated the event.

Example:

procedure Form1.TriggerTimer(CP : TObject; TriggerHandle : Word);
begin
  case TriggerHandle of
    Trigger1 : {Your timer trigger #1}
    Trigger2 : {Your timer trigger #2}
    else
      {APD-defined timer trigger, do nothing}
  end;
end;

  • !!!Why does the TApdWinsockPort component report that the ComPort is not set when I run my application?

By default, the TApdWinsockPort.DeviceLayer property is set to dlWin32. You should set the device layer to dlWinsock.

  • How can I tell when the port actually opens and closes?

When you set the ApdComPort.Open property to True, the port does not open immediately. Setting Open to True starts a background process that allocates memory for buffers, initializes internal structures, and asks Windows to open the serial port, among other things. This usually takes a few cycles to complete, but it can take longer if other time/resource consuming processes are running, or if Windows needs to load additional drivers to support the port. If you had code like this:

ApdComPort1.Open := True;
ApdComPort1.PutChar('x');

There is a possibility that the port will not be completely open when the PutChar method executes, which could cause an exception.

There are a few ways that you can handle this. The simplest is to introduce a small delay (using the DelayTicks method in OOMisc, or ProcessMessages) right after you set Open to True. A delay of 2 to 4 clock ticks is usually enough.

You can also create a TPortCallback method, using the ApdComPort.RegisterUserCallback method. The TPortCallback method is a method type that will give you notification when the port opens and closes. To implement it, add something like this to the type declaration of the form containing the ApdComPort component:

type
  TForm1 = class(TForm)
    ApdComPort1: TApdComPort;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    procedure PortOpenClose(CP : TObject; Opened : Boolean);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.PortOpenClose(CP: TObject; Opened: Boolean);
begin
  if Opened then
    { the port is now open }
  else
    { the port is now closed }
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ApdComPort1.RegisterUserCallback(PortOpenClose);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ApdComPort1.DeregisterUserCallback(PortOpenClose);
end;

Another way to do it is to use the ApdComPort's OnPortOpen and OnPortClosed events. These are TNotifyEvent events that simply provide notification when the physical port opens and closes.

  • How can I do CPU intensive activities on the OnTriggerAvail event?

It is not recommended that you execute CPU intensive code, file I/O or database access from within the time sensitive events in APRO like the OnTriggerAvail event. However, you can post a message to a custom message handler and let that handler do the work for you.

To do this, first create a constant for your custom message handler.

const
  Am_MyMessage = WM_USER + $300;

Next, declare the method that will do your CPU intensive processing.

procedure AmMyMessage (var Msg : TMessage); message Am_MyMessage;

Then, code your message handler.

procedure TForm1.AmMyMessage (var Msg : TMessage);
begin
  // Do your CPU intensive stuff here.
  ShowMessage ('Hello World');
end;

Finally, post a message to your new handler in the OnTriggerAvail event.

procedure TForm1.ApdComPort1TriggerAvail(CP: TObject; Count: Word);
var
  i : Integer;
begin
  // Read the characters out of the input buffer.
  for i := 1 to Count do
    ApdComPort1.GetChar;
  // Post a message to the message handler to process them.
  PostMessage (Application.Handle, Am_MyMessage, 0, 0);
end;

  • How can I detect COM ports or modems?

You can use the IsPortAvailable function in the AdSelCom unit to determine if a port is available on your machine. By default, the function will show all ports that are physically present, even if those ports are in use. If you want to show only those ports that are present and not busy, set the global constant, ShowPortsInUse, to False.

This example will list all available ports in a TListBox.

var
  i : Integer;
begin
  ListBox1.Items.Clear;
  for i := 1 to 64 do
    if IsPortAvailable(i) then
      ListBox1.Items.Add ('COM' + IntToStr (i));
end;

Remember, if you are using IsPortAvailable, you must include the AdSelCom unit.

  • Do the Modem or Fax components work with the TApdWinsockPort component?

No. Winsock does not support the concept of modems or the levels of faxing that Async Pro supports. The TApdWinsockPort can be used with these components, but only if the DeviceLayer is dlWin32. Async Pro does not support Internet faxing.

Deprecated components FAQ

  • Why am I getting an EModemBusy exception?

The TApdModem component raises an EModemBusy exception whenever you tell the component to do something (initialize the modem, dial, etc.) and do not let it finish that operation before attempting another one. For instance, the following code raises an EModemBusy exception:

ApdModem1.Initialize;
ApdModem1.Dial('1-719-260-9726'); {exception raised here}

Making the call to ApdModem1.Initialize sends the modem initialization command to the physical modem and then begins a background task which will wait for an OK or ERROR response the modem. Since the program has not yielded control anywhere along the way, the call to ApdModem1.Dial will be made well before the modem component has a chance to finish processing the call to Initialize. As such, an EModemBusy exception will be raised.

EModemBusy can come about from other programmer mistakes as well. For instance, making a call to TApdComPort.RemoveAllTriggers will destroy the triggers that the modem component needs to process modem responses. As such, if the modem component is busy processing modem responses when a call to RemoveAllTriggers is made, the modem will never finish processing the responses and all subsequent calls to modem component methods will raise the EModemBusy exception.

Another common programmer mistake is to close the TApdComPort component while the modem is processing commands and then reopen it later. In version 1.00 of APD, this is not allowed--as long as the modem component's Started property is equal to TRUE, the port component should not be closed.

More information about the EModemBusy exception can be found in the Async Professional manual.

  • What's the difference between TApdModem.Configure and TApdModem.Initialize?

The strings in the AWMODEM.INI database are set up in a very special way in regards to configuring and initializing modems.

For modems that have the ability to store settings in non-volatile memory, AWMODEM.INI contains a configuration string that will change the settings needed by APD, and then write those settings to non-volatile memory. AWMODEM.INI entries for such modems also contain an initialization command that will recall the modem's settings from non-volatile memory. Here's an example from the AWMODEM.INI entry for the US Robotics Sportster 14400 modem:

InitCmd=ATZ^M
ConfigCmd=ATF^M|ATE1Q0M1X7V1S7=60^M|ATA3K3B1C1D2H1M4N0R2W^M

The initialization command (InitCmd) contains the command "ATZ", which is used to retrieve stored settings from the modem's non-volatile memory. The configuration command (ConfigCmd) restores the modem to factory defaults, updates various settings, and then writes the changes back to the modem's non-volatile memory.

For modems that do not have the ability to store settings, AWMODEM.INI will contain initialization and configuration strings that are very similar, or it will contain an initialization string and no configuration string.

So how does that affect the Configure and Initialize methods?

Because of the way the configuration and initialization strings are set up in AWMODEM.INI, the Configure method is designed to be called once and only once when the user of a program first configures it. Thereafter, the Initialize method should be used to restore those settings (or set them afresh, if the modem does not have non-volatile memory).

More information about this topic can be found in the Async Professional manuals.

  • I've received an OnModemIsConnected event, but the other side isn't connected. Why?

OnModemIsConnected is called when the TApdModem component receives an entire connect string from the modem, such as

CARRIER 14400
PROTOCOL: LAP-M
CONNECT 38400

Receipt of this entire connect string indicates that your modem has finished handshaking with the remote and is ready to proceed. Receipt of this string does not necessarily indicate that the remote modem has finished handshaking. As such, programs should not rely on the OnModemIsConnected event as an indication that it is safe to proceed with the processing of an incoming or outgoing call; instead, a program-to-program handshake should take place before proceeding with a call (see the EXAUTO example program for an example of how to do this).

  • Why can't I hang up the modem?

We hear a lot about this particular problem. Here are some of the common reasons why the modem might not be getting hung up:

If the TApdModem component's HangupCmd property is equal to 'DTR' (case sensitive) then the modem will attempt to hang up the phone by lowering the port's DTR signal for DTRDropHold (another TApdModem property) clock ticks, and then re-raising it. If the physical modem is not configured to hang up in this way, the hangup will fail. In our modem database, all modems that have 'DTR' as their hangup string will automatically be configured, using the Configure method, to hangup when the DTR signal is dropped. In the case where the HangupCmd property is 'DTR', the Hangup method of the TApdModem component returns immediately, assuming that the phone has been hung up; if the HangupCmd property is anything else, then that data will be sent to the modem to hang it up, and you should install an OnCommandProcessed event handler to let you know when the hangup operation has been completed.

Another common reason why the modem doesn't get hung up is placing called to TApdModem.Hangup inside code that never gets called. In an APD program, there are a number of different things that might trigger the "end" of an online session and, as such, the need to hangup the modem. For instance, your program might have an OnProtocolFinish event handler in which it calls TApdModem.Hangup, but your program might not account for some errors in handshaking that might also necessitate hanging up the modem and, as such, your OnProtocolFinish event is never getting called because the protocol is never even starting.

If you want to assure that your modem always gets hung up properly, you must account for every possible failure. This includes handshaking errors, timeouts while waiting for prompts or data, the end of protocols, and the like.

APRO Telephony components FAQ

  • Why does my TApdTapiDevice only AutoAnswer one call?

The TApdTapiDevice.AutoAnswer method tells TAPI that we are interested in accepting incoming calls. Once we answer a call, TAPI does not notify us that a new call is being received until we call AutoAnswer again. So, to answer the next call, you need to call AutoAnswer again.

  • How can I tell when a call is established or terminated?

The TApdTapiDevice uses TAPI to establish connections (hence the name of the component). The notification that you receive depends on the mode that TAPI is in. With the TApdTapiDevice, you can be in data mode (EnableVoice = False) or voice mode (EnableVoice = True).

If you are in data mode, the OnTapiPortOpen event is generated when the connection is established, and the OnTapiPortClose event is generated when the connection is terminated.

If you are in voice mode, the OnTapiConnect event is generated when the voice connection is established. TAPI does not provide a consistent notification when a voice connection is terminated by the other side (often, TAPI can not detect this condition at all). Your best bet is to watch the OnTapiLog event for the lineDrop log event. Usually, a voice connection is terminated from the local side, either based on silence detection (inactivity on the line) or when your call termination conditions have been met. To terminate the call, use the CancelCall method and the OnTapiFail event will be generated.

  • I have a voice modem, but the TApdTapiDevice says it does not support voice extensions.

Unimodem/V and Unimodem/5 provide the TAPI voice extensions. Unimodem/V is available for Windows 9x/ME; Unimodem/5 is available for Windows 2000. If you have Windows NT4, your TAPI Service Provider does not support voice extensions.

If you have an operating system that supports voice extensions, and have a voice-capable modem, but still get the exception, check your modem drivers. http://www.modemhelp.org has links to most modem manufacturers web sites, where you can make sure you have the latest drivers.

  • My voice modem can do voice things with other applications, but not with APRO.

The most common reason for this is the other applications are not using TAPI to support the voice functions. A voice modem will usually support native AT commands (usually ATVxx or AT#xxx). The applications that ship with a voice modem are usually built using the AT commands directly instead of going through TAPI. This gives the application more control over the call than what TAPI can provide. APRO would use the AT commands directly also, except the AT commands vary quite a bit between voice modem models and manufacturers.

  • Why do I get an OnTapiConnect immediately after dialing using voice mode?

TAPI does not provide accurate call progress detection or notification on an outbound call (when you dial). That's just the nature of Unimodem/V and Unimodem/5. Microsoft designed TAPI to support things like a simple answering machine or automated data collection (DTMF detection) for inbound (answered) calls, the dialed capabilities were either thrown in there at the last minute, or they just happened to work.

As a result of this, TAPI is not looking for connection-related tags when a voice call is dialed, so it artificially sends a connection message shortly after dialing is complete, regardless of whether the called party actually answered.

There are a few ways to handle this. If your modem supports ringback detection (when the remote phone rings), you can detect that in the OnTapiStatus event (you will get the lineCallState_Ringback message). This should fire about every 6 seconds for US phone systems. Each time you receive one of these, reset a 7 second timer. When that timer goes off, you know that it has been 7 seconds since you last received a ringback message, and can assume that the called party answered the phone. A lot of automated calling stations use something like this. That is why there are a few seconds of silence before they start the conversation.

If your modem does not support ringback detection (very few do), you can play a short message saying something like "please press 1 to hear my message", and play it every few seconds until you get the OnTapiDTMF event.

You could also start recording as soon as the OnTapiConnect event is generated, then watch the ApdTapiDevice. AvgWaveInAmplitude property. That property shows the average amplitude of the recorded wave stream. You'll have to experiment with the values so you can tell what the amplitude of normal silence is with your modem and phone lines. When you see a spike in AvgWaveInAmplitude, you can assume that the called party said something (like 'Hello').

The best way to deal with this is to use a dedicated voice board. These will usually provide their own TAPI Service Provider that is designed specifically to provide accurate call progress detection and notification.

  • What is needed to use the TApdSapiEngine and TApdSapiPhone components?

You will need to install SAPI version 4.0a and a speech recognition and synthesis engine. The easiest way to do this is to get the SAPI 4.0 Speech SDK Suite from Microsoft's web site. At the time of writing, this could be found at [http://www.microsoft.com/downloads/release.asp?ReleaseID=26299||http://www.microsoft.com/downloads/release.asp?ReleaseID=26299]. SAPI 4 and SAPI 5 are not the same. Both SAPI 4 and SAPI 5 can coexist on the same machine, but SAPI 4 must be installed for the APRO SAPI components to function.

After installing the Microsoft SAPI 4.0 SDK Suite you should have several speech synthesis voices and two speech recognition engines. The installed engines can be viewed via the ExSapiLs example program. Of the two speech recognition engines installed, one engine will be optimized for PC soundcard use and the other will be optimized for telephony. Some of the speech synthesis voices are also optimized for telephony. You will want to make sure that you use the proper speech engine for your application. The ExSapiB example program shows a simple means of selecting the proper engines for a voice telephony example.

During creation, the TApdSapiEngine component will attempt to locate the SAPI 4.0 speech software. If this cannot be found, the OnSRError and OnSSError events will be fired. An application can use the IsSapi4Installed method to determine if the SAPI 4 software has been installed. Installed speech synthesis and recognition engines can be determined by querying the SSVoices.Count and SREngines.Count properties. A value greater than 0 indicates that the engines are installed.

It is strongly recommended that after installation, the SAPI voice recognition engine be trained. This is not the same as microphone training, which should occur when the SAPI 4.0 SDK Suite is installed. SAPI training involves reading text to the SAPI engine so that it can learn the nuances of your voice. This will dramatically improve the accuracy of the voice recognition. The ExSapiDl example program shows how to access the training (and other dialogs). By default, APRO will use a default speaker of "APRO User". The speaker must be set for many of the SAPI functions to work.

  • Why do I get a breakpoint on the CPU window when using voice recognition?

SAPI voice recognition engines frequently have hard breakpoints left in. This can cause unexpected behavior while debugging. This is most frequently seen in Windows 2000 PC optimized speech engines just before the OnPhraseFinish event fires. When one of these breakpoints is hit, the debugger will go to a CPU windows showing one or more breakpoints in he assembler code for the speech engine. Unfortunately, there isn't a good way to prevent this.

Fax components FAQ

  • Why doesn't the fax receive window go away after I receive a fax?

When your program calls TApdReceiveFax.StartReceive, the APD fax engine goes into "receive mode." It will continue to receive faxes until you tell it to stop (either by clicking the "Cancel" button on the status window or by calling the component's CancelFax method). If you only want to receive one fax at a time, set the TApdReceiveFax component's OneFax property to True.

The TApdReceiveFax.ConstantStatus property also determines whether or not the fax status window is displayed when a fax is not currently being received. Set it to True to show the status window whenever StartReceive is called, or set it to False to show the status window only when a fax call is being answered.

  • How do I determine if an incoming call is fax or data?

Many faxmodems support a feature called "adaptive answer." This feature allows modems to answer either voice calls or data calls (which is useful if you run a BBS, but also want to receive faxes on that same line). We have created an example program, EXADAPT, which demonstrates the use of this faxmodem feature. Refer to that example for more information. Note that this does not work reliably with TAPI.

  • How do I get Async Professional to fax on a telephone network outside the US?

When sending a fax, you can set the BlindDial property to true, which allows the modem to use a phone line even if it can't detect a dial tone. You can also set the DetectBusy property to false so false detection of a busy signal is avoided. This is necessary due to the modem's ability to detect and report the dial tone and busy signals provided by the telephone service. If the modem is configured to detect the appropriate signals, you can use BlindDial and DetectBusy as usual.

  • Do the Modem or Fax components work with the TApdWinsockPort component?

No. Winsock does not support the concept of modems or the levels of faxing that Async Pro supports. The TApdWinsockPort can be used with these components, but only if the DeviceLayer is dlWin32. Async Pro does not support Internet faxing.

  • How can I let other applications use the port when I'm waiting to receive a fax?

When you call the TApdReceiveFax.StartReceive method, the TApdComPort will open the port to wait for incoming calls. This prevents other processes from accessing the port. The TAPI/fax integration new to APRO 4.0 will help resolve this problem. Simply set the TapiDevice property of the TApdReceiveFax component to a TApdTapiDevice on your form, and call StartReceive. TAPI will begin monitoring for the incoming RING messages, and will pass the port to the TApdReceiveFax so it can receive the fax.

  • Can I collect CallerID information when receiving a fax?

The TAPI/fax integration new to APRO 4.0 can provide the CallerID information. Set the TapiDevice property of the TApdReceiveFax component to a TApdTapiDevice on your form, then use the TApdTapiDevice.OnTapiCallerID event to detect the incoming call's CallerID tags.

If you don't want to use TAPI, use data triggers or ApdDataPackets to look for the CallerID tags that your modem uses. These are usually "DATE:xxx"#13, "TIME:xxx"#13, "NAME:xxx"#13 and "NMBR:xxx"#13. You will also want to watch for "RING" so you can tell when the modem detects the incoming ring signals. In the US, the CallerID information is transmitted between the 1st and 2nd rings. Once your "RING" trigger/packet detects the 2nd "RING", you can remove your triggers or disable your ApdDataPackets (you don't want them active while the fax is in progress), then call the ApdReceiveFax.StartReceive method. Note that most modems will require a special AT command to enable CallerID detection (usually AT#CID=1), add that to the ApdReceiveFax.ModemInit property.

Fax Printer Drivers FAQ

  • How do I recompile the printer drivers?

Recompiling the 16-bit printer driver for Windows 9x and ME:

The 16-bit printer driver source file is APFGEN.DPR. Since this is a 16-bit printer driver (the printing subsystem in these operating systems is 16-bit), you must compile this with Delphi 1. Delphi 1 was included with Delphi 2 through 4; other compilers did not include it. To build the printer driver, build APFGEN.DPR. You must define the PRNDRV compiler define, which prevents extra code from being included. When it is done compiling, rename the APFGEN.DLL to APFGEN.DRV and install it.

Recompiling the 32-bit printer driver for WinNT and 2000:

The 32-bit printer driver is broken into a few different pieces. The part that does the actual conversion and communicates with the TApdFaxDriverInterface component is APFAXCNV.DLL, which is compiled with any 32-bit version of Delphi. Simply recompile APFAXCNV.DPR and install APFAXCNV.DLL. The other parts are built using MS VC++6 and above, the source for those DLLs are in the APRO\PrnDrv\NT4 tree.

  • How do I install and use the Async Professional Fax Printer drivers for the different Windows versions?

Async Professional comes with a sample printer driver installation utility, PInst. PInst will install the appropriate printer driver for the environment it is running in: APFGEN.DRV (the generic 16-bit driver) for Windows9x and Windows ME - APFPDENT.DLL, APFAXCNV.DLL and APFMON40.DLL for Windows NT/2000.

To install the 16-bit printer driver (Windows 9x/ME), use the following method (you must add PDrvInst to your uses clause):

InstallDriver('APDGEN.DRV');

To install the 32-bit printer driver (Windows NT/2000), use the following method (you must add PDrvInNT to your uses clause):

InstallDriver32(path where the printer driver files are stored);

Upon completion of these methods, the global DriverInstallError variable will contain the result of the installation. See the PInst source for the possible values.

Our printer drivers require several files supplied on the Windows installation CD specific to the Windows version being used. For the 16-bit printer driver, the following files are required: UNIDRV.DLL, UNIDRV.HLP, and ICONLIB.DLL. For the 32-bit printer driver, the following files are required: RASDD.DLL, RASDDUI.DLL, RASDDUI.HLP. Note that the RASDD* files are not available on the Windows 2000 Professional CD, but the versions on the NT4 or Windows 2000 Server CD will work.

You can install the NT drivers using INF files rather than writing your own installation utility. You'll find INF files both for the printer drivers and for the port monitors in the INF40 directory for Windows NT 4.0. Installing the 16-bit printer drivers with INF files is discouraged due to the different ways the OS uses the INF settings.

To use the printer driver, simply print to it from any Windows application. The printer driver does not interface with the serial port or any APRO components (other than the TApdFaxDriverInterface component described below). The printer driver converts printer escape codes provided by the Windows printing subsystem into an APF file. By default, this file will be saved to "C:\DEFAULT.APF".

AdFaxCtl.pas implements a non-visual component, TApdFaxDriverInterface, for interfacing the fax system. The component communicates with the converter using a named pipe in NT, and through a hidden window class in other operating systems. If the converter detects that an application with the controller component is running on the spooler server, it notifies the component when it is about to start creating a new document file, and when printing of the document has finished. This makes it relatively easy to implement automated fax servers that can send off faxes automatically when the fax printer driver is used. The resulting APF file can also be renamed, or a specific path can be specified if the ApdFaxDriverInterface.FileName property is changed before the OnDocStart event exits.

ExFaxCtl is an example program, which implements a simplistic controller application for the fax printer driver. The example displays a memo control where each document is logged with the job name as printing starts and ends. The controller component on the form provides an output filename for the printer driver.

Note that under Windows 2000, the TApdFaxDriverInterface.DocName property will not contain the real name of the document being printed; instead DocName will be "APF Fax Printer, Job X". The X will be the number of the print job being submitted. The first print job after system startup will be named "APF Fax Printer, Job 2" because of the way that Windows 2000 initializes the printer.

For more information on the Async Professional Fax Printer Drivers see the APro Help file and manual.

Note that PInst is one of the example projects provided with Async Pro and falls under the general license agreement (you can not distribute this example).

Other components FAQ

  • Why is one of my status lights "sticking" in the ON state?

When a TApdStatusLight gets "stuck" in the ON state (i.e., it is lit), it is indicative that the port attached to the TApdSLController's ComPort property has been destroyed or closed, or that the TApdSLController's Monitoring property has been prematurely set to FALSE. Other things, such as flow control being imposed for extended periods of time, can cause the lights to appear stuck.

When the communications port is destroyed or closed or Monitoring is set FALSE, the triggers that the TApdSLController uses to do its work are destroyed, causing the status lights to stick in the state in which they were last displayed.

In addition, if the light that is sticking is the RXD light, the problem could be that incoming characters are not being removed from the port's input buffer. If no component on the form is calling GetChar in an OnTriggerAvail event handler, the RXD light will appear to stick. If necessary, add a bogus OnTriggerAvail handler to your program to ensure that incoming data is being read:

procedure TForm1.ApdComPort1TriggerAvail(CP: TObject; Count: Word);
var
  I : Cardinal;
begin
  for I := 1 to Count do
    ApdComPort1.GetChar;
end;

  • Why do triggers stop working when I have the status light controller turned on?

When the TApdSLController is active, it makes use of several of the modem status triggers. When these triggers are used by the status light controller, they are not available for use by anything else. Other modem status triggers will not be active.

If you need both the status lights and the triggers, then do not use the TApdSLController. Instead, manually set the Lit property of your status light in your own trigger handling code.

  • My status lights are not doing anything, why?

For the status lights to actually respond to changes in the modem status, you must set the status light controllers' Monitoring property to True. This must be done at runtime.

SourceForge.net Logo

This document maintained by the Async Professional Project.