Aufbau eines Anrufs mit der CAPI

Zurück zur Übersicht ]   [ Einführung in die CAPI-Programmierung ]


Fortsetzung CAPI-Programmierung: Aufbau eines Anrufes

Den Quellcode aus diesem Artikel gibt es hier als VB 5-Projekt.
Eine besser funktionierende Alternative, basierend auf meinem Code aber mit einem ByteArray statt fest vorgegebenen Strukturen, hat mir dankenswerterweise Marcus Knuth zur Verfügung gestellt: CopyMem-fuer-CAPI.zip.

Um einen Anruf aufzubauen, müssen folgende Messages mit der CAPI ausgetauscht werden:

CONNECT_REQ ----->Du willst eine Verbindung aufbauen
<------CONNECT_CONFDie CAPI bestätigt dies
<------CONNECT_ACTIVE_INDDie Verbindung wurde aufgebaut, es klingelt
CONNECT_ACTIVE_RESP------->Du bestätigst dies
<-------DISCONNECT_INDDie Verbindung wurde getrennt
DISCONNECT_RESP---->Bestätigung, unbedingt erforderlich!

Die Deklarationen der verwendeten Funktionen sind im Modul des Beispielprojekts zu finden.

In meinem Beispielprojekt muss man zunächst einmal die eigene Rufnummer (MSN) und die anzurufende Nummer eingeben und dann auf "Anrufen" klicken. Dadurch wird folgender Code ausgeführt:

  Connect_Req.Appid = Appid
  Connect_Req.Command = CAPI_CONNECT
  Connect_Req.Subcommand = CAPI_REQ
  Connect_Req.MessageNumber = msgnr
  Connect_Req.Controller = &H1
  Connect_Req.CIP = 1
  Connect_Req.BProt = &H1
  Connect_Req.CalledNumber = Chr$(128) + txtNummer.Text
  Connect_Req.Length = Len(Connect_Req)
  Connect_Req.CalledNumberLen = 12
  Connect_Req.CallingNumber = Chr$(0) + Chr$(128) + txtMSN.Text
  Connect_Req.CallingNumberLen = 8
  Connect_Req.CalledSub = &H0
  Connect_Req.CallingSub = &H0
  Connect_Req.BC = &H0
  Connect_Req.LLC = &H0
  Connect_Req.HLC = &H0
  Connect_Req.AdditionalInfo = &H0
  ret = CAPI_PUT_MESSAGE(ByVal Appid, Connect_Req)

Es werden also einige Default-Werte gesetzt (Appid, Command, Subcommand usw.) und die anzurufende Nummer (Called Number) sowieso die eigene MSN (Calling Number) eingetragen. Die CAPI will bei letzteren beiden auch die Länge des Feldes wissen. Dies ist die Länge, die bei der Deklaration (siehe Beispielprojekt, capi-anruf.bas) festgelegt wurde. Mit diesem Code ist es leider nicht möglich, die Rufnummernlänge beliebig zu erlauben, denn wenn das Feld länger ist als die Rufnummer, wird der Anruf nicht aufgebaut bzw. es wird keine MSN übermittelt. Hier bietet sich der alternative Lösungsansatz von Marcus Knuth (siehe oben) mit einem Byte-Array an.

Wie auch der CAPI-Dokumentation entnehmbar ist, muss man vor die zu wählende Rufnummer ein Chr$(128) setzen, und vor die eigene MSN zusätzlich auch noch ein Chr$(0). Alle nicht benötigten Werte setze ich hier auf &H0, die MessageNummer ist fortlaufend, msgnr wird jedesmal hochgezählt.

Wenn alle Informationen eingetragen sind, werden sie an die CAPI übergeben.

Um die Verbindung wieder zu trennen, wird folgender Code benötigt:

  DisconnectReq.Appid = Appid
  DisconnectReq.Command = CAPI_DISCONNECT
  DisconnectReq.Subcommand = CAPI_REQ
  DisconnectReq.Length = Len(DisconnectReq)
  DisconnectReq.Message_Number = msgnr
  DisconnectReq.PLCI = PLCI
  ret = CAPI_PUT_MESSAGE(ByVal Appid, DisconnectReq)

Die Variable PLCI enthält eine eindeutige Nummer, die den Anruf identifiziert. Diese Nummer wird nach dem Aufbau des Calls von der Capi durch die CONNECT_CONF-Message mitgeteilt. Da der Abbau der Verbindung nicht weiter schwer ist, kommen wir gleich zur Behandlung der CAPI-Messages, die wie im Anrufmonitor in der Sub Get_Capi_Message stattfindet. Ich beschränke mich hier auf Auszüge, das Gesamtkonzept ist der CAPI-Einführung bzw. dem Quellcode zu entnehmen:

  Case CAPI_CONNECT
    If MessageHeader.Subcommand = CAPI_CONF Then 'Antwort der CAPI auf Connect-REQ
       Call RtlMoveMemory(ConnectConf, ByVal (lpCapiBuffer + HeaderLength), _
             ByVal (MessageHeader.Length - HeaderLength))
       PLCI = ConnectConf.PLCI
    End If

Beim CONNECT_CONF (wird von der CAPI nach unserem CONNECT_IND geschickt) bekommen wir also die PLCI und speichern sie zur späteren Verwendung.

Nachdem der Call verarbeitet wurde und es auf der Gegenstelle klingelt, kommt ein CONNECT_ACTIVE_IND:

  Case CAPI_CONNECT_ACTIVE
    If MessageHeader.Subcommand = CAPI_IND Then
      With ConnectActiveResp
         .Appid = Appid
         .Command = CAPI_CONNECT_ACTIVE
         .Subcommand = CAPI_RESP
         .Length = Len(ConnectActiveResp)
         .Message_Number = &H0
         .PLCI = PLCI
      End With
      x = CAPI_PUT_MESSAGE(ByVal Appid, ConnectActiveResp)
    End If

Auch hier benötigt man wieder die PLCI, um korrekt mit einem CONNECT_ACTIVE_RESP antworten zu können.

Wird nun die Verbindung unterbrochen, kommt ein DISCONNECT_IND:

  Case CAPI_DISCONNECT
    If MessageHeader.Subcommand = CAPI_IND Then
       Call RtlMoveMemory(DisconnectInd, ByVal (lpCapiBuffer + HeaderLength), _
             ByVal (MessageHeader.Length - HeaderLength))
       MsgBox "Verbindung wurde beendet: " & Info_Number_Evaluation$(DisconnectInd.Reason)
       With DisconnectResp
         .Length = Len(DisconnectResp)
         .Appid = Appid
         .Command = CAPI_DISCONNECT
         .Subcommand = CAPI_RESP
         .Message_Number = &H0
         .PLCI = PLCI
       End With
        
       x = CAPI_PUT_MESSAGE(ByVal Appid, DisconnectResp)
    End If

Selbes Spiel, antworten mit DISCONNECT_RESP, einsetzen der PLCI zur Identifizierung. Um den Grund der Trennung zu erfahren, wird aus dem übergegebenen Buffer hier noch die Reason ausgelesen und durch die Funktion Info_Number_Evaluation$, die die wichtigsten Gründe enthält, ausgewertet.

Sobald ich weitere Erkenntnisse habe, werde ich diese hier veröffentlichen!