December 18, 2014
Hot Topics:

Understanding Windows CE Telephone API (TAPI): Introduction

  • April 15, 2005
  • By Alex Gusev
  • Send Email »
  • More Articles »

The Hidden Window mechanism is selected by one of two ways:

  • when you call lineInialize
  • by specifying lpLineInitializeExParams->dwOptions = LINEINITIALIZEEXOPTION_USEHIDDENWINDOW

As a result, TAPI creates a hiden window that receives messages from TAPI when some events occur. Subclassing this window, TAPI finally calls lineCallbackFunc.

The Event Handle mechanism is selected when you set lpLineInitializeExParams->dwOptions = LINEINITIALIZEEXOPTION_USEEVENT. In this case, TAPI creates an event object on behalf of the application, and returns a handle to the object in the lpLineInitializeExParams->hEvent. Your application mustn't try to call any functions to change the state of this event (as in SetEvent, ResetEvent, or CloseHandle). Otherwise, the result of TAPI operations will be unpredicted. All your application can do is to wait on this event using functions such as WaitForSingleObject or MsgWaitForMultipleObjects. TAPI will fire this event every time some telephony event notification is pending for the application. After the event is signalled, the application should call lineGetMessage to obtain the message contents. When lineShutdown is called, the event handle is closed and the event object destroyed by TAPI. You can choose between waiting on created event handle or simply calling lineGetMessage and having it blocked until a message will be queued. Just decide which method is more suitable for your needs.

Implementing the Line Callback Function

As you have seen above, the Line Callback function is used by TAPI to inform your application about various events that happen during the TAPI session. First of all, the good news is that you can leave the callback function empty in case you do not intend to use any TAPI handles during session lifetime. The simplest example of it is device enumeration, when you want to obtain some information about available TAPI devices only.

The sample implementation of a callback function will be as simple as possible. Again, place its definition here:

VOID PASCAL LineCallbackFunc(
     DWORD hDevice,
     DWORD dwMsg,
     DWORD dwCallbackInstance,
     DWORD dwParam1,
     DWORD dwParam2,
     DWORD dwParam3)
{
...
}

The first parameter is a handle either of a line device or a call on which TAPI is informing your application. More interesting parameters are dwMsg and dwParamN. They describe fired message and its specific data. You can find a complete list of TAPI messages in the SDK documentation with a detailed description of each message parameter. To avoid odd duplication of existing documentation, I would simply like to redirect you to a well-commented SDK sample called CEDialer. It contains a sample implementation of lineCallbackFunc with gorgeous explanations of many TAPI messages. Below is a short excerpt from this sample:

VOID CALLBACK lineCallbackFunc(
     DWORD hDevice,
     DWORD dwMsg,
     DWORD dwCallbackInstance,
     DWORD dwParam1,
     DWORD dwParam2,
     DWORD dwParam3)
{
...
      switch (dwMsg)
      {
         case LINE_CALLSTATE:    // Sent after change of call state

         // dwParam1 is the specific CALLSTATE change that is occurring.
         switch (dwParam1)
         {
         case LINECALLSTATE_DIALTONE:
            lpszStatus = TEXT("Dial tone");
            break;

         case LINECALLSTATE_DIALING:
            lpszStatus = TEXT("Dialing...");
            break;

         case LINECALLSTATE_PROCEEDING:
            lpszStatus = TEXT("Dialing completed, call proceeding.");
            break;

         case LINECALLSTATE_RINGBACK:
            lpszStatus = TEXT("Ring back");
            break;

         case LINECALLSTATE_CONNECTED:
            lpszStatus = TEXT("Connected");
            break;

         case LINECALLSTATE_BUSY:
            lpszStatus = TEXT("Line busy, shutting down.");
            bCloseLine = TRUE;
            break;

         case LINECALLSTATE_IDLE:
            lpszStatus = TEXT("Line is idle");
            break;

         case LINECALLSTATE_SPECIALINFO:
            lpszStatus =TEXT("Special Information, couldn't dial number");
            bCloseLine = TRUE;
            break;

         case LINECALLSTATE_DISCONNECTED:
            {
               LPTSTR lpszDisconnected;
               lpszDisconnected = TEXT(" ");

               switch (dwParam2)
               {
               case LINEDISCONNECTMODE_NORMAL:
                  lpszDisconnected = TEXT("Remote party disconnected");
                  break;

               case LINEDISCONNECTMODE_UNKNOWN:
                  lpszDisconnected = TEXT("Disconnected: Unknown reason");
                  break;

               case LINEDISCONNECTMODE_REJECT:
                  lpszDisconnected = TEXT("Remote Party rejected call");
                  break;

               case LINEDISCONNECTMODE_PICKUP:
                  lpszDisconnected =
                     TEXT("Disconnected: Local phone picked up");
                  break;

               case LINEDISCONNECTMODE_FORWARDED:
                  lpszDisconnected = TEXT("Disconnected: Forwarded");
                  break;

               case LINEDISCONNECTMODE_BUSY:
                  lpszDisconnected = TEXT("Disconnected: Busy");
                  break;

               case LINEDISCONNECTMODE_NOANSWER:
                  lpszDisconnected = TEXT("Disconnected: No Answer");
                  break;

               case LINEDISCONNECTMODE_BADADDRESS:
                  lpszDisconnected = TEXT("Disconnected: Bad address");
                  break;

               case LINEDISCONNECTMODE_UNREACHABLE:
                  lpszDisconnected = TEXT("Disconnected: Unreachable");
                  break;

               case LINEDISCONNECTMODE_CONGESTION:
                  lpszDisconnected = TEXT("Disconnected: Congestion");
                  break;

               case LINEDISCONNECTMODE_INCOMPATIBLE:
                  lpszDisconnected = TEXT("Disconnected: Incompatible");
                  break;

               case LINEDISCONNECTMODE_UNAVAIL:
                  lpszDisconnected = TEXT("Disconnected: Unavailable");
                  break;

               case LINEDISCONNECTMODE_NODIALTONE:
                  lpszDisconnected = TEXT("Disconnected: No dial tone");
                  break;

               default:
                  lpszDisconnected = TEXT("Disconnected: Unknown reason");
                  break;
               }    // end switch (dwParam2)

               bCloseLine = TRUE;
               wcscpy(lpszStatus,lpszDisconnected);
               break;
            }       // end case LINECALLSTATE_DISCONNECTED:
         }          // end switch (dwParam1)

         if (g_hwndDial)
            SendDlgItemMessage(g_hwndDial, IDC_STATUSMESSAGE, WM_SETTEXT,
                               0,(LPARAM)lpszStatus);

         if (bCloseLine)
         {
            CurrentLineClose ();
            if (g_hwndDial)
               SendMessage (g_hwndDial, WM_COMMAND, MAKEWPARAM(IDOK,0), 0);
         }
         break;
         ....
      }

As you can see, the callback gets a lot of info on each change in TAPI-related stuff. Your applications should just respond properly.

Line Shutdown

At the very moment you do not need TAPI anymore, you should release unnecessary resources. You will learn about most of them later, but here I'll put in the simplest one. You have to shut down the opened line by the following call:

lReturn = ::lineShutdown(m_hLineApp);
As you see, this is the easiest stuff.

Where to go

In this tutorial, you have started to explore a wide area of TAPI programming. You will continue on this way in the few next articles. Neverthless, know that you can use the discussed features to obtain useful information that TAPI easily provides you.

About the Author

Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers' lives in the mobile jungles a little bit simpler.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel