Initializing TAPI

As with most API's you need to call a couple of initialization routines before you can get TAPI rolling. All TAPI functions begin either with the word "line" or "phone". For instance, the function that you call to initialize TAPI is called lineInitializeEx. You call lineInitializeEx to well, initialize TAPI. This is how its been declared in tapi.h,

LONG WINAPI lineInitializeEx(
	LPHLINEAPP lphLineApp,
	HINSTANCE hInstance,
	LINECALLBACK lpfnCallback,
	LPCSTR lpszFriendlyAppName,
	LPDWORD lpdwNumDevs,
	LPDWORD lpdwAPIVersion,
	LPLINEINITIALIZEEXPARAMS lpLineInitializeExParams
);

It is quite possible that you have begun to think of dropping the whole idea of writing telephony applications using TAPI after having taken just one look at this function. But rest assured that the call is not half as intimidating when you write the code. Lets dissect the call and inspect it piece by piece starting with the first argument.

LPHLINEAPP lphLineApp: -
Your connection to TAPI in the application is represented (as with most things in Win32) by a magical little handle that you need to pass around in all your calls to TAPI functions. This handle is called HLINEAPP. You would declare a handle of this type in the following manner,

HLINEAPP hLineApp;
and supply its address as the first parameter to lineInitializeEx. For eg.,

HLINEAPP hLineApp;

lineInitializeEx( &hLineApp, ...
HINSTANCE hInstance: -
You would supply the application's instance handle here or if you don't feel like it, the handy little NULL will suffice :). For eg.,

HLINEAPP hLineApp;

lineInitializeEx( &hLineApp, NULL, ...
LINECALLBACK lpfnCallback: -
You must have realised that one of the basic capabilities that an API like TAPI must possess in order to be taken seriously is the ability to detect and notify events. With TAPI you have a few options as to how you would like this to happen. For eg., you can have TAPI call a callback function everytime something of interest occurs or let it create a Win32 "event" object on which you can wait (click here to know more about event objects). If you choose the former method, then this parameter is a pointer to a function which has been declared like this,
void __stdcall lineCallback( DWORD dwDeviceID,
                             DWORD dwMessage,
                             DWORD dwInstance,
                             DWORD dwParam1,
                             DWORD dwParam2,
                             DWORD dwParam3 );
Personally I prefer the latter method.

LPCSTR lpszFriendlyAppName: -
A user-friendly name for the application which is returned in the LINECALLINFO structure (through a call to lineGetCallInfo). This can be NULL in which case the application's module file name is used (GetModuleFileName).

LPDWORD lpdwNumDevs: -
Every telephony capable device attached to the computer (such as a modem) is called a "line device". The caller is expected to give the address of a DWORD sized variable where a count of the number of devices attached to the system is stored.

LPDWORD lpdwAPIVersion: -
One issue that TAPI applications must deal with is the version of the API that it is stuck with. The application is expected to set a DWORD variable to the highest API version it is designed to support and pass its address as this parameter. The values that are valid have been tabulated below.

TAPI
Version
Value to be supplied
1.3 0x00010003
1.4 0x00010004
2.0 0x00020000
2.1 0x00020001
2.2 0x00020002

When the function returns, this location is filled with highest version supported by TAPI.

LPLINEINITIALIZEEXPARAMS lpLineInitializeExParams: -
A pointer to a structure of type LINEINITIALIZEEXPARAMS containing information about the event notification mechanism to use. This structure, not quite in keeping with its rather lengthy name, is a small one. Ignoring the first 4 members which have to do with dynamic resizing of the memory allocated to the structure (or in other words - nothing to do with TAPI!) the first relevant member is a DWORD called dwOptions. Before calling lineInitializeEx the application is expected to set this member to one of the LINEINITIALIZEEXOPTION_ constants. The possible values are,

Constant Meaning
LINEINITIALIZEEXOPTION_
   USEHIDDENWINDOW
If this option is chosen then TAPI creates a hidden window during initialization and whenever there is a message, it is posted to this window. It then delivers the message to the application by calling the callback function whose address has been specified in the 3rd parameter of lineInitializeEx.

LINEINITIALIZEEXOPTION_
   USEEVENT
This option is specified to use Win32 event objects for event notification. When lineInitializeEx returns, a handle to an event object created by TAPI on behalf of the application is stored in the hEvent member of the LINEINITIALIZEEXPARAMS structure. The only thing that the application is expected to do with this handle is wait on it. Whenever an event occurs, TAPI signals this event object. The application can then retrieve the message by calling lineGetMessage. To learn more about Win32 event objects, click here.

LINEINITIALIZEEXOPTION_
   USECOMPLETIONPORT
This option can be chosen in order to use Win32 IO completion ports for event notification.

The function returns zero if the call succeeds or a negative number (one of the LINERR_ constants) if it fails.

Those are all the parameters that lineInitializeEx takes. When you actually make the call, it is not quite so forbidding :). An example of how this function could be called is given below.


LONG lResult;
LINEINITIALIZEEXPARAMS lineInit;
HLINEAPP hLineApp = 0;
DWORD dwApiVersion = 0x00020002;
DWORD dwNumDevs = 0;
HANDLE hTapiEvent = 0;

memset( &lineInit, 0, sizeof( lineInit ) );

lineInit.dwTotalSize = sizeof( lineInit );
lineInit.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT;

lResult = lineInitializeEx( &hLineApp,	   //handle to TAPI - [out]
			    NULL,	   //HINSTANCE of the application - [in]
			    NULL,	   //pointer to callback function - [in]
			    "TAPI App!",   //friendly application name - [in]
			    &dwNumDevs ),  //number of line devices on the system - [out]
			    &dwApiVersion, //highest API version supported by TAPI - [in, out]
			    &lineInit );   //pointer to LINEINITIALIZEEXPARAMS object - [in, out]

if( lResult != 0 )
	SomethingReallyBadHappened( "!" );
else
	hTapiEvent = lineInit.Handles.hEvent;

1