1

目前,我们有一个网站,它依赖于 Microsoft TAPI 接口从 .NET 网站内拨打电话。它使用 VBScript 和标签,并绑定到母版页。我们正在寻找的是一个包含所有这些代码的服务器控件,并且只有在它包含在网页上时才会运行。

旧页面执行以下操作:

<object classid="clsid:21D6D48E-A88B-11D0-83DD-00AA003CCABD" id="TAPIOBJ"></object>
<object classid="clsid:E9225296-C759-11d1-A02B-00C04FB6809F" id="MAPPER"></object>

在这些代码行之后是包含用于初始化 Microsoft TAPI 3.0 库的 VBScript 和一些要拨号的函数的标记。拨号器控件创建对其中一个函数的调用以拨入 onclick 事件。

本质上,我们希望创建相同类型的控件,而无需将标签直接嵌入到页面的 HTML 中。我们也不希望在其中使用 VBScript。理想情况下,我们需要一个与 TAPI 3.0 API 一起工作并获得对客户端电话的访问权限的服务器控件。这可能吗?由于我们谈论的是“服务器”控件,因此我持怀疑态度。我可以很容易地在项目中创建一个用户控件,但是我们希望将它放在一个控件框架中以便在其他地方使用而不是复制它。

我一直在看这篇关于如何创建用于注入客户端 ActiveX 控件的服务器控件的文章,但这是否正确?

更新:这是 VBScript:

这就是标签中的内容:

<script type="text/vbscript"  LANGUAGE="VbScript">

'Constants section
'These constants are copied from tapi3if.idl
Const TAPIMEDIATYPE_AUDIO  = &H08&
Const TAPIMEDIATYPE_VIDEO = &H8000&
Const S_MEDIA_AUDIOVIDEO = &H8008&
Const TD_CAPTURE  = 0
Const TD_RENDER = 1
Const QSL_NEEDED = 1
Const AS_INSERVICE = 0
Const DC_NORMAL = 0
Const TE_CALLSTATE = 8
Const TE_CALLNOTIFICATION = 4
Const CS_DISCONNECTED = 3
Const CS_IDLE = 0
Const CS_OFFERING = 4
Const CS_CONNECTED = 2
Const CNE_OWNER =  0
Const CIS_CALLERIDNAME = 0
Const CIS_CALLERIDNUMBER = 1
'Interface IDs for casting 
'Note: you can find the following IID-s in tapi3.h, tapi3if.idl or rend.idl

Const IID_String_ITMediaSupport = "{B1EFC384-9355-11D0-835C-00AA003CCABD}"
Const IID_String_ITTerminalSupport="{B1EFC385-9355-11D0-835C-00AA003CCABD}"
Const IID_String_ITBasicCallControl = "{B1EFC389-9355-11D0-835C-00AA003CCABD}"

'Const IID_String_ITCallInfo = "{B1EFC390-9355-11d0-835C-00AA003CCABD}"
'New interface
Const IID_String_ITCallInfo = "{350F85D1-1227-11D3-83D4-00C04FB6809F}"
Const IID_String_ITStreamControl= "{EE3BD604-3868-11D2-A045-00C04FB6809F}"
Const IID_String_ITDirectoryObjectConference= "{F1029E5D-CB5B-11D0-8D59-00C04FD91AC0}"
Const IID_String_ITCallStateEvent = "{62F47097-95C9-11d0-835D-00AA003CCABD}"
Const IID_String_ITCallNotificationEvent = "{895801DF-3DD6-11d1-8F30-00C04FB6809F}"

' IID of IVideoWindow 
' Note: you can find this IID defined in control.h (from your sdk\inc directory), 
' which contains the interface to type library QuartzTypeLib for quartz.dll;
' (search for the interface IVideoWindow)
Const IID_String_IVideoWindow = "{56A868B4-0AD4-11CE-B03A-0020AF0BA770}"

' The following CLSID is defined in tapi3.h 
'(and it's used for creating a terminal of class "video window terminal")
Const CLSID_String_VideoWindowTerm = "{F7438990-D6EB-11d0-82A6-00AA00B5CA1B}"


'****************************************************************************
'Global variable section
'****************************************************************************
Dim CallStatus
Dim pICallState
pICallState = 0

'Set on True when we are unable to complete the connecting phase, to skip rest of processing
DIM sUnableToComplete
DIM sbNeedToExit
sUnableToComplete = False
sbNeedToExit = False

' If we want to receive incoming calls, we have to register on the corresponding addresses.
'We don't really use the values returned by registration (they are supposed to be used 
'for unregistration), because Unregistration is performed automatically when we shutdown the TAPI object

'The variable pRegisteredCallNotification is an array that contains cookies returned by RegisterCallNotifications;
'these would normally be used to call UnregisterNotifications.

'The variable pRegisteredName holds correspondent AddressName 

DIM pRegisteredCallNotification(50)
DIM pRegisteredName(50)
DIM iQtaRegistered
DIM callFrom

iQtaRegistered = 0


'Set by radio button "Select Address Type" 
DIM sCurrentAddressType
'sCurrentAddressType = -1
sCurrentAddressType = 1

' This variable will hold a reference to the currently established call
DIM spITCall 
spITCall = Empty


DIm pVideoWindow1
DIm pVideoWindow2

'Simplest error processing
Sub CheckError(strMsg)
if not Err.number = 0 Then
    MsgBox strMsg & ":" & Err.number & ";"&Err.description
    sbNeedToExit = True
    Err.Clear
End If

End Sub

Function IsComponentInstalled(ProgId)
Dim tmpObject

On Error Resume Next

    Set tmpObject = Server.CreateObject(ProgId)

    If Err.Number = 0 Then
        IsComponentInstalled = True
    Else
        IsComponentInstalled = False
    End If

    Set tmpObject = Nothing

End Function

</script>

在标签之后的结束正文标签下方是:

<script type="text/vbscript"  LANGUAGE="vbscript">

' Be sure that you call TAPIOBJ.Initialize before window_onload, otherwise you'll
' never receive events from tapi... 
On Error Resume Next

call TAPIOBJ.Initialize
sUnableToComplete = False
TAPIOBJ.EventFilter = &H1FFFF&


if Not Err.number = 0  Then
   MsgBox "TAPI software has not been installed on your workstation.",0,"Init"
   sUnableToComplete = True
End If  


For Each  pITAddress in TAPIOBJ.Addresses

    if left(pITAddress.AddressName,4) <> "Line" and left(pITAddress.AddressName,29) <> "Shoreline Multi-Line Monitor:" _
    and pITAddress.MediaTypes = 8 then
        callFrom = pITAddress.AddressName
    end if

next

'This section shows how to override Application Priority:
'after the execution of the following lines, our app will always receive incoming calls
'even if there are other running tapi apps that had registered for receiving calls before our app.

call TAPIOBJ.SetApplicationPriority("IEXPLORE.EXE",TAPIMEDIATYPE_AUDIO,TRUE)
call TAPIOBJ.SetApplicationPriority("IEXPLORE.EXE",TAPIMEDIATYPE_VIDEO,TRUE)



' Check parameters of a call before connecting it
Sub PressConnect(pNumber,Status)
On Error Resume Next
'MsgBox (pNumber & "," & Status)
DIM iAddressType
 DIM pConnectTo

DIM addressFrom
DIM selStr

'If not IsEmpty(spITCall) Then
'  MsgBox "You are currently in call. Disconnect first",0,"connect"
'End If


pConnectTo = pNumber
set CallStatus=Status

addressFrom = callFrom 

If addressFrom = "" Then
    callStatus.innerHTML = "Feature Unavailable"
    MsgBox "The TAPI Feature has not been setup on your phone line.",0,"COnnect"
else   
    sUnableToComplete = False

    callStatus.innerHTML = "Connecting to " & pConnectTo & " ...."

    'Create new internal call representation 
     For Each  pITAddress in TAPIOBJ.Addresses 
        if pITAddress.AddressName = addressFrom Then
         'Obtain ITMediaSupport
         Set pITAddress_Connect = pITAddress
         Exit For
      End If    
     Next

    Set pITAddress = Nothing

     'Create a Call
     DIM MediaTypes

     MediaTypes = TAPIMEDIATYPE_AUDIO

     Set pCall = pITAddress_Connect.CreateCall(pConnectTo,1,MediaTypes)

     Set spITCall = pCall

     if sUnableToComplete Then
       Call DisconnectCall(1)
       callStatus.innerHTML = "Call to "& pConnectTo & " failed."
     End If

     Call pCall.Connect(false)

     ' Check for error "invalid address" (see in tapi3err.h TAPI_E_INVALADDRESS=(HRESULT)0x8004000C)
     if Err.Number = &H8004000C Then
      Err.Clear
      Call DisconnectCall(1)
      callStatus.innerHTML = "Call to "& pConnectTo & " failed: Address is invalid"
      Set pCall = Nothing

    Else
      if not Err.Number = 0 Then 
        Err.Clear
        Call DisconnectCall(1)
        callStatus.innerHTML = "Call to "& pConnectTo & " failed: error " & Hex(Err.number)
        Set pCall = Nothing
      Else
        Set spITCall = pCall
      End if

    End If
end if  

Set pCall = Nothing

end sub

' Disconnect current call
Sub HangUp(callDisc)
'On Error resume Next

    if not IsEmpty(spITCall) Then

        if not callDisc = 8 and not callDisc = 0 Then 
          ' We need some kind of message pump here. The following call to MsgBox does exactly this:
          'MsgBox "A call is disconnected",0,"Disconnect"  
        End If  

        Set pVideoWindow1 = Nothing
        Set pVideoWindow2 = Nothing

    '   ConnANN.innerHTML =  "Disconnected"  

        if callDisc=0  Then
          spITCall.Disconnect(DC_NORMAL)
        End If

        Set spITCall = Nothing 
        spITCall = Empty  
        callStatus.innerHTML = "Disconnected"

        'btnDisconnect.disabled = true   
        'source.visible = false
    End If
End Sub


'*****************************************************************************
' Tapi events processing: 
' - call state events ("connected", "disconnected") 
' - and call notification events (these calls will be in "offering" state)
Sub TAPIOBJ_Event(event_type, tapi_event)
'On Error Resume Next  

'Check For disconnected call
if event_type = TE_CALLSTATE Then
  DIM pITCallStateEvent

  Set pITCallStateEvent = MAPPER.QueryDispatchInterface(_
  IID_String_ITCallStateEvent,tapi_event)

  iCallState = pITCallStateEvent.State 

  if iCallState= CS_DISCONNECTED or iCallState= CS_IDLE Then

   cause = pITCallStateEvent.Cause
   'pICallState=iCallState
   strinnerHTML = ""
   Select Case cause
     Case 1 '  CEC_DISCONNECT_NORMAL - Normal disconnect
       strinnerHTML =  "Disconnected"
     Case 2 '  CEC_DISCONNECT_BUSY
       strinnerHTML =  "Your Party is busy.Try Later."
     Case 3 '  CEC_DISCONNECT_BADADDRESS
       strinnerHTML =  "Address is invalid"
     case 4 '  CEC_DISCONNECT_NOANSWER
       strinnerHTML =  "No answer from your party."
     case 0 'CEC_NONE
       strinnerHTML =  "No answer from your party."
     Case Else
       strinnerHTML =  "Your call is cancelled, rejected or failed"       
   End Select

    'Call DisconnectCall(1)
    'btnDisconnect.disabled = true             
  End If  'Call is disconnected

  if iCallState = CS_CONNECTED Then 'Call is connected
   callStatus.innerHTML =  "Call is connected."
   'btnDisconnect.disabled =  False
  End If 'Call is connected
End If ' event: call state


'Check only for incoming calls
if event_type = TE_CALLNOTIFICATION Then ' We have an incoming call (an "offering" call)

  DIM pITCallNotificationEvent
  Set pITCallNotificationEvent = MAPPER.QueryDispatchInterface(_
  IID_String_ITCallNotificationEvent,tapi_event)

  Call CheckError("TAPIOBJ_Event:query for pITDirectoryObjectUser")   

  CallOwnership = pITCallNotificationEvent.Event

  DIM pITCallInfo

  Set pITCallInfo = pITCallNotificationEvent.Call

  Call CheckError("TAPIOBJ_Event:get pITCallInfo")   

  if not blnShowOnlyOnce and  pITCallInfo.CallState  = CS_OFFERING and not ( CallOwnership = CNE_OWNER) Then
    MsgBox "Unable to accept incoming calls: is other instance of this app running?",0,"Info"
     blnShowOnlyOnce  = True
    Exit Sub
  End IF

  if CallOwnership = CNE_OWNER Then  'We are the owner!

    if not IsEmpty(spITCall) Then
      MsgBox "Already in call, disconnect first",0,"Incoming Call"
      Exit Sub
    End if

    if  pITCallInfo.CallState  = CS_OFFERING Then 'Offering

      '-- CIS_CALLERIDNAME Wasn't working so I switched to NUMBER
      sCalleeName = pITCallInfo.CallInfoString(CIS_CALLERIDNAME)
      if not Err.number = 0 then ' Caller ID name is not supported 
        sCalleeName =  "Unknown Name"
        Err.Clear
      End if

      sCalleeNumber = pITCallInfo.CallInfoString(CIS_CALLERIDNUMBER)
      if not Err.number = 0 then ' Caller ID name is not supported 
        sCalleeNumber =  "Unknown Number"
        Err.Clear
      End if

      DIM pITCallOffer
      Set pITCallOffer = MAPPER.QueryDispatchInterface( _ 
        IID_String_ITBasicCallControl, pITCallInfo)

      Call CheckError("TAPIOBJ_Event:query for pITCall")   

      response = MsgBox("A call from '" & sCalleeNumber & " " & sCalleeName & "' has arrived. Do you want to accept it?",4,"Incoming call")

      if not response = 7    Then       'the did not press "NO", so he pressed "YES"
        Call AcceptIncomingCall(pITCallOffer, pITCallInfo)
      End If  
    End If 'Call is offering
   End If 'We are owner   

End If 'Call Notification has arrived  

End Sub 

</script>

是否可以使用 ITAPI3 托管库来摆脱这种情况并在代码隐藏中执行此操作?

4

1 回答 1

0

希望有人知道一种更清洁、更现代的方法,但这就是我所做的。

我将 VBScript 嵌入到脚本服务器端,并将其注册为客户端脚本。在注册之前,我将标签添加到 Literal 控件中,并将它们添加到页面标题中。服务器控件本身只不过是一个围绕电话图标图像的链接。

因为我可以在 javascript 中调用 VBScript 函数,所以我创建了一个 GetPhoneNumber 函数,该函数接受控件的 controlID,我将在其中获取我的电话号码。这是在 Dialer 控件的 ControlID 属性上设置的。在这种情况下,它是一个文本框。该函数解析任何不良数据的编号,然后调用 PressConnect... 完成。它可以工作,但我对以这种方式使用 VBScript 并不十分满意。

如果有人知道如何与用户的客户端(本地)TAPI 交互(实际示例将不胜感激),请在此处发布。

于 2013-02-12T23:11:23.473 回答