In this chapter, you'll put together all the things you learned about TAPI in a single application. The TAPIFONE application is a complete single-line telephone device that runs on a Windows workstation. With a voice-data modem and sound card and this program up and running on your machine, you can completely eliminate the telephone handset from your desk.
In this program you'll add code for handling both inbound and outbound calls. You'll also give users access to the various TAPI dialog boxes and will maintain a set of configuration values for TAPIFONE in the Windows registry. You'll be able to write (and store) call notes on each outbound call made through TAPIFONE.
You'll use Data Access objects to maintain a simple phone book database and you'll also be able to keep track of outbound calls in a call log. This log can be exported to a comma-separated value (CSV) text file that can be loaded into Excel or Word.
When you complete this project you should have a full understanding of TAPI services and how you can use them to build full-featured telephone devices in Visual Basic.
Note |
The best hardware configuration for this application is a voice-data modem and a sound card with external speakers and a microphone. You can also use this application with a standard modem and an attached telephone handset, but you'll only be able to make outbound calls. |
The TAPIFONE application is designed to replace the telephone handset that appears on your desktop. As long as your Windows workstation has a voice-data modem or telephony card and an external microphone and speakers, you can use the TAPIFONE for all your in- and outbound voice call processing.
The TAPIFONE project has three forms and three code modules. The forms are:
The three code modules in the project are:
The TAPILine and TAPICall modules need not be keyed in since they are included on the CD-ROM that comes with this book. These are stock structures, constants, and API declares for the TAPILINE control covered earlier in this book (see Chapter 26, "TAPI Tools-Using the TAPILINE Control"). The libTAPI module will be built for this chapter.
Tip |
If you do not want to enter all the code, you can locate and load the TAPIFONE project on the CD-ROM that ships with this book. |
Along with the standard dial keypad, the TAPIFONE application has a Phone Book page that lists the person's name and phone number along with the last day and time that person was called using TAPIFONE. Users can select a name from this list and press the Dial button directly from the phonebook. As each call is placed, users will be asked to add call notes. These call notes are written to a log that can be viewed online or exported to a comma-delimited text file for further manipulation.
Users can set several TAPIFONE parameters to control the behavior of the application. These control values are stored in the Windows registry and recalled each time the program is run. Values are stored in the HKEY_CURRENT_USER\Software\Visual Basic and VBA Program Settings\TAPIFONE branch of the registry tree. Key values stored there are:
The first step in building the TAPIFONE project is to start Visual Basic and create a new project. Load the TAPILINE.BAS and TAPICALL.BAS modules from a previous project (See Chapters 26 and 28 for more on these modules) by selecting File | Add File from the main menu. Once you've added these two BAS modules, save the project as TAPIFONE.VBP.
Next you need to add a new module to the project (Insert | Module). Set its Name property to LibTAPIWrapper and save it as LIBTAPI.BAS.
First, add some declaration code to the module. You need to declare a handful of public variables to handle flags and global values for the project. You'll also add two private (module-level) variables used to handle TAPI device information. Finally, you'll add a user-defined type to make it easy to place outbound calls. Open the declaration section of the form and enter the code shown in Listing 30.1.
Listing 30.1. Adding the declaration code to the LIBTAPI module.
'
Private udtLineDevCaps() As LINEDEVCAPS
Private cLineDevCapsExtra() As String * 2048
'
Public gDialString As String ' phone number to dial
Public gPlaceCall As Boolean ' ok to place call
Public gName As String ' name to call
Public gLineDev As Integer ' selected line device
'
Public gMinimize As Integer ' minimize at start
Public gMonitor As Integer ' monitor at startup
Public gOutLog As Integer ' log all outbound calls
Public gOrigNumber As String ' for calledID
Public gStartPage As Integer ' for default start page
'
Type DialParams
DeviceNumber As Integer
DialableString As String
Privilege As Long
MediaMode As Long
End Type
Next, add the routine to handle the initialization of TAPI services for the application. This routine will actually perform three things:
Add a new function called initTAPI to your project and enter the code shown in Listing 30.2.
Listing 30.2. Adding the initTAPI function.
Public Function InitTAPI(ctrl As Control, cAppName As String) As Long
'
' perform initial startup of TAPI services
'
Dim lRtn As Long
Dim iNumDev As Long
Dim iLoop As Integer
'
TAPIClearHandles ctrl ' keep it clean!
'
' start it up
lRtn = ctrl.LineInitialize(cAppName)
If lRtn < 0 Then
GoTo TAPIErr
End If
'
' confirm devices
iNumDev = ctrl.NumDevices
For iLoop = 0 To iNumDev - 1
lRtn = ctrl.LineNegotiateAPIVersion(iLoop, 65536, 65540)
If lRtn < 0 Then
GoTo TAPIErr
End If
Next
'
' fill line device capabilities structures
ReDim Preserve udtLineDevCaps(iNumDev)
ReDim Preserve cLineDevCapsExtra(iNumDev)
'
For iLoop = 0 To iNumDev - 1
lRtn = ctrl.LineGetDevCaps(iLoop)
If lRtn = 0 Then
LineDevCapsFunc TAPI_READ, udtLineDevCaps(iLoop), ÂcLineDevCapsExtra(iLoop)
cLineDevCapsExtra(iLoop) = Clean(cLineDevCapsExtra(iLoop))
End If
Next
'
GoTo TAPIExit
'
TAPIErr:
MsgBox "Unable to Start TAPI Services", vbCritical, "InitTAPI"
End
'
TAPIExit:
InitTAPI = lRtn
'
End Function
You'll notice that there are two parameters for the function. The first is the TAPILINE control used on the main form. The second is the application name when initializing TAPI services. You'll also notice that this routine loads the capabilities of each device and stores that information in a private array. This array can be accessed using another function to be defined later in this section.
Note |
You might be thinking this kind of code should be placed in a Visual Basic class module. And you'd be right-except for one little thing. Since the TAPILINE control must be placed on a form, we cannot use a class module to handle properties and methods on the control. Forms and controls cannot be encapsulated in class modules. |
Next, you need to add the routine used to read the device capabilities stored in the udtLineDevCaps array. Add a new function to the project called ReadLineDevCaps and add the code shown in Listing 30.3.
Listing 30.3. Adding the ReadLineDevCaps function.
Public Function ReadLineDevCaps(iDevNum As Integer, udtLineDev As LINEDEVCAPS, ÂcExtra As String) As Long
'
' return line caps
'
On Error GoTo LocalErr
'
Dim lRtn As Long
'
lRtn = 0
udtLineDev = udtLineDevCaps(iDevNum)
cExtra = Trim(cLineDevCapsExtra(iDevNum))
'
Exit Function
'
LocalErr:
lRtn = Err
'
End Function
Next add the routine that will be called to place an outbound call. Add a new function called TAPIDial and enter the code from Listing 30.4.
Listing 30.4. Adding the TAPIDial function.
Public Function TAPIDial(ctrl As Control, dpType As DialParams) As Long
'
' dial a selected number
'
Dim lRtn As Long
'
lRtn = ctrl.LineOpen(dpType.DeviceNumber, 0, dpType.Privilege, ÂdpType.MediaMode)
If lRtn < 0 Then
TAPIDial = lRtn
Exit Function
End If
'
SetCallParams dpType.MediaMode ' load defaults
'
' place the call
lRtn = ctrl.LineMakeCall(dpType.DialableString, 1)
'
TAPIDial = lRtn
'
End Function
You'll notice that this routine uses the DialParams user-defined type. It also calls another custom routine-SetCallParams. You'll define this next. Add a new subroutine called SetCallParams to the project and enter the code shown in Listing 30.5.
Listing 30.5. Adding the SetCallParams routine.
Public Sub SetCallParams(lMode As Long)
'
' set up call params data
'
Dim cp As LINECALLPARAMS
Dim cpx As String
'
' defaults for voice calls
cp.dwBearerMode = LINEBEARERMODE_VOICE
cp.dwMinRate = 9.6
cp.dwMaxRate = 28.8
cp.dwMediaMode = lMode
cp.dwCallParamFlags = 0
cp.dwAddressMode = lMode
cp.DialParams.dwDialPause = 0
cp.DialParams.dwDialSpeed = 0
cp.DialParams.dwDigitDuration = 0
cp.DialParams.dwWaitForDialtone = 0
cp.dwOrigAddressSize = Len(Trim(gOrigNumber))
cp.dwOrigAddressOffset = 0
cp.dwCalledPartySize = 0
cp.dwCommentSize = 0
cp.dwUserUserInfoSize = 0
cp.dwHighLevelCompSize = 0
cp.dwLowLevelCompSize = 0
cp.dwDevSpecificSize = 0
'
cpx = Trim(gOrigNumber)
cp.dwTotalSize = Len(cp) + Len(cpx)
LineCallParamsFunc TAPI_WRITE, cp, cpx
'
End Sub
This routine sets an important TAPI structure. This structure contains information about the type of call that will be requested. Notice that the gOrigNumber variable is used to fill in the originating address. This will tell those who have caller ID who you are when they receive your calls.
There is one more high-level routine used when placing a call. This is the routine that will fill the DialParams structure with the actual number to dial and the type of call to make. Add a new subroutine called TAPIPlaceCall to the project and enter the code from Listing 30.6.
Listing 30.6. Adding the TAPIPlaceCall routine.
Public Sub TAPIPlaceCall(ctrl As Control, cdialtarget As String)
'
Dim lRtn As Long
Dim cMsg As String
Dim dpValue As DialParams
'
dpValue.DeviceNumber = gLineDev
dpValue.Privilege = LINECALLPRIVILEGE_NONE
dpValue.MediaMode = LINEMEDIAMODE_INTERACTIVEVOICE
dpValue.DialableString = cdialtarget ' number to call
'
lRtn = TAPIDial(ctrl, dpValue)
If lRtn < 0 Then
cMsg = "TAPIDial - " & LineErr(lRtn)
GoTo LocalErr
End If
'
Exit Sub
'
LocalErr:
If Err <> 0 Then
lRtn = Err
cMsg = Error$
End If
'
MsgBox cMsg, vbCritical, "Dialing Err[" & Hex(lRtn) & "]"
'
End Sub
Only three support routines remain to be added. All three deal with the closing down of TAPI services. One, TAPIHangUp is used to gracefully end an active call. The TAPIClearHandles routine cleans up control properties after a call is completed. Finally, the TAPIShutdown routine closes down all TAPI services for the application. Add the three routines shown in Listing 30.7 to your project.
Listing 30.7. Adding TAPIHangUp, TAPIClearHandles, and TAPIShutdown.
Public Sub TAPIHangUp(ctrl As Control)
'
' hang up any current call
'
ctrl.LineDrop "", 0
ctrl.LineDeallocateCall
ctrl.LineClose
'
End Sub
Public Sub TAPIClearHandles(ctrl As Control)
'
' clean up handles to a call
'
ctrl.HandleToCall = 0
ctrl.LineHandle = 0
ctrl.AddressID = 0
'
End Sub
Public Sub TAPIShutdown(ctrl As Control)
'
' close down TAPI services
'
ctrl.LineShutdown
'
End Sub
Those are all the routines for the LIBTAPI.BAS module. Be sure to save the module and the project (TAPIFOINE.VBP) before you continue.
The main form for the TAPIFONE project is the frmTAPI form. This form uses a tabbed dialog box to present five different services from one form:
The form also contains a menu that allows users to view information about the application (Help | About), exit the program (File | Exit), and access TAPI configuration dialog boxes (Configure...).
The next few sections show you how to lay out the frmTAPI form. Since a tabbed dialog box is used, you are actually building five different dialog boxes in one. Refer to the figures in each section while adding the controls shown in the accompanying tables. Be sure to add the tab control first and to draw all the other controls on the tab control workspace. This will ensure that the other controls are child controls of the tab control.
Before building the details of each tab, you need to add the tab control itself along with a few command buttons. Refer to Table 30.1 and Figure 30.1 when adding these controls.
Figure 30.1 : Adding the base controls to the frmTAPI form.
Control | Property | Settings |
VB.Form | Name | frmTAPI |
Caption | "Form1" | |
Left | 1635 | |
LinkTopic | "Form1" | |
MaxButton | 0'False | |
Top | 1665 | |
Width | 5685 | |
VB.CommandButton | Name | cmdButtons |
Caption | "E&xit" | |
Height | 300 | |
Index | 3 | |
Left | 4140 | |
TabIndex | 39 | |
Top | 3480 | |
Width | 1200 | |
VB.CommandButton | Name | cmdButtons |
Caption | "&Start Monitor" | |
Height | 300 | |
Index | 0 | |
Left | 180 | |
TabIndex | 33 | |
Top | 3480 | |
Width | 1200 | |
VB.CommandButton | Name | cmdButtons |
Caption | "&Dial" | |
Height | 300 | |
Index | 1 | |
Left | 1500 | |
TabIndex | 32 | |
Top | 3480 | |
Width | 1200 | |
VB.CommandButton | Name | cmdButtons |
Caption | "&HangUp" | |
Height | 300 | |
Index | 2 | |
Left | 2820 | |
TabIndex | 31 | |
Top | 3480 | |
Width | 1200 | |
TabDlg.SSTab | Name | SSTab1 |
Height | 3255 | |
Left | 120 | |
TabIndex | 17 | |
Top | 120 | |
Width | 5295 | |
TabsPerRow | 5 | |
Tabs | 5 | |
Style | 1 | |
TabCaption(0) | "Dial Pad" | |
TabCaption(1) | "Phone Book" | |
TabCaption(2) | "Call Log" | |
TabCaption(3) | "Lines" | |
TabCaption(4) | "SetUp" | |
VB.Label | Name | lblStatus |
BorderStyle | 1 'Fixed Single | |
Caption | "Label1" | |
Height | 255 | |
Left | 120 | |
TabIndex | 16 | |
Top | 3900 | |
Width | 5295 |
After you've added the base controls, save the form as FRMTAPI.FRM before continuing.
The first page of the dialog box is the Dial Pad. This provides the user with a keypad similar to that found on desktop phones. The user can also type the phone number directly into the text box, perform a redial on the last number dialed, clear the text box, or use its contents as the start of a new address listing.
Refer to Figure 30.2 and Table 30.2 when laying out this page.
Figure 30.2 : Laying out the Dial Pad page
Warning |
Be sure to place the Frame control on the dialog page first. Also, you'll want to add the small command buttons using the control array feature of Visual Basic 4.0. |
Control Name | Property | Settings |
VB.Frame | Name | FraDial |
Height | 2475 | |
Left | 120 | |
TabIndex | 18 | |
Top | 480 | |
Width | 2055 | |
VB.CommandButton | Name | cmdKey |
Caption | "1" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 0 | |
Left | 180 | |
TabIndex | 30 | |
Top | 240 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "2" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 1 | |
Left | 780 | |
TabIndex | 29 | |
Top | 240 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "3" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Left | 1380 | |
TabIndex | 28 | |
Top | 240 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "4" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 3 | |
Left | 180 | |
TabIndex | 27 | |
Top | 780 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "5" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 4 | |
Left | 780 | |
TabIndex | 26 | |
Top | 780 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "6" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 5 | |
Left | 1380 | |
TabIndex | 25 | |
Top | 780 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "7" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 6 | |
Left | 180 | |
TabIndex | 24 | |
Top | 1320 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "8" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 7 | |
Left | 780 | |
TabIndex | 23 | |
Top | 1320 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "9" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 8 | |
Left | 1380 | |
TabIndex | 22 | |
Top | 1320 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "*" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 9 | |
Left | 180 | |
TabIndex | 21 | |
Top | 1860 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "0" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 10 | |
Left | 780 | |
TabIndex | 20 | |
Top | 1860 | |
Width | 450 | |
VB.CommandButton | Name | cmdKey |
Caption | "#" | |
Font | ||
name="MS Serif" | ||
charset=0 | ||
weight=700 | ||
size=13.5 | ||
Height | 450 | |
Index | 11 | |
Left | 1380 | |
TabIndex | 19 | |
Top | 1860 | |
Width | 450 | |
VB.Label | Name | lblMonitor |
BackStyle | 0 'Transparent | |
Caption | "Monitoring Inbound Calls" | |
Font | name="MS Sans Serif" | |
charset=0 | ||
weight=700 | ||
size=8.25 | ||
ForeColor | &H000000FF& (Red) | |
Height | 735 | |
Left | 2460 | |
TabIndex | 47 | |
Top | 420 | |
Visible | 0 'False | |
Width | 975 | |
TapilineLib.Tapiline | Name | Tapiline1 |
Left | 2520 | |
Top | 1080 | |
VB.Image | Name | Image1 |
Height | 915 | |
Left | 3000 | |
Stretch | -1 'True | |
Top | 480 | |
Width | 2055 |
The next tab in the form is the Phone Book tab. This tab is a data entry form for the phone book. Users can also press the Dial button to place a call from this form. Use Figure 30.3 and Table 30.3 to place the controls on the form.
Figure 30.3 : Adding the Phone Book controls
Control Name | Property | Settings |
VB.Data | Name | Data2 |
Caption | "Data2" | |
Connect | "Access" | |
DatabaseName | "" | |
Exclusive | 0 'False | |
Height | 300 | |
Left | -72720 | |
Options | 0 | |
ReadOnly | 0 'False | |
RecordsetType | 1 'Dynaset | |
RecordSource | "" | |
Top | 1080 | |
Visible | 0 'False | |
Width | 1140 | |
VB.Data | Name | Data3 |
Caption | "Data3" | |
Connect | "Access" | |
DatabaseName | "" | |
Exclusive | 0 'False | |
Height | 300 | |
Left | -73980 | |
Options | 0 | |
ReadOnly | 0 'False | |
RecordsetType | 1 'Dynaset | |
RecordSource | "" | |
Top | 1800 | |
Visible | 0 'False | |
Width | 2175 | |
VB.TextBox | Name | txtName |
DataField | "Name" | |
DataSource | "Data1" | |
Height | 300 | |
Left | -73440 | |
TabIndex | 13 | |
Text | "Text2" | |
Top | 2100 | |
Width | 3600 | |
VB.CommandButton | Name | cmdDialPad |
Caption | "&Add to Phone Book" | |
Height | 300 | |
Index | 2 | |
Left | 2520 | |
TabIndex | 37 | |
Top | 2640 | |
Width | 2400 | |
VB.CommandButton | Name | cmdDialPad |
Caption | "&Clear Dial String" | |
Height | 300 | |
Index | 1 | |
Left | 2520 | |
TabIndex | 36 | |
Top | 2280 | |
Width | 2400 | |
VB.CommandButton | Name | cmdDialPad |
Caption | "&ReDial Number" | |
Height | 300 | |
Index | 0 | |
Left | 2520 | |
TabIndex | 35 | |
Top | 1920 | |
Width | 2400 | |
VB.CommandButton | Name | cmdData |
Caption | "R&estore" | |
Height | 300 | |
Index | 3 | |
Left | -74760 | |
TabIndex | 8 | |
Top | 1560 | |
Width | 1200 | |
VB.CommandButton | Name | cmdData |
Caption | "&Update" | |
Height | 300 | |
Index | 2 | |
Left | -74760 | |
TabIndex | 9 | |
Top | 1200 | |
Width | 1200 | |
VB.TextBox | Name | txtDialString |
Alignment | 1 'Right Justify | |
Height | 300 | |
Left | 2520 | |
TabIndex | 34 | |
Text | "Text6" | |
Top | 1500 | |
Width | 2400 | |
VB.CommandButton | Name | cmdData |
Caption | "&Remove" | |
Height | 300 | |
Index | 1 | |
Left | -74760 | |
TabIndex | 10 | |
Top | 840 | |
Width | 1200 | |
VB.CommandButton | Name | cmdData |
Caption | "&Add" | |
Height | 300 | |
Index | 0 | |
Left | -74760 | |
TabIndex | 11 | |
Top | 480 | |
Width | 1200 | |
VB.Data | Name | Data1 |
Caption | "Data1" | |
Connect | "Access" | |
DatabaseName | "" | |
Exclusive | 0 'False | |
Height | 315 | |
Left | -72600 | |
Options | 0 | |
ReadOnly | 0 'False | |
RecordsetType | 1 'Dynaset | |
RecordSource | "" | |
Top | 1980 | |
Visible | 0 'False | |
Width | 1695 | |
VB.TextBox | Name | txtLastCalled |
DataField | "Last Called" | |
DataSource | "Data1" | |
Height | 300 | |
Left | -73440 | |
TabIndex | 15 | |
Text | "Text2" | |
Top | 2820 | |
Width | 3600 | |
VB.TextBox | Name | txtPhoneNumber |
DataField | "PhoneNumber" | |
DataSource | "Data1" | |
Height | 300 | |
Left | -73440 | |
TabIndex | 14 | |
Text | "Text2" | |
Top | 2460 | |
Width | 3600 | |
VB.Image | Name | Image2 |
Height | 1395 | |
Left | -71160 | |
Stretch | -1 'True | |
Top | 540 | |
Width | 1275 | |
MSDBGrid.DBGrid | Name | DBGrid1 |
Bindings | "frmTAPI.frx":B60A | |
Height | 2295 | |
Left | -74940 | |
OleObjectBlob | "frmTAPI.frx":B618 | |
TabIndex | 38 | |
Top | 420 | |
Width | 5115 | |
MSDBCtls.DBList | Name | DBList1 |
Bindings | "frmTAPI.frx":BD20 | |
Height | 1425 | |
Left | -73440 | |
TabIndex | 12 | |
Top | 480 | |
Width | 2175 | |
_Version | 65536 | |
_ExtentX | 3836 | |
_ExtentY | 2514 | |
_StockProps | 77 | |
ForeColor | -2147483640 | |
BackColor | -2147483643 | |
ListField | "Name" | |
BoundColumn | "Name" | |
VB.Label | Name | Label3 |
BorderStyle | 1 'Fixed Single | |
Caption | "Last Called:" | |
Height | 300 | |
Left | -74760 | |
TabIndex | 5 | |
Top | 2820 | |
Width | 1200 | |
VB.Label | Name | Label2 |
BorderStyle | 1 'Fixed Single | |
Caption | "Phone Number:" | |
Height | 300 | |
Left | -74760 | |
TabIndex | 6 | |
Top | 2460 | |
Width | 1200 | |
VB.Label | Name | Label1 |
BorderStyle | 1 'Fixed Single | |
Caption | "Name:" | |
Height | 300 | |
Left | -74760 | |
TabIndex | 7 | |
Top | 2100 | |
Width | 1200 |
After you've built this page, be sure to save the project before continuing.
The Call Log tab shows the user the list of all calls logged through the TAPIFONE application. Refer to Figure 30.4 and Table 30.4 when you build this page.
Figure 30.4 : Building the Call Log page
Control Name | Property | Settings |
VB.CommandButton | Name | cmdLog |
Caption | "&Refesh" | |
Default | -1 'True | |
Height | 300 | |
Index | 1 | |
Left | -72300 | |
TabIndex | 45 | |
Top | 2820 | |
Width | 1200 | |
VB.CommandButton | Name | cmdLines |
Cancel | -1 'True | |
Caption | "&Cancel" | |
Height | 300 | |
Index | 1 | |
Left | -72300 | |
TabIndex | 43 | |
Top | 2820 | |
Width | 1200 | |
VB.CommandButton | Name | cmdLines |
Caption | "&Apply" | |
Height | 300 | |
Index | 0 | |
Left | -70980 | |
TabIndex | 42 | |
Top | 2820 | |
Width | 1200 | |
VB.CommandButton | Name | cmdLog |
Caption | "&Clear" | |
Height | 300 | |
Index | 0 | |
Left | -70980 | |
TabIndex | 40 | |
Top | 2820 | |
Width | 1200 | |
VB.Label | Name | Label4 |
BackColor | &H00C0C0C0& | |
Caption | "Originating Number" | |
Height | 315 | |
Left | -74700 | |
TabIndex | 46 | |
Top | 2400 | |
Width | 2175 | |
VB.Label | Name | lblLines |
Caption | "Select a Line Device:" | |
Height | 255 | |
Left | -74760 | |
TabIndex | 44 | |
Top | 480 | |
Width | 3555 | |
VB.Image | Name | Image3 |
Height | 1815 | |
Left | -71040 | |
Picture | "frmTAPI.frx":52E4 | |
Stretch | -1 'True | |
Top | 720 | |
Width | 1155 | |
VB.CommandButton | Name | cmdLog |
Caption | "&Export" | |
Height | 300 | |
Index | 2 | |
Left | -73620 | |
TabIndex | 48 | |
Top | 2820 | |
Width | 1200 |
As a safety precaution, save this form before continuing.
The Line tab allows user to select which line is active for the project. Refer to Figure 30.5 and Table 30.5 when building this page.
Figure 30.5 : Adding the line page
Control Name | Property | Settings |
VB.ListBox | Name | List1 |
Height | 1815 | |
Left | -74760 | |
TabIndex | 41 | |
Top | 720 | |
Width | 3615 | |
VB.CommandButton | Name | cmdLines |
Cancel | -1 'True | |
Caption | "&Cancel" | |
Height | 300 | |
Index | 1 | |
Left | -72300 | |
TabIndex | 43 | |
Top | 2820 | |
Width | 1200 | |
VB.CommandButton | Name | cmdLines |
Caption | "&Apply" | |
Height | 300 | |
Index | 0 | |
Left | -70980 | |
TabIndex | 42 | |
Top | 2820 | |
Width | 1200 | |
VB.Label | Name | lblLines |
Caption | "Select a Line Device:" | |
Height | 255 | |
Left | -74760 | |
TabIndex | 44 | |
Top | 480 | |
Width | 3555 | |
VB.Image | Name | Image3 |
Height | 1815 | |
Left | -71040 | |
Stretch | -1 'True | |
Top | 720 | |
Width | 1155 |
Before building the last tab for this form, save the form and project.
The Setup tab contains a small group of controls that are used to update registry settings. Refer to Figure 30.6 and Table 30.6 to build this last page of the form.
Figure 30.6 : Building the Setup page
Control Name | Property | Settings |
VB.Image | Name | Image4 |
Height | 1875 | |
Left | -71880 | |
Picture | "frmTAPI.frx":0442 | |
Stretch | -1 'True | |
Top | 420 | |
Width | 1815 | |
VB.CheckBox | Name | chkMinimize |
Alignment | 1 'Right Justify | |
Caption | "Minimize On StartUp" | |
Height | 300 | |
Left | -74700 | |
TabIndex | 52 | |
Top | 1440 | |
Width | 2595 | |
VB.Frame | Name | fraStartup |
Caption | "Startup Page" | |
Height | 915 | |
Left | -74700 | |
TabIndex | 49 | |
Top | 480 | |
Width | 2595 | |
VB.OptionButton | Name | optStartup |
Caption | "Phone Book" | |
Height | 255 | |
Index | 1 | |
Left | 180 | |
TabIndex | 51 | |
Top | 540 | |
Width | 1275 | |
VB.OptionButton | Name | optStartup |
Caption | "Dial Pad" | |
Height | 255 | |
Index | 0 | |
Left | 180 | |
TabIndex | 50 | |
Top | 240 | |
Width | 1275 | |
VB.CommandButton | Name | cmdStartUp |
Caption | "&Cancel" | |
Height | 300 | |
Index | 1 | |
Left | -72300 | |
TabIndex | 0 | |
Top | 2820 | |
Width | 1200 | |
VB.CommandButton | Name | cmdStartUp |
Caption | "&Apply" | |
Height | 300 | |
Index | 0 | |
Left | -70980 | |
TabIndex | 1 | |
Top | 2820 | |
Width | 1200 | |
VB.TextBox | Name | txtOrigNumber |
Height | 300 | |
Left | -72300 | |
TabIndex | 4 | |
Text | "Text1" | |
Top | 2400 | |
Width | 2475 | |
VB.CheckBox | Name | chkOutLog |
Alignment | 1 'Right Justify | |
Caption | "Log all OutBound Calls" | |
Height | 300 | |
Left | -74700 | |
TabIndex | 3 | |
Top | 2040 | |
Width | 2595 | |
VB.CheckBox | Name | chkMonitor |
Alignment | 1 'Right Justify | |
Caption | "Monitor Calls At Start Up" | |
Height | 300 | |
Left | -74700 | |
TabIndex | 2 | |
Top | 1740 | |
Width | 2595 |
This is the last of the dialog pages for the main form. Save the form as FRMTAPI.FRM and the project as TAPIFONE.VBP.
The main form also has a set of menu options. These options allow the user to call up TAPI-generated dialog boxes to control communication between TAPI and your programs. Refer to Figure 30.7 and Table 30.7 when building the menu.
Figure 30.7 : Building the FRMTAPI menu
Menu | Property | Value |
VB.Menu | Name | mnuFile |
Caption | "&File" | |
VB.Menu | Name | mnuFileExit |
Caption | "E&xit" | |
VB.Menu | Name | mnuConf |
Caption | "Configure" | |
VB.Menu | Name | mnuConfItem |
Caption | "&Service Provider..." | |
Index | 0 | |
VB.Menu | Name | mnuConfItem |
Caption | "&Line Device..." | |
Index | 1 | |
VB.Menu | Name | mnuConfItem |
Caption | "&Dialing Properties..." | |
Index | 2 | |
VB.Menu | Name | mnuHelp |
Caption | "&Help" | |
VB.Menu | Name | mnuHelpAbout |
Caption | "About &TAPILine" | |
Index | 0 | |
VB.Menu | Name | mnuHelpAbout |
Caption | "About &Virtual Phone" | |
Index | 1 |
There are several code routines that need to be added to the frmTAPI form. These routines fall into four main groups:
The first form-level code is the variable declaration code. Add the code shown in Listing 30.8 to the declaration section of the form.
Listing 30.8. Adding the form-level declarations.
Option Explicit
'
Dim lAdd As Boolean ' phonebook adding flag
Dim lMonitor As Boolean ' call monitoring flag
Dim lDevErr As Boolean ' line device select flag
'
Dim iWidth As Integer ' remember my size
Dim iHeight As Integer ' remember
'
Dim uLineDevCaps As LINEDEVCAPS ' line devices
Dim cLineDevCapsExtra As String ' extra data strings
Next, add the code for the Form_Load event. This code calls several support routines you'll add later. Enter the code from Listing 30.9 into the Form_Load event of the form.
Listing 30.9. Adding the Form_Load event code.
Private Sub Form_Load()
'
On Error GoTo LocalErr
'
Dim lRtn As Long
Dim cMsg As String
'
' save for later
iWidth = Me.Width
iHeight = Me.Height
'
' initialize TAPI services
lRtn = InitTAPI(Me.Tapiline1, App.EXEName)
If lRtn < 0 Then
cMsg = "InitTAPI - " & LineErr(lRtn)
GoTo LocalErr
End If
'
LoadImages ' fill in image controls
InitDB ' set up data connections
LoadDevices ' get device names
ReadStartup ' get registry settings
'
' check startup page
If gLineDev = -1 Then
SSTab1.Tab = 3 ' gotta select a device first
Else
SSTab1.Tab = gStartPage ' user selection
End If
'
' check monitor at startup
If gMonitor And gLineDev <> -1 Then
lblMonitor.Visible = True
lMonitor = False ' pretend it's off
cmdButtons_Click 0 ' start monitoring
End If
'
' check for minimize on startup
If gMinimize And gLineDev <> -1 Then
Me.WindowState = vbMinimized
End If
'
' clean up controls
txtDialString = ""
lblstatus = ""
'
' setup this form
Me.Icon = LoadPicture(App.Path & "\phone04.ico")
Me.Caption = "TAPILine Virtual Phone"
Me.Left = (Screen.Width - Me.Width) / 2
Me.Top = (Screen.Height - Me.Height) / 2
'
Exit Sub
'
LocalErr:
If Err <> 0 Then
lRtn = Err
cMsg = Error$
End If
'
MsgBox cMsg, vbCritical, "Form_Load Err[" & Hex(lRtn) & "]"
TAPIShutdown Me.Tapiline1
MousePointer = vbNormal
End ' that's it!
'
End Sub
Listing 30.10 shows the code for the Form_Resize and Form_Unload events. Add this to your project.
Listing 30.10. Adding the Form_Resize and Form_Unload event code.
Private Sub Form_Resize()
'
' prevent resizing
'
If Me.WindowState <> vbMinimized _
And Me.WindowState <> vbMaximized Then
Me.Width = iWidth
Me.Height = iHeight
End If
'
End Sub
Private Sub Form_Unload(Cancel As Integer)
'
TAPIHangUp Me.Tapiline1 ' hangup any open line
TAPIShutdown Me.Tapiline1 ' close out TAPI Services
'
End Sub
Listing 30.11 shows the code that belongs in the SSTab1_Click event. This is fired each time the user clicks to change a tab. This code will continue to remind the user to select a line device, if needed.
Listing 30.11. Coding the SSTab1_Click event.
Private Sub SSTab1_Click(PreviousTab As Integer)
'
' force user to select a device, if needed
If lDevErr = True Then
MsgBox "You must select a Line Device!", vbCritical, "No Line Device"
SSTab1.Tab = 3
End If
'
End Sub
The last bit of form-level code is the code for the Tapiline1_TapiCallBack event. This code is the same code you used in the TAPIANS project of Chapter 28. Add the code shown in Listing 30.12 to the TAPICallBack event of the TAPILINE control.
Listing 30.12. Coding the TAPICallBack event.
Private Sub Tapiline1_TapiCallBack(ByVal hDevice As Long, ByVal dwMessage As Long, ÂByVal dwInstance As Long, ByVal dwParam1 As Long, ByVal dwParam2 As Long, ByVal ÂdwParam3 As Long)
'
' handle TAPI messages
'
Dim cMsg As String
'
' handle inbound call actions
Select Case dwMessage
Case LINE_CALLSTATE ' state of call on line changed
Select Case dwParam1
Case LINECALLSTATE_OFFERING ' get call handle
Tapiline1.HandleToCall = hDevice ' update handle to call
Beep ' tell user a call appeared
Me.WindowState = vbNormal ' pop up, if needed
Case LINECALLSTATE_IDLE ' they hung up on me!
cmdButtons_Click 2 ' hangup process
TAPIClearHandles Me.Tapiline1
End Select
Case LINE_CLOSE ' line was closed
cmdButtons_Click 2 ' force hangup
End Select
'
' report to status line
lblstatus = TapiCallBackHandler(hDevice, dwMessage, dwInstance, dwParam1, ÂdwParam2, dwParam3)
'
End Sub
That's it for the form-level code. Save the form and project before continuing.
There are three main menu branches. The first is the File menu. It has only one submenu-Exit. Listing 30.13 shows the code you need to add to the mnuFileExit_Click event.
Listing 30.13. Coding the mnuFileExit_Click event.
Private Sub mnuFileExit_Click()
'
Unload Me
'
End Sub
The next branch in the menu tree is the Configure branch. This was built as a menu array with three elements. Listing 30.14 shows the code that should be added to the mnuConfItem_Click event.
Listing 30.14. Coding the mnuConfItem_Click event.
Private Sub mnuConfItem_Click(Index As Integer)
'
' handle TAPI configuration dialogs
'
Select Case Index
Case 0 ' service provider
Tapiline1.PermanentProviderID = 1
Tapiline1.LineConfigProvider Me.hWnd
Case 1 ' line device
Tapiline1.LineConfigDialog 5, Me.hWnd, "tapi/line"
Case 2 ' dialing properties
Tapiline1.LineTranslateDialog 5, Me.hWnd, ""
End Select
'
End Sub
The final menu routine is the one that handles the Help menu branch. This branch also contains a menu array for displaying the TAPILINE control About box and a custom About box for the application (you'll build it later). Add the code in Listing 30.15 to the mnuHelpAbout_Click event.
Listing 30.15. Coding the mnuHelpAbout_Click event.
Private Sub mnuHelpAbout_Click(Index As Integer)
'
' handle about boxes
'
Select Case Index
Case 0 ' tapiline
Me.Tapiline1.AboutBox
Case 1 ' virtual phone
frmVPhone.Show vbModal
End Select
'
End Sub
That's the end of the menu-level routines. Save the form and project before continuing on to the page-level routines.
There are ten page-level routines in the frmTAPI form. Most of these routines are for handling selections of button array commands. Listing 30.16 shows the code for the cmdButtons_Click event. This handles the button presses on the bottom of the form. Add this code to your project.
Listing 30.16. Coding the cmdButtons_Click event.
Private Sub cmdButtons_Click(Index As Integer)
'
' handle user selections on main buttons
'
Select Case Index
Case 0 ' start monitor
If cmdButtons(0).Caption = "&Start Monitor" Then
lMonitor = LineMonitor(Me.Tapiline1, True)
Else
lMonitor = LineMonitor(Me.Tapiline1, False)
End If
'
If lMonitor = True Then
cmdButtons(0).Caption = "&End Monitor"
lblMonitor.Visible = True
Else
cmdButtons(0).Caption = "&Start Monitor"
lblMonitor.Visible = False
End If
Case 1 ' Dial Number
'
' check for call monitoring
If lMonitor = True Then
cmdButtons_Click 0 ' toggle off monitoring
End If
'
Select Case SSTab1.Tab ' check selected tab
Case 0 ' dialpad
gDialString = txtDialString
gName = "<Unknown>"
frmCall.Show vbModal
If gPlaceCall = True Then
TAPIPlaceCall frmTAPI.Tapiline1, gDialString
End If
Case 1 ' phonebook
gDialString = txtPhoneNumber
gName = txtName
frmCall.Show vbModal
If gPlaceCall = True Then
TAPIPlaceCall frmTAPI.Tapiline1, gDialString
End If
Case 2 ' call log
' no action
Case 3 ' properties
' no action
End Select
Case 2 ' Hang Up
'
' check call monitoring
If lMonitor = True Then
cmdButtons_Click 0 ' toggle monitoring off
End If
'
TAPIHangUp Me.Tapiline1
lblstatus = ""
Case 3 ' exit
Unload Me
End Select
'
End Sub
Next you need to add code to handle the command buttons on the Dial Pad itself. Enter the code from Listing 30.17 into the cmdDialPad_Click event.
Listing 30.17. Coding the cmdDialPad_Click event.
Private Sub cmdDialPad_Click(Index As Integer)
'
' handle user selections on dial pad page
'
Select Case Index
Case 0 ' redial last number
cmdButtons_Click 1 ' press dial
Case 1 ' clear dialstring
txtDialString = ""
Case 2 ' add a new record to the phone book
cmdData_Click 0 ' add a new record
txtPhoneNumber = txtDialString
txtName.SetFocus
SSTab1.Tab = 1 ' show page
End Select
'
End Sub
This same page has the array of command buttons that simulate the telephone handset keypad. Listing 30.18 shows the code that should be copied into the cmdKey_Click event.
Listing 30.18. Coding the cmdKey_Click event.
Private Sub cmdKey_Click(Index As Integer)
'
' handle user pressing keypad
'
Dim cDigit As String
'
cDigit = Mid("123456789*0#", Index + 1, 1)
txtDialString = txtDialString & cDigit
'
End Sub
The Phone Book page has two form-level routines. Listing 30.19 shows the code for handling the button array on the phone book page. Add this to your project.
Listing 30.19. Coding the cmdData_Click event.
Private Sub cmdData_Click(Index As Integer)
'
' handle data stuff
'
Dim x As Integer
'
Select Case Index
Case 0 ' add new
Data1.Recordset.AddNew
txtName.SetFocus
lAdd = True
Case 1 ' delete
Data1.Recordset.Delete
lAdd = False
Case 2 ' update
If Trim(txtName) <> "" Then
Data1.UpdateRecord
End If
lAdd = False
Case 3 ' refresh
If lAdd = False Then
Data1.Recordset.UpdateControls
Else
Data1.Recordset.CancelUpdate
End If
lAdd = False
End Select
'
' update the list and data table
If lAdd = False Then
Data1.Refresh
Data2.Refresh
DBList1.Refresh
End If
'
' enable all buttons
For x = 0 To 3
cmdData(x).Enabled = True
Next x
'
' turn of add/remove if add was pressed
If lAdd = True Then
cmdData(0).Enabled = False
cmdData(1).Enabled = False
End If
'
End Sub
Listing 30.20 shows the code you need to add to the DBList1_DblClick event.
Listing 30.20. Coding the DbList1_DblClick event.
Private Sub DBList1_DblClick()
'
' update data1 with this record
'
Dim cName As String
'
cName = DBList1.BoundText
Data1.Recordset.FindFirst "Name='" & cName & "'"
txtName.SetFocus
'
End Sub
The Call Log page has one event routine-the cmdLog_Click event. Add the code shown in Listing 30.21 to your project.
Listing 30.21. Coding the cmdLog_Click event.
Private Sub cmdLog_Click(Index As Integer)
'
' clear all records from the log
'
Dim iAns As Integer ' get user's answer
'
Select Case Index
Case 0 ' clear log
ClearLog
Case 1 ' refresh dynaset
Data3.Refresh
Case 2 ' export data to text file
ExportLog
End Select
'
End Sub
The Line page has a single event, too. Add the code from Listing 30.22 to the cmdLines_Click event of the form.
Listing 30.22. Coding the cmdLines_Click event.
Private Sub cmdLines_Click(Index As Integer)
'
' handle user selection of line device
'
Select Case Index
Case 0 ' apply
If List1.ListIndex = -1 Then
MsgBox "You must select a line device!", vbCritical, "No Line Selected"
lDevErr = True
Else
gLineDev = List1.ListIndex
SaveSetting App.EXEName, "LineDevice", "Selected", CStr(List1.ListIndex)
lDevErr = False
End If
Case 1 ' cancel
If List1.ListIndex = -1 Then
MsgBox "You must select a line device!", vbCritical, "No Line Selected"
lDevErr = True
End If
End Select
'
End Sub
The final page-level routine is the one that handles the Startup page. The code in Listing 30.23 shows what you should add to the cmdStartUp_Click event.
Listing 30.23. Coding the cmdStartUp_Click event.
Private Sub cmdStartUp_Click(Index As Integer)
'
' review startup values for application
'
Select Case Index
Case 0 ' apply
gMinimize = chkminimize
gMonitor = chkMonitor
gOutLog = chkOutLog
gOrigNumber = txtOrigNumber
gStartPage = IIf(optStartup(0) = True, 0, 1)
'
SaveSetting App.EXEName, "Startup", "MinimizeOnStart", gMinimize
SaveSetting App.EXEName, "Startup", "Monitor", gMonitor
SaveSetting App.EXEName, "Startup", "OutLog", gOutLog
SaveSetting App.EXEName, "Startup", "OrigNumber", gOrigNumber
SaveSetting App.EXEName, "Startup", "StartPage", gStartPage
'
Case 1 ' Cancel
' na
End Select
'
End Sub
That is the end of the page-level routines for the frmTAPI form. Save the form and project before continuing.
There are eight support routines for the frmTAPI form. Half of these routines are called from the Form_Load event as initialization routines. The rest are called at various times throughout the project.
First, add a new subroutine called LoadImages to the form. Then add the code shown in Listing 30.24 to the project.
Listing 30.24. Adding the LoadImages routine.
Public Sub LoadImages()
'
' fill in image controls
' on the pages
'
On Error GoTo LocalErr
'
' page 0
Image1.Picture = LoadPicture(App.Path & "\answmach.wmf")
' page 1
Image2.Picture = LoadPicture(App.Path & "\rolodex.wmf")
' page 3
Image3.Picture = LoadPicture(App.Path & "\clipbord.wmf")
' page 4
Image4.Picture = LoadPicture(App.Path & "\phone.wmf")
'
Exit Sub
'
LocalErr:
MsgBox Error$, vbCritical, "LoadImages Err [" & CStr(Err) & "]"
'
End Sub
Next, add the LoadDevices subroutine. This is the code that loads the device names into the list box on the Lines page. Enter the code from Listing 30.25.
Listing 30.25. Adding the LoadDevices routine.
Public Sub LoadDevices()
'
' Load line devices into list box
'
Dim x As Integer
Dim lRtn As Long
'
For x = 0 To Tapiline1.NumDevices - 1
lRtn = ReadLineDevCaps(x, uLineDevCaps, cLineDevCapsExtra)
If lRtn >= 0 Then
List1.AddItem GetOffset(Len(uLineDevCaps) + 4, uLineDevCaps.dwLineNameOffset, uLineDevCaps.dwLineNameSize, cLineDevCapsExtra)
Else
List1.AddItem "<BAD DEVICE> #" & CStr(x)
End If
Next
'
gLineDev = CStr(GetSetting(App.EXEName, "LineDevice", "Selected", "-1"))
List1.ListIndex = gLineDev
SaveSetting App.EXEName, "LineDevice", "Selected", CStr(List1.ListIndex)
'
End Sub
Next add a new subroutine called ReadStartUp to the project and enter the code from Listing 30.26. This code loads the registry values at program startup.
Listing 30.26. Adding the ReadStartUp routine.
Public Sub ReadStartup()
'
' load startup values
'
gMinimize = GetSetting(App.EXEName, "Startup", "MinimizeOnStart", 0)
gMonitor = GetSetting(App.EXEName, "Startup", "Monitor", 0)
gOutLog = GetSetting(App.EXEName, "Startup", "OutLog", 1)
gOrigNumber = GetSetting(App.EXEName, "Startup", "OrigNumber", "")
gStartPage = GetSetting(App.EXEName, "Startup", "StartPage", 0)
'
chkminimize = gMinimize
chkMonitor = gMonitor
chkOutLog = gOutLog
txtOrigNumber = gOrigNumber
'
If gStartPage = 0 Then
optStartup(0) = True
Else
optStartup(1) = True
End If
'
End Sub
The next two routines deal with loading or, if needed, creating the TAPI.MDB database file. First, create a subroutine called InitDB and enter the code from Listing 30.27.
Listing 30.27. Adding the InitDB routine.
Public Sub InitDB()
'
' establish initial data connections
'
On Error Resume Next ' i'll handle this
'
' see if db exists, if not - make it
Open App.Path & "\tapi.mdb" For Input As 1
If Err = 53 Then
MakeDB ' must create the database!
Else
Close #1 ' fine, just checking
End If
'
On Error GoTo LocalErr ' ok, pass them on...
'
' the phone book
Data1.DatabaseName = App.Path & "\tapi.mdb"
Data1.RecordSource = "SELECT * FROM TAPI"
Data1.Refresh
'
' the lookup list
Data2.DatabaseName = App.Path & "\tapi.mdb"
Data2.RecordSource = "SELECT Name from TAPI ORDER BY Name"
Data2.Refresh
'
' the call log
Data3.DatabaseName = App.Path & "\tapi.mdb"
Data3.RecordSource = "SELECT Format(CallDate,'general date') AS DateCalled, Name, NumberCalled, Comment FROM Log ORDER BY Name, CallDate"
Data3.Refresh
'
Exit Sub
'
LocalErr:
MsgBox Error$, vbCritical, "InitDB Err [" & CStr(Err) & "]"
End ' can't start without this!
'
End Sub
The first thing the InitDB routine does is check for the existence of the TAPI.MDB data file. If it does not exist, the MakeDB routine is called to create the database. Add the MakeDB subroutine to the form and enter the code shown in Listing 30.28.
Listing 30.28. Adding the MakeDB routine.
Public Sub MakeDB()
'
' create TAPIFONE database
'
Dim cMakeTAPI As String
Dim cMakeLOG As String
Dim cDBName As String
Dim ws As Workspace
Dim db As Database
'
' set db name
' and SQL statements
cDBName = App.Path & "\TAPI.MDB"
cMakeTAPI = "CREATE TABLE TAPI (Name TEXT(30), PhoneNumber TEXT(20), [Last Called] DATE)"
cMakeLOG = "CREATE TABLE LOG (Name TEXT(30), CallDate DATE, NumberCalled TEXT(20), Comment MEMO)"
'
' create new database
Set ws = Workspaces(0)
Set db = ws.CreateDatabase(cDBName, dbLangGeneral)
'
' execute SQL statements
db.Execute cMakeTAPI, dbFailOnError
db.Execute cMakeLOG, dbFailOnError
'
' shut things down
db.Close
Set db = Nothing
Set ws = Nothing
'
Exit Sub
'
LocalErr:
MsgBox Error$, vbCritical, "MakeDB Err [" & Str(Err) & "]"
End ' gotta stop here!
'
End Sub
The next two routines are called from the Call Log page of the form. Listing 30.29 shows the ClearLog routine. Add this to your project.
Listing 30.29. Adding the ClearLog routine.
Public Sub ClearLog()
'
' clear all recs out of log
'
On Error GoTo LocalErr
'
Dim iAns As Integer
'
iAns = MsgBox("Ready to Erase All Log Entries", vbInformation + vbYesNo, "Clear Call Log")
If iAns = vbYes Then
MousePointer = vbHourglass ' tell user you're busy
'
Data3.Recordset.MoveFirst ' start at the top
'
Do Until Data3.Recordset.EOF ' do until empty
Data3.Recordset.Delete ' remove a rec
Data3.Recordset.MoveNext ' go to next one
Loop ' back to top
'
MousePointer = vbNormal ' ok, tell user you're done
'
MsgBox "Call Log Cleared", vbInformation ' alter user
End If
Exit Sub
'
LocalErr:
MsgBox Error$, vbCritical, "ClearLog Err [" & CStr(Err) & "]"
'
End Sub
Listing 30.30 shows the ExportLog routine. This is used to create a text file version of the call log. Add this code to your project.
Listing 30.30. Adding the ExportLog routine.
Public Sub ExportLog()
'
' write call log to text file
'
Dim cFldDelim As String
Dim cLine As String
Dim cFileName As String
Dim cQuote As String
'
cFldDelim = Chr(44)
cQuote = Chr(34)
cFileName = App.Path & "\" & App.EXEName & ".log"
'
' create new file
Open cFileName For Output As 1
'
' write header line
cLine = "DateCalled,Name,NumberCalled,Comment"
Print #1, cLine
'
' export records
Data3.Recordset.MoveFirst
Do Until Data3.Recordset.EOF
With Data3.Recordset
cLine = cQuote & Trim(.Fields("DateCalled")) & cQuote & cFldDelim
cLine = cLine & cQuote & Trim(.Fields("Name")) & cQuote & cFldDelim
cLine = cLine & cQuote & Trim(.Fields("NumberCalled")) & cQuote & ÂcFldDelim
cLine = cLine & cQuote & Trim(.Fields("Comment")) & cQuote
Print #1, cLine
.MoveNext
End With
Loop
Close #1
'
MsgBox "Call Log Exported to [" & cFileName & "]", vbInformation, "Log Export"
'
End Sub
The last support routine for the frmTAPI form is the LineMonitor function. This routine toggles on or off the TAPI call monitoring service. When monitoring is on, TAPIFONE answers the incoming call. Add the code in Listing 30.31 to your form.
Listing 30.31. Adding the LineMonitor function.
Public Function LineMonitor(ctrl As Control, lMonitor As Boolean) As Boolean
'
' start/stop line monitoring
'
Dim lRtn As Long
'
If lMonitor = True Then
lRtn = ctrl.LineOpen(gLineDev, 0, LINECALLPRIVILEGE_OWNER + ÂLINECALLPRIVILEGE_MONITOR, LINEMEDIAMODE_INTERACTIVEVOICE)
If lRtn < 0 Then
MsgBox LineErr(lRtn), vbCritical, "Line Monitor Error"
LineMonitor = False
Else
LineMonitor = True
End If
Else
TAPIHangUp ctrl
LineMonitor = False
End If
'
End Function
That is all the coding needed for the frmTAPI form. Save this form and update the project before you add the Call and About dialog boxes.
The Call and About dialog boxes are two small forms that are used to support actions from the frmTAPI form. The Call dialog box appears just before an outbound call is placed. This allows the user to confirm the call and add any call notes if desired.
The About dialog box shows the name of the program, the current version, and other important information about the TAPIFONE application.
Add a new form to your project and build the Call dialog box shown in Figure 30.8. You can also refer to Table 30.8 when laying out the frmCall form.
Figure 30.8 : Laying out the frmCall form
Control | Property | Settings |
VB.Form | Name | frmCall |
BorderStyle | 3 'Fixed Dialog | |
Caption | "Ready to Place a Call" | |
ClientHeight | 3450 | |
ClientLeft | 3090 | |
ClientTop | 1770 | |
ClientWidth | 3780 | |
Height | 3855 | |
Icon | "frmCall.frx":0000 | |
Left | 3030 | |
LinkTopic | "Form1" | |
MaxButton | 0 'False | |
MinButton | 0 'False | |
ScaleHeight | 3450 | |
ScaleWidth | 3780 | |
ShowInTaskbar | 0 'False | |
Top | 1425 | |
Width | 3900 | |
VB.TextBox | Name | txtNotes |
Height | 1575 | |
Left | 960 | |
MultiLine | -1 'True | |
ScrollBars | 2 'Vertical | |
TabIndex | 5 | |
Text | "frmCall.frx":0442 | |
Top | 1320 | |
Width | 2655 | |
VB.Data | Name | Data1 |
Caption | "Data1" | |
Connect | "Access" | |
DatabaseName | "" | |
Exclusive | 0 'False | |
Height | 300 | |
Left | 180 | |
Options | 0 | |
ReadOnly | 0 'False | |
RecordsetType | 1 'Dynaset | |
RecordSource | "" | |
Top | 3060 | |
Visible | 0 'False | |
Width | 1140 | |
VB.CommandButton | Name | cmdCall |
Caption | "&Cancel" | |
Height | 300 | |
Index | 1 | |
Left | 1080 | |
TabIndex | 3 | |
Top | 3000 | |
Width | 1200 | |
VB.CommandButton | Name | cmdCall |
Caption | "&OK" | |
Height | 300 | |
Index | 0 | |
Left | 2400 | |
TabIndex | 2 | |
Top | 3000 | |
Width | 1200 | |
VB.Label | Name | Label3 |
Caption | "Call Notes:" | |
Height | 195 | |
Left | 1020 | |
TabIndex | 6 | |
Top | 1140 | |
Width | 2595 | |
VB.Label | Name | lblDialString |
Alignment | 2 'Center | |
Caption | "xxx-xxx-xxxx" | |
Font | ||
name="MS Sans Serif" | ||
charset=0 | ||
weight=700 | ||
size=8.25 | ||
underline=0 'False | ||
italic=0 'False | ||
strikethrough=0 'False | ||
Height | 300 | |
Left | 0 | |
TabIndex | 4 | |
Top | 780 | |
Width | 3795 | |
VB.Image | Name | Image1 |
Height | 1575 | |
Left | -60 | |
Picture | "frmCall.frx":0448 | |
Stretch | -1 'True | |
Top | 1260 | |
Width | 870 | |
VB.Label | Name | lblName |
Alignment | 2 'Center | |
Caption | "name" | |
Font | ||
name="MS Sans Serif" | ||
charset=0 | ||
weight=700 | ||
size=8.25 | ||
underline=0 'False | ||
italic=0 'False | ||
strikethrough=0 'False | ||
Height | 300 | |
Left | 0 | |
TabIndex | 1 | |
Top | 420 | |
Width | 3795 | |
VB.Label | Name | Label1 |
Alignment | 2 'Center | |
Caption | "Placing Call to:" | |
Font | ||
name="MS Sans Serif" | ||
charset=0 | ||
weight=700 | ||
size=8.25 | ||
underline=0 'False | ||
italic=0 'False | ||
strikethrough=0 'False | ||
Height | 300 | |
Left | 0 | |
TabIndex | 0 | |
Top | 60 | |
Width | 3795 |
After you finish laying out the frmCall form, you need to add three code routines. The first is the Form_Load event code. Listing 30.32 shows the code you need to add to the frmCall form.
Listing 30.32. Adding the Form_Load event code.
Private Sub Form_Load()
'
' init stuff
'
lblDialString = Trim(gDialString)
lblname = Trim(gName)
txtNotes = ""
Image1.Picture = LoadPicture(App.Path & "\payphone.wmf")
'
' init form stuff
Me.Caption = "Ready to Place a Call..."
Me.Icon = LoadPicture(App.Path & "\phone04.ico")
Me.Left = (Screen.Width - Me.Width) / 2
Me.Top = (Screen.Height - Me.Height) / 2
'
' handle db connections
Data1.DatabaseName = App.Path & "\tapi.mdb"
Data1.RecordSource = "Log"
Data1.Refresh
'
End Sub
Next you need to add the code shown in Listing 30.33 to the cmdCall_Click event of the form.
Listing 30.33. Coding the cmdCall_Click event.
Private Sub cmdCall_Click(Index As Integer)
'
' handle user selection
'
Select Case Index
Case 0 ' place call
gPlaceCall = True ' ok to place call
UpdateDB ' update tables
Case 1 ' cancel call
gPlaceCall = False ' no, skip it
End Select
'
Unload Me
'
End Sub
Finally, you need to add some code to support the cmdCall_Click event. Add a new subroutine called UpdateDB to the form and enter the code shown in Listing 30.34.
Listing 30.34. Adding the UpdateDB routine.
Public Sub UpdateDB()
'
' update call log and master file
'
' add call log record
With frmCall.Data1.Recordset
.AddNew
.Fields("Name") = lblname
.Fields("CallDate") = Now()
.Fields("NumberCalled") = lblDialString
.Fields("Comment") = txtNotes & " "
.Update
End With
frmCall.Data1.Refresh
'
' update master record
frmTAPI.Data1.Recordset.FindFirst "Name='" & lblname & "'"
If frmTAPI.Data1.Recordset.NoMatch = False Then
With frmTAPI.Data1.Recordset
.Edit
.Fields("[Last Called]") = Now()
.Update
End With
End If
frmTAPI.Data1.Refresh
'
End Sub
That is the end of the frmCall form. Save this form and update the project before you add the About dialog box.
The About dialog box is displayed when the user selects Help | About TAPIFONE. Add a new form to the project. Refer to Figure 30.9 and Table 30.9 when laying out the new form.
Figure 30.9 : Laying out the About dialog box
Control | Property | Settings |
VB.Form | Name | frmVPhone |
Caption | "About TAPILine Virtual Phone" | |
ClientHeight | 2670 | |
ClientLeft | 2190 | |
ClientTop | 2880 | |
ClientWidth | 5955 | |
Height | 3075 | |
Icon | "frmVPhon.frx":0000 | |
Left | 2130 | |
LinkTopic | "Form1" | |
ScaleHeight | 2670 | |
ScaleWidth | 5955 | |
Top | 2535 | |
Width | 6075 | |
VB.CommandButton | Name | Command1 |
Caption | "&OK" | |
Height | 300 | |
Left | 4620 | |
TabIndex | 2 | |
Top | 2280 | |
Width | 1200 | |
VB.Label | Name | Label2 |
BorderStyle | 1 'Fixed Single | |
Caption | "Label2" | |
Font | ||
name="MS LineDraw" | ||
charset=2 | ||
weight=400 | ||
size=8.25 | ||
underline=0 'False | ||
italic=0 'False | ||
strikethrough=0 'False | ||
Height | 1335 | |
Left | 120 | |
TabIndex | 1 | |
Top | 780 | |
Width | 5715 | |
VB.Label | Name | Label1 |
Alignment | 2 'Center | |
BorderStyle | 1 'Fixed Single | |
Caption | "TAPILine Virtual Phone" | |
Font | name="MS Sans Serif" | |
charset=0 | ||
weight=700 | ||
size=18 | ||
underline=0 'False | ||
italic=0 'False | ||
strikethrough=0 'False | ||
Height | 555 | |
Left | 120 | |
TabIndex | 0 | |
Top | 120 | |
Width | 5715 |
There are only two code routines needed for this form. Listing 30.35 shows the Form_Load event code. Add this to the form.
Listing 30.35. Adding the Form_Load event code.
Private Sub Form_Load()
'
' fill in controls
'
Dim cAboutData
Dim cVersion
'
cAboutData = ""
cVersion = CStr(App.Major) & "." & CStr(App.Minor) & "." & CStr(App.Revision)
'
cAboutData = cAboutData & "Version......." & cVersion & Chr(13)
cAboutData = cAboutData & "Title........." & App.Title & Chr(13)
cAboutData = cAboutData & "Description..." & App.FileDescription & Chr(13)
cAboutData = cAboutData & "Copyright....." & App.LegalCopyright
'
Label2 = cAboutData
'
Me.Left = (Screen.Width - Me.Width) / 2
Me.Top = (Screen.Height - Me.Height) / 2
'
End Sub
Listing 30.36 shows the line of code to add the Command1_Click event. This exits the About dialog box.
Listing 30.36. Adding the code to exit the dialog box.
Private Sub Command1_Click()
Unload Me
End Sub
That's the end of the coding for the TAPIFONE project. Now save the form and the project. You are ready to test the application.
When you first run TAPIFONE you'll be prompted to select a line device. This device will be used for all inbound and outbound calls (see Figure 30.10).
Figure 30.10 : TAPIFONE requires you to select a line device
Next, it's a good idea to select the Setup tab to review your startup configuration (see Figure 30.11).
Figure 30.11 : Adjusting the startup configuration
You can place a call using the keypad on the Dial Pad page (see Figure 30.12) or by selecting an entry in the phone book.
Figure 30.12 : Using the Dial Pad to place a call
In either case, when you press the Dial button, the Call dialog box appears asking you to confirm your call and enter any call notes (see Figure 30.13).
Figure 30.13 : Using the phone book to place a call
Once your call is completed you can view the results on the log page and even export the log to a text file (see Figure 30.14).
Figure 30.14 : Exporting the log page to a text file
In this chapter you applied all the information you have learned in the TAPI section to create a complete phone in software. You can use this device on any workstation that has TAPI services installed and has at least a voice-data modem. If the workstation has a speaker phone, you do not even need a telephone handset on your desk.
This chapter showed you what you can build in Visual Basic using the TAPILINE control. In the next chapter, you'll learn about three other TAPI tools that you can use to create TAPI-enabled applications. Two of the products are TAPI development tools. The third product is Microsoft Phone-Microsoft's e-mail-aware, telephone answering machine that can read text messages to you over the telephone.