- Initialisierung
- Versioning
- Leitungen und Geräte: lineGetDevCaps
- Die Telefonnummer einer Leitung: lineGetAddressCaps
- Registrieren einer Leitung für den Ereignisempfang: lineOpen
- Ereignisse auslesen: lineGetMessage
- Die TAPI wird aktiv
Überblick und Hinweise
Die TAPI ist eine Schnittstelle von Microsoft, implementiert in den Windows-Versionen seit XP und teils schon früher.Die TAPI 1.x ist in der Lage, ein beispielsweise über USB direkt am Computer angeschlossenes Telefon zu steuern.
Die TAPI 2.x kann eine Third Party Anbindung an die Telefonanlage über das Netzwerk steuern.
Für die TAPI 3.x gibt es mit JTAPI sogar eine Java-Anbindung. TAPI 3.x basiert auf COM. Leider wird es selten von den Telefonanlagenherstellern unterstützt.
Microsoft dokumentiert die TAPI in seiner MSDN: MSDN-Artikel TAPI 2.2 Overview
First Party wird die direkte Anbindung eines Computers an ein Telefon genannt. Der PC kann die Aktivitäten des Telefons übernehmen, etwa abheben, wählen oder weiterverbinden.
Daneben gibt es die Anbindung eines Computers an die Telefonanlage über das lokale Netzwerk, die als Third Party bezeichnet wird.
Einrichtung des TAPI-Clients
Um eine TAPI-Anwendung zu starten, muss der Rechner als TAPI-Client eingerichtet werden.Zum Einrichten eines TAPI-Clients wird der Befehl tcmsetup aufgerufen, beispielsweise in der Ausführungszeile, die über die Tastenkombination [Windows]-[R] gestartet werden kann. Ansonsten wird es über die Eingabeaufforderung gestartet.
tcmsetup /c tapiserverAls tapiserver wird der Name des TAPI-Servers genannt, der die Telefonanlage bedient.
Initialisierung
Als erste Funktion wird lineInitializeEx aufgerufen. Die Funktion liefert vor allem das Applikations-Handle (lphLineApp) und die Anzahl der zur Verfügung stehenden Geräte (lpdwNumDevs).
LONG WINAPI lineInitializeEx( LPHLINEAPP lphLineApp, HINSTANCE hInstance, LINECALLBACK lpfnCallback, LPCSTR lpszFriendlyAppName, LPDWORD lpdwNumDevs, LPDWORD lpdwAPIVersion, LPLINEINITIALIZEEXPARAMS lpLineInitializeExParams );
- lphLineApp
- Zeiger auf eine Variable vom Typ HLINEAPP, die später das Handle der Applikation zum TAPI enthalten wird.
- hInstance
- Hier wird das Instanz-Handle der Anwendung oder der DLL übergeben. Der Parameter darf lt. Doku auch NULL sein.
- lpfnCallback
- Hier wird die Callback-Funktion angegeben, die aufgerufen wird, wenn die Anwendung als Ereignisrückmeldemethode "hidden window" verwendet. Bei den anderen Methoden wird dieser Eintrag ignoriert und sollte NULL sein.
- lpszFriendlyAppName
- Ein Text, der den Namen der Anwendung enthält. Dieser Paramter dient hauptsächlich dekorativen Zwecken und kann auch NULL gesetzt werden.
- lpdwNumDevs
- Hier wird die Adresse der DWORD-Variablen abgelegt, in der nach einem erfolgreichen Aufruf die Anzahl der verfügbaren Line-Geräte stehen soll.
- lpdwAPIVersion
- Hier wird die Adresse einer DWORD-Variablen übergeben, die die TAPI-Version enthält. Vor dem Aufruf wird dieser Wert mit dem höchsten Wert belegt, den die Anwendung unterstützt.
- lpLineInitializeExParams
- Adresse einer LINEINITIALIZEEXPARAMS-Struktur. Das Element dwTotalSize muss vor dem Aufruf unbedingt korrekt gesetzt sein. Mit dwOptions wird die Ereignis-Rückmeldung bestimmt. Siehe weiter unten.
- Rückgabewert:
- 0, wenn der Aufruf erfolgreich war, ansonsten eine negative Fehlernummer.
Anmeldung der Ereignisrückmeldung
Durch Besetzung des Feldes dwOption in der Struktur LINEINITIALIZEEXPARAMS, die als Parameter an die Funktion lineInitializeEx übergeben wird, wird festgelegt, wie die Ereignisse der Telefonanlage an die Anwendung zurückgemeldet werden.- hidden window
- dwOption=LINEINITIALIZEEXOPTION_USEHIDDENWINDOW;
- event handle
- dwOption=LINEINITIALIZEEXOPTION_USEEVENT;
Der Aufruf liefert im Element hEvent das Event-Handle, das aber nicht weiterverwendet werden muss. Man kann es WaitForSingleObject verwenden. Diese Variante der Ereignissuche wird hier weiter verfolgt. - completion port
- dwOption=LINEINITIALIZEEXOPTION_USECOMPLETIONPORT;
Das Element hCompletionPort muss mit dem Handle besetzt werden, das mit der Funktion CreateIoCompletionPort verwendet wird.
Versioning
Man fragt die eigene Schnittstelle und die Gegenstation, welche TAPI-Version sie beherrscht. Die Funktionen lauten lineNegotiateAPIVersion. Für Erweiterungen der TAPI gibt es noch die Funktion lineNegotiateExtVersion.Die Funktion wird für jede Leitung aufgerufen. Der Wert von dwDeviceID liegt zwischen 0 und der Anzahl der gemeldeten Leitungen/Geräte -1.
LONG WINAPI lineNegotiateAPIVersion( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPILowVersion, DWORD dwAPIHighVersion, LPDWORD lpdwAPIVersion, LPLINEEXTENSIONID lpExtensionID );Die Parameter haben folgende Bedeutung
- hLineApp
- Das TAPI-Handle.
- dwDeviceID
- Index der Leitung zwischen 0 und Gerätezahl-1.
- dwAPILowVersion
- Die niedrigste TAPI-Version, mit der die Anwendung arbeiten kann oder will.
- dwAPIHighVersion
- Die höchste TAPI-Version, die die Anwendung beherrscht.
- lpdwAPIVersion
- Hier wird die Adresse eine DWORD-Variable angegeben, in der die Funktion die TAPI-Version ablegt, die das Gerät beherrscht. Diese muss bei den Aufrufen fuer diese Leitung übergeben werden.
- lpExtensionID
- Zeiger auf eine Variable vom Typ LINEEXTENSIONID. Nur wichtig, wenn der Geräteanbieter irgendwelche Erweiterungen zur TAPI implementiert.
- Rückgabewert
- 0 für Erfolg, ansonsten eine negative Fehlernummer.
Leitungen und Geräte: lineGetDevCaps
lineGetDevCaps beschafft die Informationen über die verfügbaren Leitungen. Die Eingabeparameter sind das TAPI-Instance-Handle der Anwendung, die Gerätenummer und die TAPI-Version. Zurückgeliefert wird ein Zeiger auf eine Struktur vom Typ LINEDEVCAPS. Aber Vorsicht! Die Größe ist vor dem Aufruf nicht bekannt.Hintergrund ist die MSDN-Information von Microsoft.
LONG WINAPI lineGetDevCaps( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, DWORD dwExtVersion, LPLINEDEVCAPS lpLineDevCaps );
- hLineApp
- Das Applikationshandle der TAPI, wie sie von lineInitializeEx geliefert wird.
- dwDeviceID
- Die Nummer der Leitung. Die Leitungen werden durchnummeriert von 0 bis zur maximalen Zahl der Geräte, die als lpdwNumDevs von der Funktion lineInitializeEx geliefert wird.
- dwAPIVersion
- Die Versionsnummer der TAPI kann für jedes Gerät anders sein. Am besten, man bestimmt diese zuvor über die Funktion lineNegotiateAPIVersion.
- dwExtVersion
- Versionsnummer für Erweiterungen des Herstellers. In den meisten Fällen ist 0 eine gute Idee.
- lpLineDevCaps
- Ein Zeiger auf eine Struktur LINEDEVCAPS. Vor dem Aufruf muss das Element dwTotalSize auf die Größe der Struktur festgesetzt werden, sonst kommt es zu unvorhersehbaren Effekten. Siehe unten!
- Rückgabewert
- Die Funktion liefert 0, wenn alles klappte. Ansonsten eine negative Fehlernummer.
Die LINEDEVCAPS-Struktur
Die ausführliche Strukturbeschreibung findet sich auf den MSDN-Seiten.Die TAPI versucht, an die LINEDEVCAPS-Struktur noch einige Zeichenketten anzuhängen, die dann per Offset erreicht werden. Darum muss zwischen Anwendung und TAPI ausgehandelt werden, wie groß der zur Verfügung stehende Speicher ist. Drei Elementvariablen sind für diese Aushandlung relevant.
- dwTotalSize
- Dies ist die Größe des Speichers, den die Anwendung zur Verfügung stellt. Sie sollte mindestens sizeof(LINEDEVCAPS) sein. Man kann auch in weiser Voraussicht ein wenig mehr spendieren.
- dwNeededSize
- Die TAPI besetzt anschließend dieses Feld mit der Größe, die sie benötigt. Ist der Wert höher als dwTotalSize, sollte die Anwendung neuen Speicher anfordern und den Aufruf wiederholen.
- dwUsedSize
- Enthält die Größe des Speicherbereichs, der tatsächlich mit Daten gefüllt wurde.
- dwLineNameSize Die Länge des Leitungsnamens. Ist dies 0, gibt es keinen.
- dwLineNameOffset
- Dieser Wert gibt die Distanz zwischen dem Anfang der LINEDEVCAPS-Struktur und dem Anfang des Leitungsnamens an. Soll der Leitungsname in einen String namens ziel kopiert werden, gibt man folgende Anweisung:
int lineDevCapsSize = sizeof(LINEDEVCAPS + 4096; LINEDEVCAPS *lineDevCaps = new char[lineDevCapsSize]; lineDevCaps->dwTotalSize = lineDevCapsSize; long err = lineGetDevCaps( ..., lineDevCaps); ... memcpy(ziel, (char*)lineDevCaps + lineDevCaps->dwLineNameOffset, lineDevCaps->dwLineNameSize);
Die Telefonnummer einer Leitung: lineGetAddressCaps
Diese Funktion ermittelt die Telefonnummer der angegebenen Leitung. Die Informationen basieren auf der MSDN-Seite zu lineGetAddressCaps.LONG WINAPI lineGetAddressCaps( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAddressID, DWORD dwAPIVersion, DWORD dwExtVersion, LPLINEADDRESSCAPS lpAddressCaps );
- hLineApp
- Anwendungs-TAPI-Handle
- dwDeviceID
- Die Nummer der Leitung. Die Leitungen werden durchnummeriert von 0 bis zur maximalen Zahl der Geräte, die als lpdwNumDevs von der Funktion lineInitializeEx geliefert wird.
- dwAddressID
- Die ID der Adresse. Hier funktioniert 0.
- dwAPIVersion
- Hier wird die TAPI-Version übergeben. Die Versionsnummer erhält man durch Aufruf von lineNegotiateAPIVersion.
- dwExtVersion
- Hier funktioniert auch 0.
- lpAddressCaps
- Hier wird ein Zeiger auf eine Datenstruktur vom Typ LINEADDRESSCAPS übergeben. Die Daten muss der Aufrufer angefordert haben - und ein wenig mehr. Die Größe der Datenstruktur muss in dem Element dwTotalSize vor dem Aufruf abgelegt werden.
- Rückgabewert
- Liefert bei Erfolg eine 0 zurück, ansonsten eine Fehlernummer.
Registrieren einer Leitung für den Ereignisempfang: lineOpen
lineOpen meldet eine Leitung an, deren Ereignisse gefangen werden soll. Der Aufruf ist auch die Voraussetzung dafür, Anrufe mit den Funktionen lineMakeCall, lineUnpark, linePickup, lineSetupConference oder lineForward zu steuern.Die Informationen dieses Abschnitts basieren auf der MSDN-Seite zu lineOpen und eigenen Experimenten.
LONG WINAPI lineOpen( HLINEAPP hLineApp, DWORD dwDeviceID, LPHLINE lphLine, DWORD dwAPIVersion, DWORD dwExtVersion, DWORD_PTR dwCallbackInstance, DWORD dwPrivileges, DWORD dwMediaModes, LPLINECALLPARAMS const lpCallParams );
- hLineApp
- Anwendungs-TAPI-Handle
- dwDeviceID
- Die Leitungsnummer, die geöffnet werden soll.
- lphLine
- Zeiger auf eine Variable, die nach dem Aufruf das Leitungs-Handle enthalten wird.
- dwAPIVersion
- Die TAPI-Version, auf die sich Anwendung und Gerät/Leitung mittels der Funktion lineNegotiateAPIVersion geeinigt haben.
- dwExtVersion
- Die Version der Hersteller-Erweiterung, sofern eine genutzt wird. Normalerweise wird hier 0 übergeben.
- dwCallbackInstance
- Hier kann die Applikation einen Zeiger auf einen beliebigen Datenbestand übergeben, der beim Eintreffen eines TAPI-Ereignisses zurückgegeben wird. Die TAPI selbst interpretiert diesen Parameter nicht.
- dwPrivileges
- Hier werden Privilegien gesetzt, die die Applikation anfordert. Typischerweise sind dies LINECALLPRIVILEGE_MONITOR | LINECALLPRIVILEGE_OWNER.
- dwMediaModes
- Hier werden die LINEMEDIAMODE_-Konstanten gesetzt, typischerweise LINEMEDIAMODE_VOICEVIEW.
- lpCallParams
- Dieser Wert wird ignoriert, wenn nicht LINEMAPPER or LINEOPENOPTION_PROXY benutzt werden, und darum auf 0 gesetzt.
- Rückgabewert
- Die Funktion gibt 0 im Erfolgsfall, andernfalls
eine negative Fehlernummer zurück.
- LINEERR_ALLOCATED
- Die Leitung ist permanent durch einen anderen Prozess belegt.
- LINEERR_RESOURCEUNAVAIL
- Die Leitung ist kurzfristig belegt, kann aber vielleicht etwas später wieder verfügbar sein. Ein neuer Versuch ist sinnvoll.
- LINEERR_REINIT
- Durch eine TAPI-Reinitialisierung ausgelöst. Die Anwendung muss wohl neu initialisieren.
Beim Aufruf von openLine ist die API-Version von entscheidender Wichtigkeit. Darum sollte diese zuvor unbedingt per lineNegotiateAPIVersion ermittelt werden.
Ereignisse auslesen: lineGetMessage
Die Funktion lineGetMessage fragt die Ereignisse aller durch lineOpen geöffneten Leitungen an.LINEMESSAGE lineMessage; long err = lineGetMessage(handleLineApp, &lineMessage, 0);Der Prototyp der Funktion lautet:
LONG WINAPI lineGetMessage( HLINEAPP hLineApp, LPLINEMESSAGE lpMessage, DWORD dwTimeout );
- hLineApp
- Das Handle der Anwendung
- lpMessage
- Zeiger auf eine Struktur des Typs LINEMESSAGE, in der die Funktion ihre Ergebnisse hinterlegt.
- dwTimeout
- Timeout in Millisekunden. Wie lange die Funktion auf Ereignisse wartet.
- Rückgabe
- 0 bei Erfolg, negativ bei Fehler. Dabei bedeutet der Fehler LINEERR_OPERATIONFAILED lediglich, dass noch keine Ereignisse vorliegen.
Die LINEMESSAGE-Struktur:
typedef struct linemessage_tag { DWORD hDevice; DWORD dwMessageID; DWORD_PTR dwCallbackInstance; DWORD_PTR dwParam1; DWORD_PTR dwParam2; DWORD_PTR dwParam3; } LINEMESSAGE, *LPLINEMESSAGE;
- hDevice
- Handle (nicht Index) der Leitung oder des Calls, je nachdem, was das Ereignis ausgelöst hat.
- dwMessageID
-
kann folgende Werte annehmen:
- LINE_REPLY
- Wird nach einem lineMakeCall oder lineDrop ausgelöst. Der Aufruf dieser Funktionen erfolgt asynchron. Der Rückgabewert ist eine ID, kein Handle. Diese ID wird mit dem Parameter dwParam1 geliefert und identifiziert den Aufruf. dwParam2 liefert ggf. eine negative Fehlernummer, sonst 0. Erst nach LINE_REPLY ist auch das Call-Handle von lineMakeCall gültig.
- LINE_CALLSTATE
- Ein Anruf hat seinen Status verändert.
Es wird weiter unterschieden anhand des Wertes in lineMessage.dwParam1:
- LINECALLSTATE_OFFERING
- Ein Anruf ist eingetroffen. Das Telefon klingelt.
- LINECALLSTATE_IDLE
- Der Anruf wurde beendet.
- LINECALLSTATE_CONNECTED
- Ein Anruf wurde verbunden.
- LINECALLSTATE_DISCONNECTED
- Ein Anruf wurde von der Gegenstation getrennt. Hier kann lineDrop aufgerufen werden.
- LINE_CALLINFO
- Ein Anruf liefert Informationen.
Nach dem Aufruf von lineGetCallInfo
lassen sich diese Informationen aus der Struktur LINECALLINFO
auslesen. Welcher Bestandteil der Struktur verändert wurde,
lässt sich anhand des Message-Parameters dwParam1 auslesen.
Er enth&aulm;lt den eine Konstante vom Typ LINECALLINFOSTATE_xxx.
- LINECALLINFOSTATE_CALLEDID
- Die Telefonnummer, die der Anwender gewählt wurde, wurde eingetragen.
- dwCallbackInstance
- Hier wird der Zeiger wieder hervorgebracht, den die Anwendung beim Aufruf von lineInitializeEx im Parameter dwCallBackInstance abgelegt hat. Bei geschickter Wahl des übergebenen Zeigers kann die Ereignisbearbeitung die Leitung damit leicht identifizieren.
- dwParam1, dwParam2 und dwParam3
- Weitere Parmeter für die verschiedenen Nachrichtentypen.
Informationen über einen Anruf: lineGetCallInfo
lineGetCallInfo ermittelt die Daten über einen Anruf. Insbesondere die Telefonnummer des Anrufenden lässt sich hier ermitteln.LONG WINAPI lineGetCallInfo( HCALL hCall, LPLINECALLINFO lpCallInfo );
- hCall
- Handle für den Anruf
- lpCallInfo
- Zeiger auf eine Struktur LINECALLINFO
- Rückgabewert 0 bei Erfolg, negativ als Fehlermeldung
- dwTotalSize, dwNeededSize, dwUsedSize
- Das Element dwTotalSize muss vor dem Aufruf gesetzt sein. Es reicht nicht aus, nur die sizeof(LINECALLINFO) zu verwenden, sondern es muss etwas mehr reserviert werden, damit die TAPI noch Strings anhängen kann. Sollte der Platz nicht reichen, gibt es einen negativen Rückgabewert. Ansonsten liefert dwUsedSize, wieviel Speicher in Anspruch genommen wurde.
- dwCallerIDSize, dwCallerIDOffset
- Dahinter verbirgt sich die Telefonnummer des Anrufers als C-String. Er beginnt am Anfang der Struktur LINECALLINFO plus dwCallerIDOffset und ist dwCallerIDSize lang.
Die TAPI wird aktiv
Das Programm telefoniert: lineMakeCall
Alternativ - oder auch in Kombination - kann lineMakeCall zu lineDialverwendet werden. Hier wird die Leitungsnummer als Parameter übergeben werden. Die Leitung muss durch lineOpen zuvor geöffnet worden sein.
LONG WINAPI lineMakeCall( HLINE hLine, LPHCALL lphCall, LPCSTR lpszDestAddress, DWORD dwCountryCode, LPLINECALLPARAMS const lpCallParams );
- hLine
- Das Handle der Leitung, über den die Wahl erfolgen soll.
- lphCall
- Der Aufruf liefert das Handle des Anrufs in eine Variable zurück, deren Adresse hier übergeben wird. Allerdings ist der Wert nicht sofort gültig, sondern erst, wenn ein LINE_REPLY-Ereignis durch lineGetMessage empfangen wurde.
- lpszDestAddress
- Die Telefonnummer als String, die angerufen werden soll.
- dwCountryCode
- Der Landes- oder Regionalcode der Zielnummer. Wird hier 0 übergeben, wird die Vorgabe der Telefonanlage verwendet.
- Rückgabewert
- Ist negativ, wenn ein Fehler auftrat, positiv bei asynchronem Ende der Funktion. Dieser Wert ist eine ID, die bei dem beim zugehörigen LINE_REPLY-Ereignis im Parameter dwParam1 steht.
Das Programm wählt: lineDial
Mit der Funktion lineDial kann eine Nummer gewählt werden. Voraussetzung ist ein bereits existierender Anruf. Dieser könnte beispielsweise durch lineMakeCall erzeugt worden sein, wenn dieser keine Rufnummer als Paramter übergibt.
LONG WINAPI lineDial( HCALL hCall, LPCSTR lpszDestAddress, DWORD dwCountryCode );
- hCall
- Das Handle des Anrufs über den die Wahl erfolgen soll. Dieses wird beispielsweise durch lineMakeCall erzeugt.
- lpszDestAddress
- Die Telefonnummer als String, die angerufen werden soll.
- dwCountryCode
- Der Landes- oder Regionalcode der Zielnummer. Wird hier 0 übergeben, wird die Vorgabe der Telefonanlage verwendet.
- Rückgabewert
- Ist negativ, wenn ein Fehler auftrat, positiv bei asynchronem Ende der Funktion.
Das Programm legt auf: lineDrop
Mit der Funktion lineDrop legt das Programm den Hörer auf. Voraussetzung ist ein Call-Handle, also ein Anruf. Dieser könnte beispielsweise durch lineMakeCall erzeugt worden sein, oder bei einigen Ereignissen durch lineGetMessage ermittelt worden sein. Paramter übergibt.
LONG WINAPI lineDrop( HCALL hCall, LPCSTR lpsUserUserInfo, DWORD dwSize );
- hCall
- Das Handle des Anrufs der beendet werden soll.
- lpsUserUserInfo
- Zeiger eines Strings, der an die andere Seite gesandt werden soll. Normalerweise NULL.
- dwSize
- Die Größe des Strings. Normalerweise 0.
- Rückgabewert
- Ist negativ, wenn ein Fehler auftrat, eine positive ID bei asynchronem Ende der Funktion. Diese ID wird beim LINE_REPLY-Ereignis in dwParam1 zur Identifikation gesendet.
Das Programm hebt ab: lineAnswer
Die Funktion lineAnswer nimmt den Hörer ab, wenn ein Anruf anliegt. Dies erfährt das Programm durch ein Ereignis, das die Funktion lineGetMessage ausliest.
LONG WINAPI lineAnswer( HCALL hCall, LPCSTR lpsUserUserInfo, DWORD dwSize );
- hCall
- Das Handle des Anrufs der entgegen genommen werden soll.
- lpsUserUserInfo
- Zeiger eines Strings, der an die andere Seite gesandt werden soll. Normalerweise NULL.
- dwSize
- Die Größe des Strings. Normalerweise 0.
- Rückgabewert
- Ist negativ, wenn ein Fehler auftrat, eine positive ID bei asynchronem Ende der Funktion. Diese ID wird beim LINE_REPLY-Ereignis in dwParam1 zur Identifikation gesendet.