The last integration project in the book combines MAPI services with audio recording. The Talk Mail project allows you to record messages and then send them to others via e-mail. It's a bit like an asynchronous telephone conversation.
You will need a sound card, a microphone, and speakers (or headphones) in order to run this project. You will be able to select one or more recipients, press the record button, record a message, and ship both the header data and the audio binary file to any other person in the MAPI directory.
Note |
In this version of the Talk Mail project, all MAPI addresses are resolved against current names in your address book(s). You could add code to allow any user with a universal e-mail address (for example, yourname@internet.com) to receive the audio recordings. However, you'll need to ensure that the file is sent and received properly by Internet users before you add this feature. |
You'll use the OLE Messaging library to implement the MAPI services. The audio recording will be handled using the Windows Media Control Interface (MCI). This project will make use of the new Windows 95 controls for Visual Basic, including the listview control, the toolbar control, and the statusbar control.
Warning |
Because this project makes extensive use of the Windows 95 controls, you will not be able to build it on a 16-bit Windows platform. You'll need to use the 32-bit version of Visual Basic and run it on Windows 95 or Windows NT. |
One of the advantages of the OLE Messaging library over the MAPI OCX tool is the added access to MAPI objects and properties. In this project we'll define a new message type (IPM.Note.TalkMail) for all messages generated by our Talk Mail application. The real benefit in this is that we'll be able to tell our Talk Mail client to pay attention only to the messages generated by other Talk Mail clients. This way, when our new voice-mail client checks the MAPI inbox for new messages, only the Talk Mail messages will appear on the screen.
The voice recordings, in the form of WAV files, will be shipped as an attachment with each MAPI message. The Talk Mail client will automatically load the WAV file into the MCI form control, ready for playback (or further recording). The Talk Mail client never tells the user that there is an attachment to the message. In fact, as far as the user is concerned, there is no attachment!
Tip |
All Talk Mail messages can be viewed from the standard Windows Messaging or Microsoft Mail MAPI clients. When you use the standard MAPI clients, you'll see the WAV file appear as an attachment to the text message. |
It may seem that we should use the SAPI services for the "talking" portion of the application. However, because the primary focus of this application is voice, it's a better idea to use the pure voice recording instead of rendering text into speech. Also, by using the MCI tool that ships with Visual Basic Professional and Enterprise Editions, you can provide full record and playback services with very little coding. Therefore, this application will take advantage of users' tendency to prefer actual voices over computer-generated sound.
The project has four forms and one code module. The code module holds routines for handling several OLE operations along with global variable declarations and other support routines. The four forms for the project are
You'll need to make sure you have the following references and custom controls added to your project:
Tip |
You load the object libraries using the Tools | References menu option. You load the OCX controls using the Tools | Custom Controls menu option. |
Now that you have a good idea of how the project works, let's jump right into creating the BAS module that will hold the general support routines for the project.
The LibTalkMail module has seven subroutines and three functions. Most of these routines deal with MAPI service requests but others include error handling and simple helper functions to manage the Talk Mail messages. This module also has several public variables that are declared here and used throughout the program.
First, start a new Visual Basic project and make sure you have loaded the OLE Messaging library and the custom controls listed in the preceding section.
Next, add a module to the project (Insert | Module) and set its Name property to LibTalkMail. Now add the code in Listing 36.1 to the general declaration section of the module.
Listing 36.1. Public variables and objects for the Talk Mail project.
Option Explicit
'
' internal message pointer
Type MsgPtr
ID As String
Subject As String
End Type
'
' to track msgs
Public uMsgP() As MsgPtr
Public iMsgCount As Integer
Public cMsgID As String
'
' ole message libary objects
Public objSession As Object
Public objInBox As Object
Public objOutBox As Object
Public objMsgColl As Object
Public objAttach As Object
Public objAttachColl As Object
Public objRecipColl As Object
Public objRecip As Object
Public objMsg As Object
Public objAddrEntry As Object
'
' for MCI wav work
Public cWavFile As String
Public Const conInterval = 50
Public Const conIntervalPlus = 55
There are three sets of variables and objects in the code in Listing 36.1. First you see the creation of a user-defined type (UDT) that will hold the unique MAPI message ID and the MAPI subject. This UDT will be used to perform quick lookups of a selected record in the mail system. After defining the MsgPtr type, three variables are defined to hold information about the message pool. The next set of declarations defines the OLE message objects. These will be used (and re-used) throughout the program. Finally, the module contains a few variables for handling the MCI control.
Next you need to add the MAPI-related subroutines, the first of which is the MAPIStart routine. This routine is called to begin a MAPI session. Add a new subroutine called MAPIStart (select Insert | Procedure) and enter the code shown in Listing 36.2.
Listing 36.2. Adding the MAPIStart routine.
Public Sub MAPIStart()
'
' log into mapi
'
On Error GoTo LocalErr
'
Set objSession = CreateObject("MAPI.Session")
objSession.Logon
'
Set objInBox = objSession.Inbox
Set objOutBox = objSession.Outbox
Exit Sub
'
LocalErr:
MsgBox ErrMsg(Err), vbCritical, "MAPIStart"
'
End Sub
The MAPIEnd routine is called when the user wants to end the MAPI session completely. Most of the code in the MAPIEnd routine is required to free precious workstation memory.
Tip |
It is always a good idea to set Visual Basic objects equal to Nothing when you are through with them. This frees workstation memory and can improve overall workstation performance. |
Add a new subroutine (MAPIEnd) and enter the code from Listing 36.3.
Listing 36.3. Adding the MAPIEnd routine.
Public Sub MAPIEnd()
'
On Error Resume Next
'
objSession.Logoff
Set objSession = Nothing
Set objInBox = Nothing
Set objOutBox = Nothing
Set objMsgColl = Nothing
Set objRecip = Nothing
Set objMsg = Nothing
'
End Sub
Two short MAPI routines are MAPIAddrBook and MAPIDeleteMsg. These two routines give the user access to the MAPI address book and delete a selected message, respectively. Add these two subroutines to your project from Listings 36.4 and 36.5.
Listing 36.4. Adding the MAPIAddrBook routine.
Public Sub MAPIAddrBook()
'
On Error GoTo LocalErr
'
objSession.AddressBook
Exit Sub
'
LocalErr:
MsgBox ErrMsg(Err), vbCritical, "MAPIAddrBook"
'
End Sub
The MAPIDeleteMsg routine will remove a selected message object from the collection. Add the code from Listing 36.5 to your project.
Listing 36.5. Adding the MAPIDeleteMsg routine.
Public Sub MAPIDeleteMsg(cMsgID As String)
'
' delete selected message
'
On Error GoTo LocalErr
'
Dim iAns As Integer
'
Set objMsg = objSession.GetMessage(cMsgID)
'
iAns = MsgBox(objMsg.Subject, vbExclamation + vbYesNo, "Delete Talk Mail ÂMessage")
If iAns = vbYes Then
objMsg.Delete
End If
'
Exit Sub
'
LocalErr:
MsgBox ErrMsg(Err), vbCritical, "MAPIDeleteMsg"
'
End Sub
Next you need to add two routines that call the tmRead and tmNew dialog boxes to read or create new messages. These two routines are almost identical. The only difference is the name of the form that is launched. Add the MAPINewMsg subroutine and enter the code form Listing 36.6.
Listing 36.6. Adding the MAPINewMsg routine.
Public Sub MAPINewMsg()
'
' allow user to compose a message
'
frmTMView.CMDialog1.Filter = "WaveForm File (*.wav)|*.wav"
frmTMNew.MMControl1.DeviceType = "WaveAudio"
frmTMNew.Show
frmTMView.Hide
'
End Sub
Note that this routine (and the MAPIReadMsg routine) both just hide the main form rather than unloading it. This is necessary because the project has some values that must be shared between forms. Now add the MAPIReadMsg routine shown in Listing 36.7.
Listing 36.7. Adding the MAPIReadMsg routine.
Public Sub MAPIReadMsg(cMsgID As String)
'
' allow user to view a message
'
frmTMView.CMDialog1.Filter = "WaveForm File (*.wav)|*.wav"
frmTMRead.MMControl1.DeviceType = "WaveAudio"
frmTMRead.Show
frmTMView.Hide
'
End Sub
The next routine is the largest one in the module. The MAPISendMsg routine is the one that builds the MAPI message object and makes sure it is sent off to the recipient(s). Add the MAPISendMsg subroutine to the project and enter the code from Listing 36.8.
Listing 36.8. Adding the MAPISendMsg routine.
Public Sub MAPISendMsg(objRecipList As Object, cSubject As String, cBody As String, ÂcWavFile As String)
'
' construct a message and send it off
'
On Error GoTo LocalErr
'
Dim x As Integer
'
' build new message
Set objMsg = objOutBox.Messages.Add
objMsg.Type = "IPM.Note.TalkMail"
objMsg.Subject = cSubject
objMsg.Text = " " & cBody
'
' add wav file as attachment
If Len(cWavFile) <> 0 Then
Set objAttach = objMsg.Attachments.Add
objAttach.Name = "Talk Mail.WAV" 'cWavFile
objAttach.position = 0
objAttach.Type = mapiFileData
objAttach.Source = cWavFile
objAttach.ReadFromFile cWavFile
End If
'
' load recipient(s)
If objRecipList Is Nothing Then
MsgBox "No Recipients!"
Else
For x = 1 To objRecipList.Count
Set objRecip = objMsg.Recipients.Add
objRecip.Name = objRecipList.Item(x).Name
Next x
End If
'
' send it out quietly
On Error Resume Next
objMsg.Update ' update all the collections
objMsg.Send showdialog:=False
'
' let everyone know
MsgBox "Message Sent", vbInformation, "Talk Mail"
'
Exit Sub
'
LocalErr:
MsgBox ErrMsg(Err), vbCritical, "MAPISendMsg"
'
End Sub
There are four main tasks performed by this routine. First, the message body is assembled. Note the use of IPM.Note.TalkMail in the Type property. You'll use this value as a search criterion when you refresh the list of available Talk Mail messages.
Next, the recorded WAV audio file is added to the package as an attachment. There are a couple of important points to make here. First, it is important that you use ".WAV" as the suffix of the Name property of the attachment object. This will make sure you can click the object, and Windows will call up the audio player automatically. Also, when you are attaching data to the message (not just linking, but attaching), you need to invoke the ReadFromFile method to actually load the selected file into the message package. Unlike the OCX controls, OLE does not do this for you.
Third, you need to add the recipients from the collection returned by the address book into the collection for the message. This requires iterating through the source object and using the results to insert into the message's receipt object.
Lastly, the routine updates all its child objects and quietly sends the MAPI package to the MAPI spooler for delivery.
There are three general helper functions that need to be added to the LibTalkMail module. The first one is the FindSubject function. This is used to return a unique MAPI message ID using the UDT you built at the start of this section. Add the FindSubject function and enter the code shown in Listing 36.9.
Listing 36.9. Adding the FindSubject function.
Public Function FindSubject(cSubject As String) As String
'
' takes subject line, returns MsgID
'
Dim x As Integer
Dim cRtn As String
'
cRtn = "" ' start empty
For x = 1 To iMsgCount
If UCase(cSubject) = UCase(uMsgP(x).Subject) Then
cRtn = uMsgP(x).ID
Exit For
End If
Next x
'
FindSubject = cRtn
'
End Function
Another very valuable helper function is the GetRecipients function. This routine accepts a collection of recipients and extracts the display name into a single string for producing an onscreen list of the message recipients. After adding the new GetRecipients function to the project, enter the code shown in Listing 36.10.
Listing 36.10. Adding the new GetRecipients function.
Public Function GetRecipients(objRecipColl As Object) As String
'
' pull qualified recipients from object collection
'
Dim cRtn As String
Dim x As Integer
'
cRtn = ""
'
If objRecipColl Is Nothing Then
GoTo LeaveHere
End If
'
For x = 1 To objRecipColl.Count
Set objRecip = objRecipColl.Item(x)
cRtn = cRtn & objRecip.Name & ";"
Next x
'
If Len(cRtn) > 0 Then
cRtn = Left(cRtn, Len(cRtn) - 1)
End If
'
LeaveHere:
GetRecipients = cRtn
'
End Function
The last helper function you need to add to the LibTalkMail module is the ErrMsg function. This routine uses the new Visual Basic 4.0 Err object to build an informative message concerning the name, type, and originator of the message. Add the code in Listing 36.11 to your project.
Listing 36.11. Add the ErrMsg function.
Public Function ErrMsg(ErrObj As Object) As String
'
' return formatted message
'
Dim cMsg As String
'
cMsg = "ErrCode:" & Chr(9) & CStr(ErrObj.Number) & Chr(13)
cMsg = cMsg & "ErrMsg:" & Chr(9) & ErrObj.Description & Chr(13)
cMsg = cMsg & "Source:" & Chr(9) & ErrObj.Source
'
ErrMsg = cMsg
'
End Function
That's all you need to add to the BAS module of the Talk Mail project. Be sure to save this file under the name LIBTMAIL.BAS and the project under the name TALKMAIL.VBP before continuing.
The main form shows a list of all the Talk Mail messages in the user's inbox. It also has a set of toolbar buttons for performing the basic MAPI actions of logon, logoff, viewing the address book, creating a new Talk Mail message, reading an Existing Talk Mail message, and deleting a Talk Mail message. There are also buttons for adjusting the list view from large icon, small icon, list, and detail formats.
The first step is to lay out the form's controls. Refer to Table 36.1 and Figure 36.1 for details on the layout of the tmView form.
Figure 36.1 : Laying out the tmView form.
Control | Property | Setting |
VB.Form | Name | frmTMView |
Caption | "Form1" | |
Height | 4410 | |
Left | 1185 | |
Top | 1665 | |
Width | 8715 | |
MSComDlg.CommonDialog | Name | CMDialog1 |
Left | 6360 | |
Top | 2880 | |
ComctlLib.StatusBar | Name | StatusBar1 |
Align | 2 'Align Bottom | |
Height | 315 | |
Left | 0 | |
TabIndex | 2 | |
Top | 3405 | |
Width | 8595 | |
AlignSet | -1 'True | |
SimpleText | "" | |
ComctlLib.ImageList | Name | imglstSmall |
Left | 3720 | |
Top | 1440 | |
ComctlLib.ImageList | Name | imglstBig |
Left | 3900 | |
Top | 660 | |
ComctlLib.ImageList | Name | imglstToolBar |
Left | 5040 | |
Top | 120 | |
ImageWidth | 16 | |
ImageHeight | 16 | |
ComctlLib.Toolbar | Name | tbrMain |
Align | 1 'Align Top | |
Height | 390 | |
Left | 0 | |
TabIndex | 1 | |
Top | 0 | |
Width | 8595 | |
ImageList | "" | |
AlignSet | -1 'True | |
ComctlLib.ListView | Name | ListView1 |
Height | 2295 | |
Left | 120 | |
TabIndex | 0 | |
Top | 480 | |
Width | 8355 | |
appearance | 1 | |
Arrange | 2 | |
Icons | "ImageList3" | |
SmallIcons | "ImageList2" | |
View | 2 |
The form doesn't look like much at first, but you'll add all the fancy stuff (bitmaps, icons, and so on) at runtime. Once you get the controls onto the form, you need to build the menu. Figure 36.2 and Table 36.2 show you the details of the menu layout.
Figure 36.2 : Laying out the tmView menu.
Tip |
The menu layout makes extensive use of menu arrays. Be sure to pay close attention to the index number values when building the menu. You'll use these index values throughout the program. |
Menu Level | Properties | Settings |
Top | Name | mnuFile |
Caption | "File" | |
Level 2 | Name | mnuFileItem |
Caption | "Log &In..." | |
Index | 0 | |
Level 2 | Name | mnuFileItem |
Caption | "Log &Out" | |
Index | 1 | |
Level 2 | Name | mnuFileItem |
Caption | "-" | |
Index | 2 | |
Level 2 | Name | mnuFileItem |
Caption | "&Scan Inbox" | |
Index | 3 | |
Level 2 | Name | mnuFileItem |
Caption | "&Address Book..." | |
Index | 4 | |
Level 2 | Name | mnuFileItem |
Caption | "-" | |
Index | 5 | |
Level 2 | Name | mnuFileItem |
Caption | "E&xit" | |
Index | 6 | |
Top | Name | mnuMsgs |
Caption | "&Messages" | |
Level 2 | Name | mnuMsgsItem |
Caption | "&New..." | |
Index | 0 | |
Level 2 | Name | mnuMsgsItem |
Caption | "&Read" | |
Index | 1 | |
Level 2 | Name | mnuMsgsItem |
Caption | "&Delete" | |
Index | 2 | |
Top | Name | mnuView |
Caption | "&View" | |
Level 2 | Name | mnuViewItem |
Caption | "Lar&ge Icons" | |
Index | 0 | |
Level 2 | Name | mnuViewItem |
Caption | "&Small Icons" | |
Index | 1 | |
Level 2 | Name | mnuViewItem |
Caption | "L&ist" | |
Index | 2 | |
Level 2 | Name | mnuViewItem |
Caption | "&Details" | |
Index | 3 | |
Top | Name | mnuHelp |
Caption | "&Help" | |
Level 2 | Name | mnuHelpItem |
Caption | "&About" | |
Index | 0 |
Once you have the form controls and menus in place, save the form as TMVIEW.FRM and save the project (TALKMAIL.VBP) before you go on to add the form code.
Most of the code for the tmView form is needed to set up the toolbar, listview, and statusbar controls. There are also several code sections for handling the menu selections and the basic form events. There are a few short events for handling toolbar and list view clicks and there is one routine for requesting new messages from the MAPI service.
The code can be divided into the following related groups:
The Form_Load event calls the routines to build the form controls and then set some properties of the form itself. Enter the code shown in Listing 36.12 into the Form_Load event.
Listing 36.12. Coding the Form_Load event.
Private Sub Form_Load()
'
BuildToolBar
BuildListView
BuildStatusBar
'
Me.Caption = "Talk Mail 95"
Me.Left = (Screen.Width - Me.Width) / 2
Me.Top = (Screen.Height - Me.Height) / 2
Me.Icon = LoadPicture(App.Path & "\tmMsg32.ico")
'
End Sub
Warning |
The code example above uses the App.Path property to locate the icon file. This will not work properly if you locate your project in a root directory of a drive. It is recommended that you place all project files in a single directory. If you place your files in a root directory, you'll need to modify the code that uses the app.path object. |
You also need to add code to the Form_Resize event. This code will resize the listview control to make sure it fills the form. Enter the code from Listing 36.13 into your project.
Listing 36.13. Adding the Form_Resize event code.
Private Sub Form_Resize()
'
' handle form resizing
'
If Me.WindowState <> vbMinimized Then
ListView1.Left = 0
ListView1.Top = tbrMain.Height
ListView1.Width = Me.ScaleWidth
ListView1.Height = Me.ScaleHeight - tbrMain.Height - StatusBar1.Height
End If
'
End Sub
Three of the controls (listview, toolbar, and statusbar) require extensive setup. While this could be done at design time using the custom property boxes, it is easier to modify the properties if you build the controls at run-time.
Add a new subroutine called BuildStatusBar and enter the code shown in Listing 36.14.
Listing 36.14. Adding the BuildStatusBar routine.
Public Sub BuildStatusBar()
'
' create details of status bar display
'
Dim I As Integer
'
For I = 1 To 4
StatusBar1.Panels.Add ' Add Panel objects.
StatusBar1.Panels(I).AutoSize = sbrContents
Next I
With StatusBar1.Panels
.Item(1).Style = sbrText
.Item(2).Style = sbrCaps ' Caps lock
.Item(3).Style = sbrIns ' insert
.Item(4).Style = sbrDate ' date
.Item(5).Style = sbrTime ' time
End With
'
StatusBar1.Panels(1).Text = "Talk Mail" & Space(50)
StatusBar1.Style = sbrNormal
'
End Sub
The code in Listing 36.14 sets up a status bar that will show the status of the CAPS and INS buttons, the date and time, and reserve some space for a status message.
Next, add a new subroutine called BuildListView and enter the code shown in Listing 36.15.
Listing 36.15. Adding the BuildListView routine.
Public Sub BuildListView()
'
' build list view
'
Dim clmX As ColumnHeader
Dim ItmX As ListItem
Dim ImgX As ListImage
'
' set view properties
ListView1.BorderStyle = ccFixedSingle
ListView1.View = lvwReport
ListView1.Sorted = True
mnuViewItem(3).Checked = True ' show check on menu
'
' set column headers for detail view
Set clmX = ListView1.ColumnHeaders. _
Add(, , "Subject", ListView1.Width * 0.25)
Set clmX = ListView1.ColumnHeaders. _
Add(, , "RecvDate", ListView1.Width * 0.25)
Set clmX = ListView1.ColumnHeaders. _
Add(, , "From", ListView1.Width * 0.25)
'
' set large image list control
imglstbig.ImageHeight = 32
imglstbig.ImageWidth = 32
Set ImgX = imglstbig.ListImages. _
Add(, , LoadPicture(App.Path & "\tmMsg32.ico"))
Set ImgX = imglstbig.ListImages. _
Add(, , LoadPicture(App.Path & "\note32.ico"))
'
' set small image control
imglstsmall.ImageHeight = 16
imglstsmall.ImageWidth = 16
Set ImgX = imglstsmall.ListImages. _
Add(, , LoadPicture(App.Path & "\tmMsg16.ico"))
Set ImgX = imglstsmall.ListImages. _
Add(, , LoadPicture(App.Path & "\note16.ico"))
'
' link image and listview
ListView1.Icons = imglstbig
ListView1.SmallIcons = imglstsmall
'
End Sub
The code in Listing 36.15 performs several tasks. First, columns are defined for the detail view. Next, two image controls are initialized for the large and small icon views. Finally, those two image controls are bound to the listview control so that the list view knows which icons to use when displaying the contents.
The last of the "build" routines is the BuildToolBar routine. This is the most involved of the three because it contains fourteen buttons (some of them separators) with all their icons, tooltips, and keys. Add the new subroutine (BuildToolBar) and enter the code shown in Listing 36.16.
Listing 36.16. Adding the BuildToolBar routine.
Public Sub BuildToolBar()
'
' set up win95 tool bar
'
Dim ImgX As ListImage
Dim BtnX As Button
Dim tlbrPics(14) As String
Dim tlbrKeys(14) As String
Dim tlbrTips(14) As String
Dim tlbrStyle(14) As Integer
Dim x As Integer
'
tlbrPics(1) = "tmStart.ico"
tlbrPics(2) = "tmEnd.ico"
tlbrPics(3) = "tmstart.ico"
tlbrPics(4) = "tmAdrBk.ico"
tlbrPics(5) = "tmScan.ico"
tlbrPics(6) = "tmstart.ico"
tlbrPics(7) = "tmMsg16.ico"
tlbrPics(8) = "tmRead.ico"
tlbrPics(9) = "tmTrash.ico"
tlbrPics(10) = "tmstart.ico"
tlbrPics(11) = "vw-lrgic.bmp"
tlbrPics(12) = "vw-smlic.bmp"
tlbrPics(13) = "vw-list.bmp"
tlbrPics(14) = "vw-dtls.bmp"
'
tlbrKeys(1) = "LOGIN"
tlbrKeys(2) = "LOGOUT"
tlbrKeys(3) = ""
tlbrKeys(4) = "ADDRBOOK"
tlbrKeys(5) = "SCANINBOX"
tlbrKeys(6) = ""
tlbrKeys(7) = "NEWMSG"
tlbrKeys(8) = "READMSG"
tlbrKeys(9) = "DELETE"
tlbrKeys(10) = ""
tlbrKeys(11) = "ICONS"
tlbrKeys(12) = "SMALLICONS"
tlbrKeys(13) = "LISTVIEW"
tlbrKeys(14) = "DETAILS"
'
tlbrTips(1) = "Log In"
tlbrTips(2) = "Log Out"
tlbrTips(3) = ""
tlbrTips(4) = "Address Book"
tlbrTips(5) = "Scan InBox"
tlbrTips(6) = ""
tlbrTips(7) = "New Msg"
tlbrTips(8) = "Read Msg"
tlbrTips(9) = "Delete Msg"
tlbrTips(10) = ""
tlbrTips(11) = "Icons"
tlbrTips(12) = "Small Icons"
tlbrTips(13) = "List View"
tlbrTips(14) = "Details"
'
imglstToolbar.ImageHeight = 16
imglstToolbar.ImageWidth = 16
'
' fill image list
For x = 1 To 14
Set ImgX = imglstToolbar.ListImages. _
Add(, , LoadPicture(App.Path & "\" & tlbrPics(x)))
Next x
'
' fill toolbar
tbrMain.ImageList = imglstToolbar
For x = 1 To 14
Set BtnX = tbrMain.Buttons.Add
BtnX.Key = tlbrKeys(x)
BtnX.ToolTipText = tlbrTips(x)
If tlbrTips(x) <> "" Then
BtnX.Style = tbrDefault
BtnX.Image = x
Else
BtnX.Style = tbrSeparator
End If
Next x
End Sub
Note |
This routine refers to several icon files. These icons can be found on the CD-ROM that ships with this book. They should have been copied to your local drive when you installed the CD-ROM. Make sure you copy them to your project directory before you run the project. |
There are four main menu branches: File, Message, View, and Help. Each branch is built as a menu array. You need to add code to handle user selections for each menu branch.
First, add the code shown in Listing 36.17 to the mnuFileItem_Click event.
Listing 36.17. Adding the mnuFileItem_Click event code.
Private Sub mnuFileItem_Click(Index As Integer)
'
' handle file menu stuff
'
Select Case Index
Case 0 ' login
MAPIStart
Case 1 ' logout
MAPIEnd
Case 3 ' scan inbox
MAPIScanInBox
Case 4 ' addr book
MAPIAddrBook
Case 6 ' exit
MAPIEnd
Unload Me
End Select
'
End Sub
Next, add the code from Listing 36.18 to the mnuMsgItem_Click event.
Listing 36.18. Coding the mnuMsgItem_Click event.
Private Sub mnuMsgsItem_Click(Index As Integer)
'
' handle msgs menu
'
Dim Itm As Object
Dim x As Integer
'
Select Case Index
Case 0 ' new
MAPINewMsg
Case 1 ' read
If cMsgID <> "" Then
MAPIReadMsg cMsgID
End If
Case 2 ' delete
If cMsgID <> "" Then
MAPIDeleteMsg cMsgID
MAPIScanInBox ' update view
End If
End Select
'
End Sub
The next code section deals with adjustments in the list view options. Add the code from Listing 36.19 to the mnuViewItem_Click event.
Listing 36.19. Coding the mnuViewItem_Click event.
Private Sub mnuViewItem_Click(Index As Integer)
'
' handle views
'
Dim x As Integer
'
Select Case Index
Case 0 ' large icon
ListView1.View = lvwIcon
Case 1 ' small icon
ListView1.View = lvwSmallIcon
Case 2 ' list view
ListView1.View = lvwList
Case 3 ' detail view
ListView1.View = lvwReport
End Select
'
For x = 0 To 3
If x = Index Then
mnuViewItem(x).Checked = True
Else
mnuViewItem(x).Checked = False
End If
Next x
'
End Sub
The last menu code is for the mnuHelpItem_Click event. Enter the code from Listing 36.20 into your project.
Listing 36.20. Adding the mnuHelpItem_Click event code.
Private Sub mnuHelpItem_Click(Index As Integer)
'
' handle help menu
'
Select Case Index
Case 0 ' about
frmAbout.Show vbModal
End Select
'
End Sub
The last control event code you need to add is the code that handles the toolbar selections. This code looks very similar to the menu event code. In this case, the user selection is determined by the value of the Button.Key property. Enter the code from Listing 36.21 into the tbrMain_ButtonClick event.
Listing 36.21. Coding the tbrMain_ButtonClick event.
Private Sub TbrMain_ButtonClick(ByVal Button As Button)
'
Select Case Button.Key
Case "LOGIN"
MAPIStart
MAPIScanInBox
Case "LOGOUT"
MAPIEnd
Unload Me
Case "ADDRBOOK"
MAPIAddrBook
Case "NEWMSG"
MAPINewMsg
Case "READMSG"
MAPIReadMsg cMsgID
Case "DELETE"
MAPIDeleteMsg cMsgID
MAPIScanInBox
Case "SCANINBOX"
MAPIScanInBox
Case "ICONS"
mnuViewItem_Click 0
Case "SMALLICONS"
mnuViewItem_Click 1
Case "LISTVIEW"
mnuViewItem_Click 2
Case "DETAILS"
mnuViewItem_Click 3
End Select
'
End Sub
The last set of code routines for the tmView form is the code that is executed for various control events. There are three events for the list control. These events adjust the sorting order, collect the subject of the selected item in the list, and launch the Talk Mail message reader. Add code for the three routines shown in Listing 36.22.
Listing 36.22. Coding the ListView events.
Private Sub ListView1_ColumnClick(ByVal ColumnHeader As ColumnHeader)
ListView1.SortKey = ColumnHeader.Index - 1 ' change sort order
End Sub
Private Sub ListView1_DblClick()
MAPIReadMsg cMsgID ' launch reader form
End Sub
Private Sub ListView1_ItemClick(ByVal Item As ListItem)
cMsgID = FindSubject(Item.Text) ' get subject text
End Sub
There is only one more code routine for the tmView form-the MAPIScanInBox routine. This routine scans the MAPI inbox for any Talk Mail messages addressed to the user and fills the list view with the results. This routine also builds an array of message pointers that will be used to locate messages in the MAPI infostore whenever the user wishes to read a particular message. Add the MAPIScanInBox subroutine to the project and enter the code shown in Listing 36.23.
Listing 36.23. Adding the MAPIScanInBox code.
Private Sub MAPIScanInBox()
'
' scan inbox for msgs
'
On Error Resume Next
'
Dim ItmX As ListItem
'
' refresh collections
Set objInBox = objSession.Inbox
Set objMsgColl = objInBox.Messages
'
ListView1.ListItems.Clear
iMsgCount = 0
ReDim uMsgP(0)
'
' only get talk mail records
Set objMsg = objMsgColl.GetFirst("IPM.Note.TalkMail")
Do Until objMsg Is Nothing
Set ItmX = ListView1.ListItems.Add
ItmX.Icon = 1
ItmX.SmallIcon = 1
If Trim(objMsg.Subject) = "" Then
ItmX.Text = "<No Subject>"
Else
ItmX.Text = objMsg.Subject
End If
'
ItmX.SubItems(1) = Format(objMsg.TimeReceived, "general date")
'
Set objAddrEntry = objMsg.Sender
If objAddrEntry Is Nothing Then
ItmX.SubItems(2) = "<No Sender>"
Else
ItmX.SubItems(2) = objAddrEntry.Name
End If
'
' store in pointer set
iMsgCount = iMsgCount + 1
ReDim Preserve uMsgP(iMsgCount)
uMsgP(iMsgCount).ID = objMsg.ID
uMsgP(iMsgCount).Subject = ItmX.Text
'
Set objMsg = objMsgColl.GetNext
Loop
'
Set objMsg = Nothing
Set objMsgColl = Nothing
'
StatusBar1.Panels(1).Text = CStr(iMsgCount) & " Talk Mail Message(s)" & ÂSpace(40)
'
Exit Sub
'
LocalErr:
MsgBox ErrMsg(Err), vbCritical, "MAPIScanInBox"
'
End Sub
That's the end of the code routines for the tmView form. Be sure to save the form (TMVIEW.FRM) and the project (TALKMAIL.VBP) before you continue.
The tmNew and tmRead forms are where the real action happens. These forms present the user with some input controls for selecting recipients, setting a subject line, and entering a supporting text message. The center of the form is the MCI control. This can be used for playback and recording of the audio WAV file.
First, refer to Figure 36.3 and Table 36.3 for the layout of the tmNew form.
Figure 36.3 : Laying out the tmNew form.
Control | Property | Setting |
VB.Form | Name | frmTMNew |
Caption | "Talk Mail Compose Form" | |
Height | 6030 | |
Left | 2415 | |
Top | 1455 | |
Width | 5250 | |
VB.HScrollBar | Name | HScroll1 |
Height | 300 | |
Left | 120 | |
Max | 100 | |
TabIndex | 12 | |
Top | 2220 | |
Width | 4860 | |
VB.CommandButton | Name | cmdNewMsg |
Cancel | -1 'True | |
Caption | "&Cancel" | |
Height | 300 | |
Index | 1 | |
Left | 2460 | |
TabIndex | 5 | |
Top | 4920 | |
Width | 1200 | |
VB.CommandButton | Name | cmdAddrBook |
Caption | "Send To... " | |
Height | 300 | |
Left | 120 | |
TabIndex | 0 | |
Top | 120 | |
Width | 1200 | |
VB.CommandButton | Name | cmdNewMsg |
Caption | "&Send" | |
Height | 300 | |
Index | 0 | |
Left | 3780 | |
TabIndex | 4 | |
Top | 4920 | |
Width | 1200 | |
VB.TextBox | Name | txtSubject |
Height | 300 | |
Left | 1380 | |
TabIndex | 1 | |
Text | "Text3" | |
Top | 1080 | |
Width | 3600 | |
VB.TextBox | Name | txtBody |
Height | 1995 | |
Left | 120 | |
MultiLine | -1 'True | |
ScrollBars | 2 'Vertical | |
TabIndex | 3 | |
Top | 2820 | |
Width | 4860 | |
VB.Label | Name | Label3 |
Alignment | 2 'Center | |
Caption | "Pause" | |
Height | 300 | |
Left | 2520 | |
TabIndex | 16 | |
Top | 1860 | |
Width | 795 | |
VB.Label | Name | lblFFwd |
Alignment | 2 'Center | |
Caption | "FFwd" | |
Height | 300 | |
Left | 960 | |
TabIndex | 15 | |
Top | 1860 | |
Width | 735 | |
VB.Label | Name | Label1 |
Height | 255 | |
Left | 120 | |
TabIndex | 14 | |
Top | 2520 | |
Width | 600 | |
VB.Label | Name | Label2 |
Height | 255 | |
Left | 4380 | |
TabIndex | 13 | |
Top | 2520 | |
Width | 600 | |
VB.Label | Name | lblRecord |
Alignment | 2 'Center | |
Caption | "Record" | |
Height | 300 | |
Left | 4140 | |
TabIndex | 11 | |
Top | 1860 | |
Width | 855 | |
VB.Label | Name | lblStop |
Alignment | 2 'Center | |
Caption | "Stop" | |
Height | 300 | |
Left | 3360 | |
TabIndex | 10 | |
Top | 1860 | |
Width | 735 | |
VB.Label | Name | lblPlay |
Alignment | 2 'Center | |
Caption | "Play" | |
Height | 300 | |
Left | 1740 | |
TabIndex | 9 | |
Top | 1860 | |
Width | 735 | |
VB.Label | Name | lblRewind |
Alignment | 2 'Center | |
Caption | "Rewind" | |
Height | 300 | |
Left | 120 | |
TabIndex | 8 | |
Top | 1860 | |
Width | 795 | |
MCI.MMControl | Name | MMControl1 |
Height | 315 | |
Left | 120 | |
TabIndex | 2 | |
Top | 1500 | |
Width | 4875 | |
BackVisible | 0 'False | |
StepVisible | 0 'False | |
EjectVisible | 0 'False | |
BorderStyle | 1 | |
VB.Label | Name | lblRecips |
BorderStyle | 1 'Fixed Single | |
Caption | "Label3" | |
Height | 900 | |
Left | 1380 | |
TabIndex | 7 | |
Top | 120 | |
Width | 3615 | |
VB.Label | Name | lblSubject |
BorderStyle | 1 'Fixed Single | |
Caption | "Subject:" | |
Height | 300 | |
Left | 120 | |
TabIndex | 6 | |
Top | 1080 | |
Width | 1200 |
The tmNew form also has a short menu. Refer to Figure 36.4 and Table 36.4 for laying out the form menu.
Figure 36.4 : Building the tmNew form menu.
Level | Properties | Settings |
Top | Name | mnuFile |
Caption | "File" | |
Level 2 | Name | mnuFileItem |
Caption | "Save Wave File..." | |
Index | 0 | |
Level 2 | Name | mnuFileItem |
Caption | "&Send Message" | |
Index | 1 | |
Level 2 | Name | mnuFileItem |
Caption | "-" | |
Index | 2 | |
Level 2 | Name | mnuFileItem |
Caption | "&Cancel && Exit" | |
Index | 3 |
Now is a good time to save the new form (TMNEW.FRM) and the project (TALKMAIL.VBP) before you add the code to the form.
Most of the code for the tmNew form is needed to handle MCI control events. However, there are also menu and button events that need to be addressed.
First, add the following lines to the general declaration area:
Option Explicit
'
Dim CurrentValue As Double
This variable is used to keep track of the progress of the audio playback.
Next, add the Form_Load event code shown in Listing 36.24. This code sets some basic form properties, creates a temporary filename for the audio file, and calls the HandleOpen routine to establish the audio WAV file.
Listing 36.24. Coding the Form_Load event.
Private Sub Form_Load()
'
' first startup of form
'
MMControl1.Wait = True
'
txtSubject = "Talk Mail Message #" & Format(Now(), "DDHHmmss")
txtBody = "Message Recorded at " & Format(Now, "general date")
lblrecips = ""
'
Me.Icon = LoadPicture(App.Path & "\tmMsg32.ico")
Me.Caption = "Talk Mail Compose Form"
Me.Left = (Screen.Width - Me.Width) / 2
Me.Top = (Screen.Height - Me.Height) / 2
'
cWavFile = App.Path & "\" & Format(Now(), "DDHHmmss") & ".wav"
FileCopy App.Path & "\xxx.wav", cWavFile
HandleOpen cWavFile
'
End Sub
Warning |
The code in Listing 36.25 refers to a file called "xxx.wav." This is an empty WAV format audio file that is used as a "starter" file for each new message. This file can be found on the CD-ROM that ships with this book. If you cannot find the file, you can make a new one using the WAV audio applet that ships with Windows or the one that came with your sound card. |
Listing 36.25 shows a short bit of code for the Form_Unload event. Add this to your project.
Listing 36.25. Coding the Form_Unload event.
Private Sub Form_Unload(Cancel As Integer)
Me.Hide
frmTMView.Show
End Sub
The next big chunk of code is for the HandleOpen subroutine. This routine initializes the MCI control and clears the scrollbar values. Add the code from Listing 36.26 to your form.
Listing 36.26. Adding the HandleOpen routine.
Private Sub HandleOpen(cWavFile As String)
Dim msec As Double
' Set the number of milliseconds between successive
' StatusUpdate events.
MMControl1.UpdateInterval = 0
' If the device is open, close it.
If Not MMControl1.Mode = mciModeNotOpen Then
MMControl1.Command = "Close"
End If
' Open the device with the new filename.
MMControl1.filename = cWavFile
On Error GoTo MCI_ERROR
MMControl1.Command = "Open"
On Error GoTo 0
'
SetTiming
'
' Set the scrollbar values.
Hscroll1.value = 0
CurrentValue = 0#
'
Exit Sub
MCI_ERROR:
MsgBox ErrMsg(Err), vbCritical, "frmTMNew.HandleOpen"
Resume MCI_EXIT
MCI_EXIT:
Unload Me
End Sub
The HandleOpen routine calls another support routine-the SetTiming routine. This short routine establishes the total length of existing recordings and is used to set the start and stop limits of the scrollbar. Add the code from Listing 36.27 to your form.
Listing 36.27. Adding the SetTiming routine.
Public Sub SetTiming()
'
' Set the timing labels on the form.
Dim msec As Double
'
MMControl1.TimeFormat = mciFormatMilliseconds
Label1.Caption = "0.0"
msec = (CDbl(MMControl1.Length) / 1000)
Label2.Caption = Format$(msec, "0.00")
'
End Sub
Next you can add the code to handle the menu array. This code allows the user to save the recorded file to disk, send the message, and exit the form without sending the message. Add the code from Listing 36.28 to your form.
Listing 36.28. Coding the mnuFileItem_Click event.
Private Sub mnuFileItem_Click(Index As Integer)
'
' handle user menu selections
'
Select Case Index
Case 0 ' save as
MMControl1.filename = cWavFile
frmTMView.CMDialog1.ShowSave
MMControl1.filename = frmTMView.CMDialog1.filename
MMControl1.Command = "Save"
Case 1 ' send
cmdNewMsg_Click 0
Case 2 ' na
Case 3 ' close
cmdNewMsg_Click 1
End Select
End Sub
There are two command buttons on the form in a control array-Cancel and OK. The code in Listing 36.29 should be added to the cmdNewMsg_Click event.
Listing 36.29. Coding the cmdNewMsg_Click event.
Private Sub cmdNewMsg_Click(Index As Integer)
'
' handle new msg buttons
'
Select Case Index
Case 0 ' OK to send
MMControl1.Command = "Save" ' save the wave file
MMControl1.Command = "Close" ' close out and release
MAPISendMsg objRecipColl, txtSubject, txtBody, cWavFile ' send message
Case 1 ' cancel send
' na
End Select
'
On Error Resume Next
Kill cWavFile ' remove temp file
Unload Me ' return to caller
'
End Sub
Notice the call to the MAPISendMsg routine. You built this routine in the LibTalkMail module at the start of the chapter.
There is one other button on the form-the Send To... button. When the user presses this button, the MAPI address book appears. When the user is finished selecting addresses, a recipients collection is returned. This is the list of people who will receive the message.
Note |
In this program users can send messages only if they use the To: option and not Cc: or Bcc: This was done to simplify the project. If you want, you can modify the project to address messages to courtesy copy and blind courtesy copy recipients. |
Once the collection is returned, the GetRecipients function is used to pull the names out of the collection and insert them into the label control on the form. Add the code shown in Listing 36.30 to the cmdAddrBook_Click event.
Listing 36.30. Coding the cmdAddrBook_Click event.
Private Sub cmdAddrBook_Click()
'
' get recipients from user
'
Dim x As Integer
'
Set objRecipColl = objSession.AddressBook(reciplists:=1, Title:="Select ÂTalkMail Recipient(s)")
lblrecips = GetRecipients(objRecipColl)
'
'
End Sub
The last set of code routines for the tmNew form are for the MCI multimedia control. First, add the code in Listing 36.31 to the MMControl1_StatusUpdate event.
Listing 36.31. Coding the MMControl1_StatusUpdate event.
Private Sub MMControl1_StatusUpdate()
Dim value As Integer
' If the device is not playing, reset to the beginning.
If Not MMControl1.Mode = mciModePlay Then
Hscroll1.value = Hscroll1.Max
MMControl1.UpdateInterval = 0
Exit Sub
End If
' Determine how much of the file has played. Set a
' value of the scrollbar between 0 and 100.
CurrentValue = CurrentValue + conIntervalPlus
value = CInt((CurrentValue / MMControl1.Length) * 100)
If value > Hscroll1.Max Then
value = 100
End If
Hscroll1.value = value
End Sub
This code is used to compute playback progress and update the scrollbar control on the form.
There are four other code events for the MCI control. These are executed whenever the user presses Pause, Play, Rewind, or Stop. Listing 36.32 shows the code for these four events.
Listing 36.32. Coding the MCI button events.
Private Sub MMControl1_PauseClick(Cancel As Integer)
' Set the number of milliseconds between successive
' StatusUpdate events.
If MMControl1.UpdateInterval = 0 Then
MMControl1.UpdateInterval = conInterval
Else
MMControl1.UpdateInterval = 0
End If
End Sub
Private Sub MMControl1_PlayClick(Cancel As Integer)
' Set the number of milliseconds between successive
' StatusUpdate events.
MMControl1.UpdateInterval = conInterval
End Sub
Private Sub MMControl1_PrevClick(Cancel As Integer)
' Set the number of milliseconds between successive
' StatusUpdate events.
MMControl1.UpdateInterval = 0
' Reset the scrollbar values.
Hscroll1.value = 0
CurrentValue = 0#
MMControl1.Command = "Prev"
End Sub
Private Sub MMControl1_StopClick(Cancel As Integer)
'
SetTiming ' compute any new value
'
End Sub
That's the end of the code for the tmNew form. Save the form (TMNEW.FRM) and project (TALKMAIL.VBP) before coding the tmRead form.
The tmRead form is almost identical to the tmNew form. This form is used to read Talk Mail messages sent to the user. For this reason, most of the controls have been disabled and the form is basically in a "read-only" mode.
Normally, users would read a message and then generate a reply to the sender or forward the message to another party. For this example, no reply buttons have been placed on the form. This has been done to keep the project simple and to focus on the integration of MAPI and MCI services. You can add these options later if you wish.
Add a new form to the project and lay out the controls as shown in Figure 36.5 and in Table 36.5.
Figure 36.5 : Laying out the tmRead form.
Control | Property | Setting |
VB.Form | Name | frmTMRead |
Caption | "Talk Mail Reader Form" | |
Height | 6030 | |
Left | 2415 | |
Top | 1455 | |
Width | 5250 | |
VB.HScrollBar | Name | HScroll1 |
Height | 300 | |
Left | 120 | |
Max | 100 | |
TabIndex | 9 | |
Top | 2220 | |
Width | 4860 | |
VB.CommandButton | Name | cmdNewMsg |
Caption | "&Close" | |
Height | 300 | |
Index | 0 | |
Left | 3780 | |
TabIndex | 2 | |
Top | 4980 | |
Width | 1200 | |
VB.TextBox | Name | txtBody |
BackColor | &H00C0C0C0& | |
Height | 1995 | |
Left | 120 | |
MultiLine | -1 'True | |
ScrollBars | 2 'Vertical | |
TabIndex | 1 | |
Top | 2880 | |
Width | 4860 | |
VB.Label | Name | lblSubjLine |
BorderStyle | 1 'Fixed Single | |
Caption | "Label4" | |
Height | 315 | |
Left | 1380 | |
TabIndex | 15 | |
Top | 1080 | |
Width | 3615 | |
VB.Label | Name | lblSender |
BorderStyle | 1 'Fixed Single | |
Caption | "Sent by:" | |
Height | 300 | |
Left | 120 | |
TabIndex | 14 | |
Top | 120 | |
Width | 1200 | |
VB.Label | Name | Label3 |
Alignment | 2 'Center | |
Caption | "Pause" | |
Height | 300 | |
Left | 2520 | |
TabIndex | 13 | |
Top | 1860 | |
Width | 795 | |
VB.Label | Name | lblFFwd |
Alignment | 2 'Center | |
Caption | "FFwd" | |
Height | 300 | |
Left | 960 | |
TabIndex | 12 | |
Top | 1860 | |
Width | 735 | |
VB.Label | Name | Label1 |
Height | 255 | |
Left | 120 | |
TabIndex | 11 | |
Top | 2520 | |
Width | 600 | |
VB.Label | Name | Label2 |
Height | 255 | |
Left | 4380 | |
TabIndex | 10 | |
Top | 2520 | |
Width | 600 | |
VB.Label | Name | lblRecord |
Alignment | 2 'Center | |
Caption | "Record" | |
Height | 300 | |
Left | 4140 | |
TabIndex | 8 | |
Top | 1860 | |
Width | 855 | |
VB.Label | Name | lblStop |
Alignment | 2 'Center | |
Caption | "Stop" | |
Height | 300 | |
Left | 3360 | |
TabIndex | 7 | |
Top | 1860 | |
Width | 735 | |
VB.Label | Name | lblPlay |
Alignment | 2 'Center | |
Caption | "Play" | |
Height | 300 | |
Left | 1740 | |
TabIndex | 6 | |
Top | 1860 | |
Width | 735 | |
VB.Label | Name | lblRewind |
Alignment | 2 'Center | |
Caption | "Rewind" | |
Height | 300 | |
Left | 120 | |
TabIndex | 5 | |
Top | 1860 | |
Width | 795 | |
MCI.MMControl | Name | MMControl1 |
Height | 315 | |
Left | 120 | |
TabIndex | 0 | |
Top | 1500 | |
Width | 4875 | |
BackVisible | 0 'False | |
StepVisible | 0 'False | |
EjectVisible | 0 'False | |
BorderStyle | 1 | |
VB.Label | Name | lblRecips |
BorderStyle | 1 'Fixed Single | |
Caption | "Label3" | |
Height | 900 | |
Left | 1380 | |
TabIndex | 4 | |
Top | 120 | |
Width | 3615 | |
VB.Label | Name | lblSubject |
BorderStyle | 1 'Fixed Single | |
Caption | "Subject:" | |
Height | 300 | |
Left | 120 | |
TabIndex | 3 | |
Top | 1080 | |
Width | 1200 |
After laying out the form controls, you can add the form menu. Refer to Figure 36.6 and Table 36.6 for details on the tmRead menu.
Figure 36.6 : Adding the tmRead menu.
Level | Properties | Settings |
Top | Name | mnuFile |
Caption | "File" | |
Level 2 | Name | mnuFileItem |
Caption | "Save Wave File..." | |
Index | 0 | |
Level 2 | Name | mnuFileItem |
Caption | "-" | |
Index | 2 | |
Level 2 | Name | mnuFileItem |
Caption | "&Close" | |
Index | 3 |
After building the form, save it as TMREAD.FRM before you go on to add the code.
As mentioned earlier in the chapter, the tmNew and tmRead forms are very similar. In fact, the two largest sections of form code, the HandleOpen and the MMControl1... events, are the same in both projects. As long as you are careful, you can copy the code from the tmNew form onto the tmRead form. Do this by bringing up the tmNew form, highlighting all of the HandleOpen routine, select Edit | Copy, and then move to the tmRead form and use Edit | Paste to place the code in the general declarations section.
The following code sections from tmNew can be copied to tmRead using the same technique:
Once you've successfully copied these routines from tmNew to tmRead you need to add just a few more routines to the tmRead form.
First, add the following lines to the general declaration section of the form.
Option Explicit
'
Dim CurrentValue As Double
Next, add the Form_Load event code shown in Listing 36.33.
Listing 36.33. Adding the Form_Load event code.
Private Sub Form_Load()
'
' first startup of form
'
On Error GoTo LocalErr
'
MMControl1.Wait = True
'
Dim cID As String
Dim x As Integer
'
Set objMsg = objSession.GetMessage(cMsgID)
'
lblSubjLine = objMsg.Subject
txtBody = objMsg.Text
lblrecips = GetRecipients(objMsg.Recipients)
'
Me.Icon = LoadPicture(App.Path & "\tmMsg32.ico")
Me.Caption = "Talk Mail Reader Form"
Me.Left = (Screen.Width - Me.Width) / 2
Me.Top = (Screen.Height - Me.Height) / 2
'
' get attachment to read
Set objAttachColl = objMsg.Attachments
If objAttachColl Is Nothing Then Exit Sub
For x = 1 To objAttachColl.Count
Set objAttach = objAttachColl.Item(x)
objAttach.WriteToFile "temp.wav"
cWavFile = objAttach.Source
Next x
'
' go open it with the WAV device
HandleOpen "temp.wav"
'
Exit Sub
'
LocalErr:
MsgBox ErrMsg(Err), vbCritical, "frmTMRead.Form_Load"
'
End Sub
This code is slightly different from the code in the Form_Load event of tmNew. Here, you want to open the selected message object and extract the audio WAV attachment, save it to a temporary file, and then place that audio file into the MCI control for playback (using the OpenHandle routine).
Next, add the code for the Form_Unload event shown in Listing 36.34.
Listing 36.34. Coding the Form_Unload event.
Private Sub Form_Unload(Cancel As Integer)
Me.Hide
frmTMView.Show
End Sub
Because this form only has a Close button, you need to add one line of code to the cmdNewmsg_Click event:
Private Sub cmdNewMsg_Click(Index As Integer)
Unload Me
End Sub
]Next, you need to add a line of code to the txtBody control to prevent users from typing the read-only form.
Private Sub txtBody_KeyPress(KeyAscii As Integer)
KeyAscii = 0 ' ignore any keystrokes here
End Sub
Tip |
You may notice that the txtBody control's background color was set to light gray to make it look like a label control instead of an input control. Under the Windows GUI standards, "actionable" controls have a white background and read-only controls have a light gray background. |
The only form code left is the code that handles the user's menu selections. Add the code shown in Listing 36.35 to your form.
Listing 36.35. Coding the mnuFileItem_Click event.
Private Sub mnuFileItem_Click(Index As Integer)
'
' handle user menu selections
'
Select Case Index
Case 0 ' save as
MMControl1.filename = cWavFile
frmTMView.CMDialog1.ShowSave
MMControl1.filename = frmTMView.CMDialog1.filename
MMControl1.Command = "Save"
Case 2 ' close
cmdNewMsg_Click 1
End Select
End Sub
That's the end of coding for the tmRead form. Save the form (TMREAD.FRM) and the project (TALKMAIL.VBP) before you add the final About box to the application.
The tmABout box is a simple About dialog box for the project. Figure 36.7 and Table 36.7 show the layout information for the form.
Figure 36.7 : Laying out the tmAbout form.
Control | Property | Setting |
VB.Form | Name | frmAbout |
BorderStyle | 3 'Fixed Dialog | |
Caption | "About Talk Mail" | |
Height | 2415 | |
Left | 2955 | |
MaxButton | 0 'False | |
MinButton | 0 'False | |
ShowInTaskbar | 0 'False | |
Top | 2415 | |
Width | 4230 | |
VB.CommandButton | Name | cmdOK |
Caption | "OK" | |
Height | 300 | |
Left | 2760 | |
TabIndex | 0 | |
Top | 1560 | |
Width | 1200 | |
VB.Label | Name | Label1 |
Caption | "Label1" | |
Height | 1155 | |
Left | 1320 | |
TabIndex | 1 | |
Top | 180 | |
Width | 2595 | |
VB.Image | Name | Image1 |
Height | 1215 | |
Left | 180 | |
Top | 120 | |
Width | 915 |
You need to add just a little bit of code to the Form_Load event to complete the tmAbout form. Listing 36.36 shows the code you should add to the form.
Listing 36.36. Adding code to the Form_Load event.
Private Sub Form_Load()
'
' build simple about box
'
Me.Icon = LoadPicture(App.Path & "\tmMsg32.ico")
Me.Caption = "About " & App.Title
Me.Left = (Screen.Width - Me.Width) / 2
Me.Top = (Screen.Height - Me.Height) / 2
'
Image1.Stretch = True
Image1.Picture = LoadPicture(App.Path & "\tmMsg32.ico")
'
Label1 = App.Title & Chr(13) & Chr(13)
Label1 = Label1 & App.LegalCopyright & Chr(13) & Chr(13)
Label1 = Label1 & App.FileDescription
'
End Sub
The last bit of code is a single line in the cmdOK_Click event:
Private Sub cmdOK_Click()
Unload Me
End Sub
Now save the form (TMABOUT.FRM) and the project (TALKMAIL.VBP). You are now finished coding and ready to test the program.
First, you need to compile Talk Mail and save it to disk, but before you compile it, you need to add a bit of information to the App object properties. These properties will be displayed in the application's About box.
Select File | Make EXE | Options to bring up the dialog box for setting the App objects properties. Refer to Table 36.8 and Figure 36.8 for setting the properties.
Figure 36.8 : The APP object properties dialog box.
Property | Setting |
Title | Talk Mail |
Comments | Demonstration of MAPI and MCI |
Company | MCA/SAMS |
File Description | E-mail Client for Voice Recording |
Legal Copyright | (c)1996 MCA/SAMS Publishing |
Auto Increment | Checked ON |
Once you set these properties, press OK and then compile the project. When you are able to compile the project without errors, you're ready to start testing Talk Mail.
Tip |
It is a good idea to compile the Talk Mail project before running it. The process of compiling will point out any coding errors and the resulting program will run faster than in design mode. |
When you first start Talk Mail, you see the populated button bar and an empty listview control. Press the green stoplight button (or select File | Log In from the menu) to log into MAPI and collect any Talk Mail messages you have waiting in your inbox (see Figure 36.9).
Figure 36.9 : Logging into Talk Mail.
The first time you log into Talk Mail, you'll see no messages for you. You can fix this by using Talk Mail to send yourself the first message. To do this, press the microphone toolbar button or select Message | New from the menu. You'll see the Talk Mail compose form ready to record your message (see Figure 36.10).
Figure 36.10 : Adding a new Talk Mail message.
The form comes up with a default subject line and a notation in the text message area. You can press the record button to begin recording your message and press stop when you are finished. You can also press playback, pause, rewind, and fast-forward to review your message. You can even append additional information to the end of your message if you wish.
You must select at least one recipient before you can send your message. To address the Talk Mail message, press the Send To... button at the top left of the form. You'll see the MAPI address dialog box appear (see Figure 36.11).
Figure 36.11 : Addressing the Talk Mail message.
For your first message, address it to yourself. You can then "read" this message using Talk Mail. After addressing the message, press the Send button at the bottom of the form or select File | Send Message from the menu. You'll receive notification that the message was sent and then you will be returned to the list view form.
Now you can select File | Scan InBox from the menu or press the inbox button to re-read your inbox. Your message should now appear in the list view. You can listen to your message by selecting the item and pressing the read button (it's the ear!), or by selecting Message | Read from the menu. You'll see the read form and be able to use the MCI control to play back the recording (see Figure 36.12).
Figure 36.12 : Reading an incoming Talk Mail message.
To delete a Talk Mail message, simply highlight the message and press the trash can toolbar button or select Messages | Delete from the menu. You'll see a confirmation message before you actually delete the item.
You can also use the toolbar to adjust the list view the same way you can adjust the Windows 95 Explorer views. Figure 36.13 shows the Talk Mail client in large icon view while showing the About box.
Figure 36.13 : The Talk Mail About box.
That's the end of the tour!
In this chapter, you learned how to combine the MAPI and Media Control Interface (MCI) services to create a voice-mail client. In the process you learned about declaring your own MAPI message type and about how to use the Windows 95 common controls.
This project is handy, but not quite complete. If you wish to use this application as more than a demonstration, you'll need to add the ability for users to reply to and forward received messages. You may also want to consider deploying this as a Microsoft Exchange form instead of as a standalone MAPI client. That way, all Microsoft Exchange users could install the form and use it throughout your organization.