www.pudn.com > vbTAPI.zip > TAPILine.cls


VERSION 1.0 CLASS 
BEGIN 
  MultiUse = -1  'True 
END 
Attribute VB_Name = "CvbTAPILine" 
Attribute VB_GlobalNameSpace = False 
Attribute VB_Creatable = True 
Attribute VB_PredeclaredId = False 
Attribute VB_Exposed = False 
Option Explicit 
'**************************************************************** 
'*  VB file:   TAPILine.cls... VB32 wrapper for MS TAPI LINE API 
'* 
'*  created:        1999 by Ray Mercer 
'* 
'*  last modified:  8/25/99 by Ray Mercer 
'* 
'* 
'*  Copyright (C) 1999 Ray Mercer.  All rights reserved. 
'*  Latest version at http://i.am/shrinkwrapvb 
'**************************************************************** 
 
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" _ 
                                    (dest As Any, src As Any, ByVal length As Long) 
 
'DrawIconEx Constants 
Private Const DI_MASK          As Long = &H1 
Private Const DI_IMAGE         As Long = &H2 
Private Const DI_NORMAL        As Long = &H3 
Private Const DI_COMPAT        As Long = &H4 
Private Const DI_DEFAULTSIZE   As Long = &H8 
Private Declare Function DrawIconEx Lib "user32.dll" _ 
                            (ByVal hdc As Long, ByVal left As Long, ByVal top As Long, ByVal hIcon As Long, _ 
                            ByVal width As Long, ByVal height As Long, ByVal step As Long, ByVal hBrush As Long, _ 
                            ByVal uFlags As Long) As Long 
Private Declare Function DestroyIcon Lib "user32.dll" (ByVal hIcon As Long) As Long  'BOOL 
 
'Initialization, error & version control variables 
Private m_hLineApp As Long 'handle to TAPI 
Private m_APIversions() As Long 
Private m_ExtAPIversions() As LINEEXTENSIONID 
Private m_ApplicationVersion As Long 'some TAPI calls need this instead of negotiated API version 
Private m_LowAPI As Long 'default TAPI 1.3 (&H00010003) 
Private m_HiAPI As Long 'deafult TAPI 3.0 (&H00030000) 
Private m_LastTAPIError As Long 
 
'line selection variables 
Private m_numLines As Long 
Private m_CurLineID As Long 
 
'devcaps variables 
Private m_linecaps As LINEDEVCAPS 
Private m_LineName As String 
Private m_ProviderInfo As String 
Private m_SwitchInfo As String 
Private m_PermanentLineID As Long 
Private m_StringFormat As Long 
Private m_numAddresses As Long 
Private m_maxDataRate As Long 
Private m_BearerModes As Long 
Private m_AddressModes As Long 
Private m_MediaModes As Long 
Private m_GenerateToneMaxNumFreq As Long 
Private m_GenerateToneModes As Long 
Private m_numTerminals As Long 
 
'Call-state and asynch function state variables 
Private m_hLine As Long 
Private m_hCall As Long 
Private m_RequestingCall As Long 
Private m_DroppingCall As Long 
Private m_ReqPrivileges As Long 
Private m_ReqMediaModes As Long 
 
'Events 
Event MakeCallResult(ByVal errorCode As Long) 
Event DropCallResult(ByVal errorCode As Long) 
Event Connected() 
Event Idle() 
Event Disconnected() 
 
Private Sub Class_Initialize() 
    Debug.Print "class init" 
    'default TAPI 1.3 - 3.0 
    m_LowAPI = &H10003 
    m_HiAPI = &H30000 
End Sub 
Public Property Get LowAPI() As Long 
    LowAPI = m_LowAPI 
End Property 
Public Property Let LowAPI(ByVal ver As Long) 
    m_LowAPI = ver 
End Property 
 
Public Property Get HiAPI() As Long 
    HiAPI = m_HiAPI 
End Property 
Public Property Let HiAPI(ByVal ver As Long) 
    m_HiAPI = ver 
End Property 
 
 
Public Property Get LastError() As Long 
    LastError = m_LastTAPIError 
    'reset error value after access 
    m_LastTAPIError = 0& 
End Property 
 
Public Function ErrorString(ByVal errCode As Long) As String 
    ErrorString = GetLineErrString(errCode) 
End Function 
 
Public Function Create() As Boolean 
 
    Dim rc As Long 
    Dim line As Long 
    Dim lip As LINEINITIALIZEEXPARAMS 
    Dim lxid As LINEEXTENSIONID 
     
    'init params 
    lip.dwTotalSize = Len(lip) 
    lip.dwOptions = LINEINITIALIZEEXOPTION_USEHIDDENWINDOW 
     
    'initialize TAPI lines and get handle 
    rc = lineInitializeEx(m_hLineApp, App.hInstance, AddressOf mTAPIvb.LineCallbackProc, App.Title, _ 
                                m_numLines, m_HiAPI, lip) 
    If rc <> TAPI_SUCCESS Then 
        m_LastTAPIError = rc 
        Exit Function 
    Else 
        If m_numLines < 1 Then Exit Function 'no lines! 
        'negotiate and cache API versions for each line 
        ReDim m_APIversions(0 To m_numLines - 1) 
        ReDim m_ExtAPIversions(0 To m_numLines - 1) 
        For line = 0 To m_numLines - 1 
            rc = lineNegotiateAPIVersion(m_hLineApp, line, m_LowAPI, m_HiAPI, m_APIversions(line), lxid) 
            If rc <> TAPI_SUCCESS Then 
                m_APIversions(line) = 0 'no compatible API negotiated for this line 
                rc = 0 
            Else 
                'also cache extension version (dev-specific features) if available 
                m_ExtAPIversions(line).dwExtensionID0 = lxid.dwExtensionID0 
                m_ExtAPIversions(line).dwExtensionID1 = lxid.dwExtensionID1 
                m_ExtAPIversions(line).dwExtensionID2 = lxid.dwExtensionID2 
                m_ExtAPIversions(line).dwExtensionID3 = lxid.dwExtensionID3 
                'TODO! add call to lineNegotiateExtVersion() 
                'and save the highest negotiated version as our app version 
                If m_APIversions(line) > m_ApplicationVersion Then 
                    m_ApplicationVersion = m_APIversions(line) 
                End If 
            End If 
                 
        Next 
    End If 
    rc = GetLineDevCaps() 
    Create = True 'return success 
 
End Function 
 
Public Property Get numLines() As Long 
    numLines = m_numLines 
End Property 
 
Public Property Get CurrentLineID() As Long 
    CurrentLineID = m_CurLineID 
End Property 
 
Public Property Let CurrentLineID(ByVal id As Long) 
    If id < 0 Then Err.Raise 380 
    If id > m_numLines - 1 Then Err.Raise 380 
     
    m_CurLineID = id 
    Call GetLineDevCaps 
     
End Property 
 
Public Property Get NegotiatedAPIVersion() As Long 
    NegotiatedAPIVersion = m_APIversions(m_CurLineID) 
End Property 
 
Public Property Get ExtAPI_ID0() As Long 
   ExtAPI_ID0 = m_ExtAPIversions(m_CurLineID).dwExtensionID0 
End Property 
 
Public Property Get ExtAPI_ID1() As Long 
   ExtAPI_ID1 = m_ExtAPIversions(m_CurLineID).dwExtensionID1 
End Property 
 
Public Property Get ExtAPI_ID2() As Long 
   ExtAPI_ID2 = m_ExtAPIversions(m_CurLineID).dwExtensionID2 
End Property 
 
Public Property Get ExtAPI_ID3() As Long 
   ExtAPI_ID3 = m_ExtAPIversions(m_CurLineID).dwExtensionID3 
End Property 
 
Private Function GetLineDevCaps() As Boolean 
    Dim rc As Long 
     
    'init required fields in devcaps UDT 
    m_linecaps.dwTotalSize = Len(m_linecaps) 
     
    'the LINEDEVCAPS UDT is just hard-allocated to be big enough to hold most 
    'variable-length structures that TAPI may throw at you 
    'if there is a better way from VB, I'd like to know (besides a Byte-array that is)... 
     
    'request TAPI to fill UDT with info 
    rc = lineGetDevCaps(m_hLineApp, m_CurLineID, m_APIversions(m_CurLineID), _ 
                        0&, m_linecaps) 
    If rc <> TAPI_SUCCESS Then 
        m_LastTAPIError = rc 
        Exit Function 
    End If 
     
    'store UDT info in class local variables 
    m_LineName = GetTAPIStructString(VarPtr(m_linecaps), m_linecaps.dwLineNameOffset, m_linecaps.dwLineNameSize) 
    m_ProviderInfo = GetTAPIStructString(VarPtr(m_linecaps), m_linecaps.dwProviderInfoOffset, m_linecaps.dwProviderInfoSize) 
    m_SwitchInfo = GetTAPIStructString(VarPtr(m_linecaps), m_linecaps.dwSwitchInfoOffset, m_linecaps.dwSwitchInfoSize) 
    m_PermanentLineID = m_linecaps.dwPermanentLineID 
    m_StringFormat = m_linecaps.dwStringFormat 
    m_numAddresses = m_linecaps.dwNumAddresses 
    m_maxDataRate = m_linecaps.dwMaxRate 
    m_BearerModes = m_linecaps.dwBearerModes 
    m_AddressModes = m_linecaps.dwAddressModes 
    m_MediaModes = m_linecaps.dwMediaModes 
    m_GenerateToneMaxNumFreq = m_linecaps.dwGenerateToneMaxNumFreq 
    m_GenerateToneModes = m_linecaps.dwGenerateToneModes 
    m_numTerminals = m_linecaps.dwNumTerminals 
     
     'return success 
    GetLineDevCaps = True 
End Function 
Public Property Get LineName() As String 
    LineName = m_LineName 
End Property 
Public Property Get ProviderInfo() As String 
    ProviderInfo = m_ProviderInfo 
End Property 
Public Property Get SwitchInfo() As String 
    SwitchInfo = m_SwitchInfo 
End Property 
Public Property Get PermanentLineID() As Long 
    PermanentLineID = m_PermanentLineID 
End Property 
 
Public Property Get StringFormat() As Long 
    StringFormat = m_StringFormat 
End Property 
Public Property Get numAddresses() As Long 
    numAddresses = m_numAddresses 
End Property 
 
Public Property Get maxDataRate() As Long 
    maxDataRate = m_maxDataRate 
End Property 
Public Property Get BearerModes() As Long 
    BearerModes = m_BearerModes 
End Property 
Public Property Get AddressModes() As Long 
    AddressModes = m_AddressModes 
End Property 
Public Property Get mediamodes() As Long 
    mediamodes = m_MediaModes 
End Property 
Public Property Get GenerateToneMaxNumFreq() As Long 
    GenerateToneMaxNumFreq = m_GenerateToneMaxNumFreq 
End Property 
Public Property Get GenerateToneModes() As Long 
    GenerateToneModes = m_GenerateToneModes 
End Property 
Public Property Get numTerminals() As Long 
    numTerminals = m_numTerminals 
End Property 
 
Public Property Get LineSupportsVoiceCalls() As Boolean 
    If m_BearerModes And LINEBEARERMODE_VOICE Then 
        If m_MediaModes And LINEMEDIAMODE_INTERACTIVEVOICE Then 
            LineSupportsVoiceCalls = True 
        End If 
    End If 
End Property 
 
 
Public Function OpenLine(Optional ByVal privileges As Long = LINECALLPRIVILEGE_NONE, _ 
                        Optional ByVal mediamodes As Long = LINEMEDIAMODE_INTERACTIVEVOICE) As Boolean 
    'returns false on error or if a line is already open 
    'if a TAPI error occurs the error number will be stored in m_LastTAPIerror 
    If m_hLine <> 0 Then 
        Debug.Print "OpenLine called recursively!" 
        Exit Function 
    End If 
    Dim rc As Long 
     
    'open the line for outgoing call 
    '(passes a reference to itself in the dwCallbackinstance parameter 
    'tapi will pass that reference back to the callback procedure and 
    'we will use the ITapiCallbackSink interface to call back to this 
    'class instance) 
    rc = lineOpen(m_hLineApp, _ 
                    m_CurLineID, _ 
                    m_hLine, _ 
                    m_APIversions(m_CurLineID), _ 
                    0&, _ 
                    ByVal ObjPtr(Me), _ 
                    privileges, _ 
                    mediamodes, _ 
                    ByVal 0&) 
    If rc <> TAPI_SUCCESS Then 
        m_LastTAPIError = rc 
        Debug.Print ErrorString(rc) 
        Exit Function 
    End If 
    Debug.Assert m_hLine 
    OpenLine = True 
 
End Function 
Public Function MakeCallAsynch(Optional ByVal phonenumber As String = "") As Boolean 
    'returns false on error or if m_hLine has not been initialized(by calling OpenLine) 
    'if a TAPI error occurs the error number will be stored in m_LastTAPIerror 
    Dim rc As Long 
    'Dim callParams As LINECALLPARAMS 
     
    If 0 = m_hLine Then 
        Debug.Print "MakeCallAsynch entered recursively!" 
        Exit Function 
    End If 
    Debug.Print "MakeCallAsynch entered" 
     
    'callParams.dwTotalSize = Len(callParams) 
    If phonenumber = "" Then 'just get dialtone 
        rc = lineMakeCall(m_hLine, m_hCall, vbNullString, 0&, ByVal 0&) 
    Else 'dial a number 
        rc = lineMakeCall(m_hLine, m_hCall, phonenumber, 0&, ByVal 0&) 
    End If 
    If rc > 0 Then 
        'now placing call - completion will be signalled by a LINE_REPLY event in the callback 
        'store positive request identifier in class member variable for use in the callback handler 
        m_RequestingCall = rc 
    Else 
        m_LastTAPIError = rc 
        Debug.Print "MakeCallAsynch error" 
        Exit Function 
    End If 
    Debug.Print "MakeCallAsynch successful" 
    MakeCallAsynch = True 
     
End Function 
 
Public Function DropCallAsynch() As Boolean 
    'returns false on error or if m_hLine has not been initialized(by calling OpenLine) 
    'if a TAPI error occurs the error number will be stored in m_LastTAPIerror 
    Dim rc As Long 
     
    If m_hCall = 0 Then 
        Debug.Print "Can't drop call - no hCall!" 
        Exit Function 
    End If 
     
    rc = lineDrop(m_hCall, vbNullString, 0&) 
    If rc > 0 Then 
        'dropping call 
        m_DroppingCall = rc 
    Else 
        m_LastTAPIError = rc 
        Exit Function 
    End If 
    DropCallAsynch = True 
     
End Function 
 
Public Function CloseLine() As Boolean 
    'returns false on error or if a line is already closed 
    'if a TAPI error occurs the error number will be stored in m_LastTAPIerror 
    Dim rc As Long 
     
    If 0 = m_hLine Then 
        Debug.Print "No hLine to close!" 
        Exit Function 
    End If 
     
    rc = lineClose(m_hLine) 
    'line handle is now invalid 
    Debug.Print "Line Closed" 
    m_hLine = 0 
    'store errors 
    If rc <> TAPI_SUCCESS Then 
        m_LastTAPIError = rc 
        Exit Function 
    End If 
     
    CloseLine = True 
     
End Function 
 
Public Function ConfigDialog(Optional ByVal OwnerHwnd As Long = 0&, Optional ByVal DeviceClass As String = "") As Boolean 
    Dim rc As Long 
     
    If DeviceClass = "" Then 
        rc = lineConfigDialog(m_CurLineID, OwnerHwnd, vbNullString) 
    Else 
        rc = lineConfigDialog(m_CurLineID, OwnerHwnd, DeviceClass) 
    End If 
    If rc <> TAPI_SUCCESS Then 
       m_LastTAPIError = rc 
       Exit Function 
    End If 
    'indicate success 
    ConfigDialog = True 
     
End Function 
 
Public Function DialingPropertiesDialog(Optional ByVal OwnerHwnd As Long = 0&, Optional ByVal phonenumber As String = "") As Boolean 
    Dim rc As Long 
    If phonenumber = "" Then 
        rc = lineTranslateDialog(m_hLineApp, m_CurLineID, m_ApplicationVersion, OwnerHwnd, vbNullString) 
    Else 
        rc = lineTranslateDialog(m_hLineApp, m_CurLineID, m_ApplicationVersion, OwnerHwnd, phonenumber) 
    End If 
    If rc <> TAPI_SUCCESS Then 
        m_LastTAPIError = rc 
        Exit Function 
    End If 
    'indicate success 
    DialingPropertiesDialog = True 
End Function 
Public Function PaintDevIcon(ByVal hdc As Long, _ 
                                Optional ByVal left As Long = 0, _ 
                                Optional ByVal top As Long = 0, _ 
                                Optional ByVal width As Long = 0, _ 
                                Optional ByVal height As Long = 0) As Boolean 
    Dim hIcon As Long 
    Dim rc As Long 
     
    rc = lineGetIcon(m_CurLineID, 0&, hIcon) 
    If rc <> TAPI_SUCCESS Then 
        m_LastTAPIError = rc 
        Exit Function 
    End If 
    rc = DrawIconEx(hdc, left, top, hIcon, width, height, 0&, 0&, DI_NORMAL) 
    '(function succeeds even when there is no icon in the TSP) 
    If 0 = hIcon Then  'function failed (check actual hIcon instead of return value) 
        Exit Function 
    End If 
    Call DestroyIcon(hIcon) 
     
    PaintDevIcon = True 
     
End Function 
 
 
Private Function GetTAPIStructString(ByVal ptrTapistruct As Long, ByVal offset As Long, ByVal length As Long) As String 
'ugly C-hacker way to deal with ugly C-hacker TAPI structs (UDTs) 
Dim buffer() As Byte 
 
If length < 1 Then Exit Function 'handle erroneous input 
 
If offset Then ' 
    ReDim buffer(0 To length - 1) 
    CopyMemory buffer(0), ByVal ptrTapistruct + offset, length 
    GetTAPIStructString = StrConv(buffer, vbUnicode) 
End If 
 
End Function 
 
Private Sub Class_Terminate() 
    Debug.Print "class term" 
    If m_hCall <> 0 Then 
        Call lineDeallocateCall(m_hCall) 
        m_hCall = 0 
    End If 
    If m_hLine <> 0 Then 
        Call CloseLine 
    End If 
    If m_hLineApp <> 0 Then 
        Call lineShutdown(m_hLineApp) 
        m_hLineApp = 0 
    End If 
End Sub 
 
Friend Sub LineProcHandler(ByVal hDevice As Long, _ 
                                        ByVal dwMsg As Long, _ 
                                        ByVal dwParam1 As Long, _ 
                                        ByVal dwParam2 As Long, _ 
                                        ByVal dwParam3 As Long) 
'Handle callbacks here in the class itself via ITapiCallbackSink 
    Debug.Print "Entering LineProcHandler" 
    Select Case dwMsg 
        Case LINE_REPLY 
            If dwParam1 = m_RequestingCall Then 
                Debug.Print "LINE_REPLY-CALL REQUEST RETURNS" 
                '(earlier we called the asynch lineMakeCall() function from the 
                'MakeCallAsynch method and stored the requester in m_RequestingCall 
                'now we can see that this is the asynchronous reply to that call) 
                'don't need ID anymore - it matched 
                m_RequestingCall = 0 
                 
                'if it was an error make sure the line is closed 
                If dwParam2 <> 0 Then Call CloseLine 
                'send result to parent via event 
                RaiseEvent MakeCallResult(dwParam2) 
                 
            ElseIf dwParam1 = m_DroppingCall Then 
                Debug.Print "LINE_REPLY-CALL DROP RETURNS" 
                'asynch reply to lineDrop() call 
                m_DroppingCall = 0 
                RaiseEvent DropCallResult(dwParam2) 
                 
            End If 
        Case LINE_CALLSTATE 
            Select Case dwParam1 
                Case LINECALLSTATE_DISCONNECTED 
                    'remote party has disconnected from the call 
                    Debug.Print "LINECALLSTATE_DISCONNECTED" 
                    Call DropCallAsynch 
                    RaiseEvent Disconnected 
                                     
                Case LINECALLSTATE_IDLE 
                    'no call exists - the line is idle 
                    Debug.Print "LINECALLSTATE_IDLE" 
                    If m_hCall <> 0 Then 
                        Debug.Print "Deallocating Call" 
                        Call lineDeallocateCall(m_hCall) 
                        Debug.Print "Closing Line" 
                        Call CloseLine 
                    End If 
                    RaiseEvent Idle 
                Case LINECALLSTATE_CONNECTED 
                    Debug.Print "LINECALLSTATE_CONNECTED" 
                    RaiseEvent Connected 
                                        
                Case LINECALLSTATE_BUSY 
                    Debug.Print "LINECALLSTATE_BUSY" 
                    'nuff said 
                 
                Case LINECALLSTATE_DIALTONE 
                    'switch is ready to receive a dialed number 
                    Debug.Print "LINECALLSTATE_DIALTONE" 
                 
                Case LINECALLSTATE_RINGBACK 
                    'the other station has been reached and is being alerted (ringing) 
                    Debug.Print "LINECALLSTATE_RINGBACK" 
                 
                Case LINECALLSTATE_DIALING 
                    Debug.Print "LINECALLSTATE_DIALING" 
                 
                Case LINECALLSTATE_PROCEEDING 
                    Debug.Print "LINECALLSTATE_PROCEEDING" 
                 
                Case LINECALLSTATE_SPECIALINFO 
                    'network error occured 
                    Debug.Print "LINECALLSTATE_SPECIALINFO" 
                     
                Case Else 
                    Debug.Print "CallSTATE: " & Hex(dwParam1) 
            End Select 
        Case Else 
    End Select 
 
End Sub