www.pudn.com > ppc_Cellcore.rar > cedialer.c


// 
// Copyright (c) Microsoft Corporation.  All rights reserved. 
// 
// 
// Use of this source code is subject to the terms of the Microsoft end-user 
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT. 
// If you did not accept the terms of the EULA, you are not authorized to use 
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your 
// install media. 
// 
/*********************************************************************** 
 
    MODULE:  
    CeDialer.c 
 
    ABSTRACT:  
    This code sample shows how to initialize an application's use 
    of TAPI, open a line device, negotiate an API version to use, 
    translate an address into another format, place a call on an   
    opened line device, close an opened line device, and shut down  
    an application's use of the line abstraction of the API.  
 
    FUNCTIONS: 
    ConnectUsingProc - Processes messages sent to IDD_CONNECTUSING dialog. 
    CurrentLineClose - Closes the opened line device.  
    DialerDlgProc    - Processes messages sent to IDD_CEDIALER dialog. 
    DialingProc      - Processes messages sent to IDD_DIALING dialog. 
    GetLineInfo      - Get line information for selected line. 
    InitAddrCB       - Fills address list box on IDD_CONNECTUSING dialog. 
    InitApplication  - Initializes application. 
    InitializeTAPI   - Initializes the application's use of the Tapi.dll. 
    InitInstance     - Instance initialization. 
    InitLineCB       - Fills line list box on IDD_CONNECTUSING dialog. 
    lineCallbackFunc - Monitors line and call status.  
    MainWndProc      - Processes messages sent to the main window. 
    MakeCanonicalNum - Converts phone number to canonical address format. 
    MakePhoneCall    - Demonstrates the use of TAPI call functions. 
    WinMain          - Application entry point and initialization. 
           
***********************************************************************/ 
 
// Include the proper version of TAPI 
#define ERR_NONE              0 
#define TAPI_VERSION_1_0      0x00010003 
#define TAPI_VERSION_1_4      0x00010004 
#define TAPI_VERSION_2_0      0x00020000 
#define TAPI_CURRENT_VERSION  TAPI_VERSION_2_0 
 
#define REASONABLE_BUFFER_SIZE  512 
 
#include  
#include  
#include  
#include  
#include "resource.h"   
#include "CeDialer.h" 
 
HINSTANCE g_hInst    = NULL;    // hInstance of the application 
HWND g_hwndMain      = NULL;    // Handle to the main window 
HWND g_hwndDial      = NULL;    // Handle to the dialing window 
HWND g_hwndDialerDlg = NULL;    // Handle to the dialer dialog  
 
TCHAR g_szTitle[] = TEXT("CeDialer TAPI Sample"); 
// CeDialer application window name 
TCHAR g_szAppName[] = TEXT("CeDialer"); 
// Main window class name 
 
HLINEAPP g_hLineApp = NULL;     // Application's use handle for TAPI 
// (lineInitialize) 
HCALL g_hCall = NULL;           // Handle to the open line device on  
// which the call is to be originated  
// (lineMakeCall) 
LONG g_MakeCallRequestID = 0;   // Request identifier returned by  
// lineMakeCall 
LONG g_DropCallRequestID = 0;   // Request identifier returned by  
// lineDrop 
BOOL g_bCurrentLineAvail = TRUE;// Indicates line availability 
 
TCHAR g_szCurrentNum[TAPIMAXDESTADDRESSSIZE + 1];  
// Current phone number 
TCHAR g_szLastNum[TAPIMAXDESTADDRESSSIZE + 1];          
// Last called phone number 
 
 
DWORD g_dwNumDevs = 0;          // Number of line devices available 
DWORD g_dwCurrentLineID = -1;   // Current line device identifier 
DWORD g_dwCurrentLineAddr = -1; // Current line address 
 
LINEINFO g_CurrentLineInfo;     // Contains the current line information 
LINEINFO *g_lpLineInfo = NULL;  // Array that contains all the lines'  
// information 
 
#define ErrorBox(_s) MessageBox(g_hwndDialerDlg,_s, \ 
TEXT("CeDialer Message"),MB_OK) 
#define MENU_HEIGHT 26          // Height of menu bar at screen bottom 
 
 
// Purpose: Determine at runtime if the app is running on a smartphone device 
static BOOL IsSmartphone()  
{ 
    TCHAR tszPlatform[64]; 
     
    if (TRUE == SystemParametersInfo(SPI_GETPLATFORMTYPE, 
        sizeof(tszPlatform)/sizeof(*tszPlatform),tszPlatform,0)) 
    { 
        if (0 == _tcsicmp(TEXT("Smartphone"), tszPlatform))  
        { 
            return TRUE; 
        } 
    } 
    return FALSE;    
} 
 
/*********************************************************************** 
 
  FUNCTION:  
  DialerDlgProc 
   
    PURPOSE:  
    Processes messages sent to the IDD_CEDIALER dialog box. 
     
***********************************************************************/ 
BOOL CALLBACK DialerDlgProc( 
    HWND hwnd,  
    UINT uMsg,  
    WPARAM wParam,  
    LPARAM lParam 
    ) 
 
{ 
    switch (uMsg) 
    { 
 
    case WM_HOTKEY:  
        {  
            UINT uVirt; 
            //handle "Back" key 
            uVirt = HIWORD(lParam); 
 
            if (uVirt == VK_TBACK) 
            { 
                SendMessage(GetDlgItem (hwnd, IDC_PHONENUM), WM_CHAR, VK_BACK, 0); 
            } 
 
            break; 
        } 
    case WM_INITDIALOG: 
        { 
             
            SHINITDLGINFO shidi; 
            SHMENUBARINFO mbi; 
             
            g_hwndDialerDlg = hwnd; 
             
            // Create OK button in navigation bar and size dialog. 
            shidi.dwMask = SHIDIM_FLAGS; 
            shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN |  
                SHIDIF_SIZEDLGFULLSCREEN; 
            shidi.hDlg =  hwnd; 
            SHInitDialog(&shidi); 
             
             
            if (IsSmartphone() == TRUE) 
            { 
                 
                memset(&mbi, 0, sizeof(SHMENUBARINFO)); 
                mbi.cbSize     = sizeof(SHMENUBARINFO); 
                mbi.hwndParent = hwnd; 
                mbi.nToolBarId = IDR_SPMENU; 
                mbi.hInstRes   = g_hInst; 
                mbi.nBmpId     = 0; 
                mbi.cBmpImages = 0; 
                 
                if (SHCreateMenuBar(&mbi) == 0)  
                    return FALSE; 
            } 
             
            // ignore the phone key 
            SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TTALK, 
                MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, 
                SHMBOF_NODEFAULT | SHMBOF_NOTIFY)); 
             
            // reroute Back key to WM_HOTKEY handler 
            SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TBACK,  
                MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY,  
                SHMBOF_NODEFAULT | SHMBOF_NOTIFY)); 
 
             
             
            // Limit text in phone number field to TAPIMAXDESTADDRESSSIZE. 
            SendDlgItemMessage (hwnd, IDC_PHONENUM, CB_LIMITTEXT,  
                (WPARAM)TAPIMAXDESTADDRESSSIZE, 0); 
             
            // Initialize the application's use of Tapi.dll. If the function 
            // fails, terminate the application. 
            if (InitializeTAPI ()) 
            { 
                ErrorBox (TEXT("Intilization of Tapi.dll failed.")); 
                 
                if (g_hLineApp) 
                    lineShutdown (g_hLineApp); 
                 
                DestroyWindow (hwnd); 
            } 
             
            return TRUE; 
        } 
         
         
         
    case WM_COMMAND: 
        { 
            switch (LOWORD(wParam)) 
            { 
                 
                 
            case IDM_QUIT: 
                EndDialog(hwnd, IDOK); 
                break; 
            case IDM_SELECTLINE: 
            case IDC_SELECTLINE: 
                 
                DialogBox (g_hInst,  
                    MAKEINTRESOURCE(IDD_CONNECTUSING),  
                    hwnd,  
                    (DLGPROC) ConnectUsingProc); 
                 
                return TRUE; 
                 
            case IDM_DIAL: 
            case IDC_DIAL: 
                { 
                    // Check if there is a number entered. 
                    if (SendDlgItemMessage (hwnd,  
                        IDC_PHONENUM,  
                        WM_GETTEXTLENGTH, 0, 0) > 0) 
                    { 
                        // Set the current line if it is not already set.   
                        if (g_dwCurrentLineID == -1) 
                        { 
                            DialogBox (g_hInst,  
                                MAKEINTRESOURCE(IDD_CONNECTUSING),  
                                hwnd,  
                                (DLGPROC) ConnectUsingProc); 
                        } 
                         
                        // Get the number to be dialed. 
                        GetDlgItemText (hwnd,  
                            IDC_PHONENUM,  
                            (LPTSTR) g_szCurrentNum,  
                            TAPIMAXDESTADDRESSSIZE); 
                         
                        // Convert the phone number into a canonical format. 
                        if (!MakeCanonicalNum (g_szCurrentNum)) 
                            return TRUE; 
                         
                        // Make the call. 
                        MakePhoneCall (g_szCurrentNum); 
                         
                        // Set the focus on the phone number Edit control. 
                        SetFocus (GetDlgItem (hwnd, IDC_PHONENUM)); 
                         
                        // Select the phone number once it is dialed. 
                        SendDlgItemMessage (hwnd, IDC_PHONENUM, EM_SETSEL, 0, -1); 
                         
                        // Save the phone number in the g_szLastNum string. 
                        lstrcpy (g_szLastNum, g_szCurrentNum); 
                    } 
                    return TRUE; 
                } 
                 
            case IDC_BUTTON1: 
            case IDC_BUTTON2: 
            case IDC_BUTTON3: 
            case IDC_BUTTON4: 
            case IDC_BUTTON5: 
            case IDC_BUTTON6: 
            case IDC_BUTTON7: 
            case IDC_BUTTON8: 
            case IDC_BUTTON9: 
            case IDC_BUTTON0: 
            case IDC_BUTTONSTAR: 
            case IDC_BUTTONPOUND: 
                { 
                    int iNumOfDigits = 0; 
                    TCHAR *lpszBuffer; 
                    static const TCHAR digits[] = {'1', '2', '3', '4',  
                        '5', '6', '7', '8',  
                        '9', '0', '*', '#'}; 
                     
                    lpszBuffer = (TCHAR *)LocalAlloc (LPTR,  
                        (TAPIMAXDESTADDRESSSIZE + 1) * sizeof(TCHAR)); 
                     
                    // Clear the current selection. 
                    SendDlgItemMessage (hwnd, IDC_PHONENUM, WM_CLEAR, 0, 0); 
                     
                    iNumOfDigits = SendDlgItemMessage ( 
                        hwnd,  
                        IDC_PHONENUM,  
                        WM_GETTEXT, 
                        (WPARAM)TAPIMAXDESTADDRESSSIZE + 1, 
                        (LPARAM)lpszBuffer); 
                     
                    if (iNumOfDigits < TAPIMAXDESTADDRESSSIZE) 
                    { 
                        lpszBuffer[iNumOfDigits] =  
                            digits[LOWORD(wParam) - IDC_BUTTON1]; 
                         
                        SendDlgItemMessage (hwnd, IDC_PHONENUM, WM_SETTEXT, 0, 
                            (LPARAM)lpszBuffer); 
                    } 
                     
                    LocalFree (lpszBuffer); 
                    return TRUE; 
                } 
                 
            case IDOK: 
                 
                if (g_lpLineInfo) 
                    LocalFree (g_lpLineInfo); 
                 
                lineShutdown (g_hLineApp); 
                 
                DestroyWindow (hwnd); 
                PostQuitMessage (0); 
                return TRUE; 
      }  
      break;  
    }  
     
    //case WM_DESTROY: 
    //  PostQuitMessage (0); 
    //  return TRUE; 
         
  } 
   
  return FALSE; 
} 
 
/*********************************************************************** 
 
FUNCTION:  
MainWndProc 
 
PURPOSE:  
Processes messages sent to the main window. 
     
***********************************************************************/ 
BOOL CALLBACK MainWndProc( 
    HWND hwnd,  
    UINT uMsg,  
    WPARAM wParam,  
    LPARAM lParam 
    ) 
{ 
    switch (uMsg) 
    { 
    case WM_CREATE: 
         
        // Create dialer dialog box. 
        DialogBox (g_hInst,  
            MAKEINTRESOURCE(IDD_CEDIALER),  
            hwnd,  
            (DLGPROC) DialerDlgProc); 
        break; 
         
    case WM_DESTROY: 
        DestroyWindow(g_hwndDialerDlg); 
        PostQuitMessage (0); 
        return TRUE; 
         
    default: 
        return DefWindowProc (hwnd, uMsg, wParam, lParam); 
    } 
     
    return FALSE; 
} 
 
 
/*********************************************************************** 
       
FUNCTION:  
InitInstance 
 
PURPOSE:  
Instance initialization. 
           
***********************************************************************/       
BOOL InitInstance( 
    HINSTANCE hInstance, 
    int nCmdShow 
    ) 
{ 
     
    g_hInst = hInstance; 
    if (IsSmartphone()) 
    { 
        DialogBox (g_hInst,  
            MAKEINTRESOURCE(IDD_CEDIALER_SP),  
            NULL,  
            (DLGPROC) DialerDlgProc); 
         
    } 
    else 
    { 
        DialogBox (g_hInst,  
            MAKEINTRESOURCE(IDD_CEDIALER),  
            NULL,  
            (DLGPROC) DialerDlgProc); 
    } 
     
     
    return TRUE; 
} 
       
/*********************************************************************** 
       
        FUNCTION:  
        InitApplication 
         
          PURPOSE:  
          Initialize application. 
           
***********************************************************************/ 
 BOOL InitApplication( 
     HINSTANCE hInstance 
     ) 
{ 
      
     WNDCLASS wc; 
     BOOL f; 
      
     // Register application main window  
     wc.style         = CS_HREDRAW | CS_VREDRAW; 
     wc.lpfnWndProc   = (WNDPROC) MainWndProc;         
     wc.cbClsExtra    = 0; 
     wc.cbWndExtra    = 0; 
     wc.hIcon        = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_CEDIALER)); 
     wc.hInstance     = hInstance; 
     wc.hCursor       = NULL; 
     wc.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH ); 
     wc.lpszMenuName  = NULL; 
     wc.lpszClassName = g_szAppName; 
      
     f = (RegisterClass(&wc)); 
      
     return f; 
      
 } 
       
/*********************************************************************** 
       
FUNCTION:  
WinMain 
 
PURPOSE:  
Called by the system as the initial entry point for this Windows  
CE-based application. 
           
***********************************************************************/ 
int WINAPI WinMain( 
    HINSTANCE hInstance,  
    HINSTANCE hPrevInstance,  
    LPTSTR lpCmdLine,  
    int nCmdShow 
    ) 
{ 
     
    HWND hwndCeDialer; 
     
    // If CeDialer.exe is running, then give the focus to the window. 
    hwndCeDialer = FindWindow (g_szAppName, g_szTitle);  
    if (hwndCeDialer)  
    { 
        SetForegroundWindow (hwndCeDialer);     
        return 0; 
    } 
     
    
     
    if ( !InitInstance( hInstance,  nCmdShow )  ) 
    { 
        return (FALSE); 
    }  
     
    return 0;      
} 
       
       
/*********************************************************************** 
       
FUNCTION:  
lineCallbackFunc 
 
PURPOSE:  
This is a callback function invoked to determine status and events on 
the line device, addresses, or calls.  
           
***********************************************************************/ 
VOID CALLBACK lineCallbackFunc ( 
    DWORD hDevice,  
    DWORD dwMsg,  
    DWORD dwCallbackInstance, 
    DWORD dwParam1,  
    DWORD dwParam2,  
    DWORD dwParam3 
    ) 
{ 
           
    BOOL bCloseLine = FALSE; 
    LPTSTR lpszStatus; 
    lpszStatus = TEXT(" "); 
           
    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; 
                      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;    
       
    case LINE_LINEDEVSTATE: 
         
        switch (dwParam1) 
        { 
        case LINEDEVSTATE_RINGING: 
            lpszStatus = TEXT("Ringing"); 
            break; 
             
        case LINEDEVSTATE_OUTOFSERVICE: 
            lpszStatus = TEXT("The line selected is out of service."); 
            if (g_hwndDial) 
                SendDlgItemMessage(g_hwndDial, IDC_STATUSMESSAGE,  
                WM_SETTEXT,0,(LPARAM)lpszStatus); 
            CurrentLineClose (); 
            if (g_hwndDial) 
                SendMessage (g_hwndDial, WM_COMMAND, MAKEWPARAM(IDOK,0), 0); 
            break; 
             
        case LINEDEVSTATE_DISCONNECTED: 
            lpszStatus = TEXT("The line selected is disconnected."); 
            if (g_hwndDial) 
                SendDlgItemMessage(g_hwndDial, IDC_STATUSMESSAGE,  
                WM_SETTEXT,0,(LPARAM)lpszStatus); 
            CurrentLineClose (); 
            if (g_hwndDial) 
                SendMessage (g_hwndDial, WM_COMMAND, MAKEWPARAM(IDOK,0), 0); 
            break; 
             
        case LINEDEVSTATE_MAINTENANCE: 
            lpszStatus = TEXT("The line selected is out for maintenance."); 
            if (g_hwndDial) 
                SendDlgItemMessage(g_hwndDial, IDC_STATUSMESSAGE,  
                WM_SETTEXT,0,(LPARAM)lpszStatus); 
            CurrentLineClose (); 
            if (g_hwndDial) 
                SendMessage (g_hwndDial, WM_COMMAND, MAKEWPARAM(IDOK,0), 0); 
            break; 
             
        case LINEDEVSTATE_TRANSLATECHANGE: 
            break; 
             
        case LINEDEVSTATE_REMOVED: 
            ErrorBox ( 
                TEXT("The Line device has been removed; no action taken.")); 
            break; 
             
        case LINEDEVSTATE_REINIT: 
            { 
                // This usually means that a service provider has changed in  
                // such a way that requires TAPI to REINIT. Note that there  
                // are both soft REINITs and hard REINITs. Soft REINITs do not 
                // require a full shutdown but an informational change that 
                // historically required a REINIT to force the application to 
                // deal with.  TAPI API Version 1.3 applications require a  
                // full REINIT for both hard and soft REINITs. 
                 
                switch(dwParam2) 
                { 
                    // This is the hard REINIT. TAPI is waiting for everyone to 
                    // shut down. Our response is to immediately shut down any  
                    // calls, shut down our use of TAPI and notify the user. 
                case 0: 
                    if (MessageBox ( 
                        g_hwndMain,  
                        TEXT("Tapi line configuration has been changed. ") 
                        TEXT("You have to shut down CeDialer to\n") 
                        TEXT("re-initialize the use of tapi.dll. Do ") 
                        TEXT("you want to shut down CeDialer now?"), 
                        TEXT("Warning"),  
                        MB_YESNO) == IDYES) 
                    { 
                        lineShutdown (g_hLineApp); 
                        DestroyWindow (g_hwndMain); 
                    } 
                     
                    break; 
                     
                case LINE_CREATE: 
                    lineCallbackFunc (hDevice, dwParam2, dwCallbackInstance,  
                        dwParam3, 0, 0); 
                    break; 
                     
                case LINE_LINEDEVSTATE: 
                    lineCallbackFunc (hDevice, dwParam2, dwCallbackInstance,  
                        dwParam3, 0, 0); 
                    break; 
                     
                    // There might be other reasons to send a soft REINIT. 
                    // No need to shut down for these reasons. 
                default: 
                    break; 
                } 
            } 
             
        default: 
            break; 
        } 
        break; 
         
        case LINE_REPLY: 
             
            // Reply from the lineMakeCall function. 
            if ((LONG)dwParam1 == g_MakeCallRequestID) 
            { 
                // If an error occurred on making the call. 
                if (dwParam2 != ERR_NONE) 
                { 
                    lpszStatus = TEXT("Closing line"); 
                    if (dwParam2 == LINEERR_CALLUNAVAIL) 
                        lpszStatus = TEXT("The line is not available."); 
                     
                    if (g_hwndDial) 
                        SendDlgItemMessage(g_hwndDial, IDC_STATUSMESSAGE,  
                        WM_SETTEXT, 0,(LPARAM)lpszStatus); 
                    CurrentLineClose (); 
                     
                    if (g_hwndDial) 
                        SendMessage (g_hwndDial, WM_COMMAND, MAKEWPARAM(IDOK,0), 0); 
                } 
            } 
             
            break; 
             
        case LINE_CREATE: 
             
            // dwParam1 is the device identifier of the new line.  
            if (dwParam1 >= g_dwNumDevs)  
            { 
                DWORD dwLineID; 
                LINEINFO *lpLineInfo; 
                 
                g_dwNumDevs = dwParam1 + 1; 
                 
                // Allocate a buffer for storing LINEINFO for all the lines. 
                if (!(lpLineInfo = (LPLINEINFO) LocalAlloc ( 
                    LPTR,  
                    sizeof (LINEINFO) * g_dwNumDevs))) 
                { 
                    break; 
                } 
                 
                // Assume we just add a new line, the lines are sequential and 
                // the new line is the last one. 
                for (dwLineID = 0; dwLineID < dwParam1; ++dwLineID) 
                { 
                    lpLineInfo[dwLineID] = g_lpLineInfo[dwLineID]; 
                } 
                 
                // Get the new line information. 
                GetLineInfo (dwParam1, &lpLineInfo[dwParam1]); 
                 
                LocalFree (g_lpLineInfo); 
                g_lpLineInfo = lpLineInfo;  
            } 
            break; 
             
        case LINE_CLOSE: 
            if (g_CurrentLineInfo.hLine == (HLINE) hDevice) 
            { 
                lpszStatus = TEXT("Closing line"); 
                if (g_hwndDial) 
                    SendDlgItemMessage(g_hwndDial, IDC_STATUSMESSAGE,  
                    WM_SETTEXT, 0,(LPARAM)lpszStatus); 
                CurrentLineClose (); 
                 
                if (g_hwndDial) 
                    SendMessage (g_hwndDial, WM_COMMAND, MAKEWPARAM(IDOK,0), 0); 
            } 
            break; 
             
        case LINE_ADDRESSSTATE: 
        case LINE_CALLINFO: 
        case LINE_DEVSPECIFIC: 
        case LINE_DEVSPECIFICFEATURE: 
        case LINE_GATHERDIGITS: 
        case LINE_GENERATE: 
        case LINE_MONITORDIGITS: 
        case LINE_MONITORMEDIA: 
        case LINE_MONITORTONE: 
        case LINE_REMOVE: 
        case LINE_REQUEST: 
        default: 
            break; 
  } 
   
} 
 
/*********************************************************************** 
 
FUNCTION:  
DialingProc 
 
PURPOSE:  
Processes messages sent to the IDD_DIALING dialog box window.  
     
***********************************************************************/ 
BOOL CALLBACK DialingProc( 
    HWND hwnd,  
    UINT uMsg,  
    WPARAM wParam,  
    LPARAM lParam 
    ) 
{ 
    SHINITDLGINFO shidi; 
     
    switch (uMsg) 
    { 
    case WM_INITDIALOG: 
         
        // Set the global handle to the window. 
        g_hwndDial = hwnd;  
         
        // Create OK button in navigation bar. 
        shidi.dwMask  = SHIDIM_FLAGS; 
        shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN |  
            SHIDIF_SIZEDLGFULLSCREEN; 
        shidi.hDlg =  hwnd; 
        SHInitDialog(&shidi); 
         
        // Display the current dialing phone number. 
        SetDlgItemText (hwnd, IDC_PHONENUM, g_szCurrentNum);  
         
        break; 
         
    case WM_COMMAND: 
         
        switch (LOWORD(wParam)) 
        { 
            // Drop the line, close the line, and then close the dialog box. 
            // This is the case when the Hangup button gets pushed or 
            // when application sends a message to close the dialog box. 
        case IDCANCEL:         
        case IDOK: 
             
            // Close the current phone line. 
            CurrentLineClose (); 
             
            // Close the dialing dialog box. 
            EndDialog (g_hwndDial, TRUE); 
             
            // Invalidate the dialing dialog box window handle. 
            g_hwndDial = NULL; 
             
            return TRUE; 
        } 
        break; 
    } 
    return FALSE; 
} 
       
/*********************************************************************** 
       
FUNCTION:  
CurrentLineClose 
 
PURPOSE:  
This function closes the opened line device.   
           
***********************************************************************/ 
VOID CurrentLineClose () 
{ 
    Sleep(2000); // Time delay to provide message display. 
     
    // If lineMakeCall succeeded, then drop the call. 
    if (g_hCall) 
    { 
        g_DropCallRequestID = lineDrop (g_hCall, NULL, 0); 
        Sleep(5000); 
        lineDeallocateCall (g_hCall); // Deallocate call handle. 
    } 
     
    // Close the current line. 
    if (g_CurrentLineInfo.hLine) 
        lineClose (g_CurrentLineInfo.hLine); 
     
    // Reinitialize the variables. 
    g_CurrentLineInfo.hLine = NULL; 
    g_bCurrentLineAvail = TRUE; 
    g_hCall = NULL; 
} 
       
       
/*********************************************************************** 
       
FUNCTION:  
GetLineInfo  
 
PURPOSE: 
Get line information for selected line. 
     
***********************************************************************/ 
DWORD GetLineInfo( 
    DWORD dwLineID,  
    LPLINEINFO lpLineInfo 
    ) 
{ 
    DWORD dwSize; 
    DWORD     dwReturn; 
    LPTSTR lpszLineName = NULL;  
    LPLINEDEVCAPS lpLineDevCaps = NULL; 
     
    // Negotiate the API version number. If it fails, return to dwReturn. 
    if (dwReturn = lineNegotiateAPIVersion ( 
        g_hLineApp,                   // TAPI registration handle 
        dwLineID,                     // Line device to be queried 
        TAPI_VERSION_1_0,             // Least recent API version  
        TAPI_CURRENT_VERSION,         // Most recent API version  
        &(lpLineInfo->dwAPIVersion),  // Negotiated API version  
        NULL))                        // Must be NULL; the provider- 
        // specific extension is not  
        // supported on Windows CE 
    { 
        goto exit; 
    } 
     
    dwSize = sizeof (LINEDEVCAPS); 
     
    // Allocate enough memory for lpLineDevCaps. 
    do 
    { 
        if (!(lpLineDevCaps = (LPLINEDEVCAPS) LocalAlloc (LPTR, dwSize))) 
        { 
            dwReturn = LINEERR_NOMEM; 
            goto exit; 
        } 
         
        lpLineDevCaps->dwTotalSize = dwSize; 
         
        if (dwReturn = lineGetDevCaps (g_hLineApp, 
            dwLineID, 
            lpLineInfo->dwAPIVersion, 
            0, 
            lpLineDevCaps)) 
        { 
            goto exit; 
        } 
         
        // Stop if the allocated memory is equal to or greater than the  
        // needed memory. 
        if (lpLineDevCaps->dwNeededSize <= lpLineDevCaps->dwTotalSize) 
            break;   
         
        dwSize = lpLineDevCaps->dwNeededSize; 
        LocalFree (lpLineDevCaps); 
        lpLineDevCaps = NULL; 
         
    } while (TRUE); 
     
    // Store the line information in *lpLineInfo. 
    lpLineInfo->dwPermanentLineID = lpLineDevCaps->dwPermanentLineID; 
    lpLineInfo->dwNumOfAddress = lpLineDevCaps->dwNumAddresses; 
    lpLineInfo->bVoiceLine =  
        (lpLineDevCaps->dwMediaModes & LINEMEDIAMODE_INTERACTIVEVOICE); 
     
    // Allocate memory for lpszLineName. 
    if (!(lpszLineName = (LPTSTR) LocalAlloc (LPTR, REASONABLE_BUFFER_SIZE))) 
    { 
        dwReturn = LINEERR_NOMEM; 
        goto exit; 
    }   
     
    // Store the line name in *lpszLineName. 
    if (lpLineDevCaps->dwLineNameSize > 0) 
    { 
        StringCbCopy( 
            lpszLineName,  
            REASONABLE_BUFFER_SIZE, 
            (LPTSTR)((LPSTR)lpLineDevCaps + lpLineDevCaps->dwLineNameOffset)); 
    } 
    else  
    { 
        _stprintf (lpszLineName, TEXT("Line %d"), dwLineID); 
    } 
     
    // Copy lpszLineName to lpLineInfo->lpszLineName. 
    lstrcpy (lpLineInfo->szLineName, lpszLineName); 
     
    dwReturn = ERR_NONE; 
     
exit: 
     
    if (lpLineDevCaps) 
        LocalFree (lpLineDevCaps); 
     
    if (lpszLineName) 
        LocalFree (lpszLineName); 
     
    return dwReturn;  
} 
       
/*********************************************************************** 
       
FUNCTION:  
InitializeTAPI  
 
PURPOSE:   
Initialize the application's use of Tapi.dll. 
           
***********************************************************************/ 
DWORD InitializeTAPI () 
{ 
    DWORD dwLineID, 
        dwReturn, 
        dwTimeCount = GetTickCount (); 
     
    TCHAR szWarning[] = TEXT("Cannot initialize tapi.dll.")  
        TEXT("\nQuit all other telephony") 
        TEXT("\nprograms, and try again."); 
     
    // Initialize the application's use of Tapi.dll. Keep trying until the 
    // user cancels or stops getting LINEERR_REINIT. 
    while ( (dwReturn = lineInitialize (&g_hLineApp,  
        g_hInst,  
        (LINECALLBACK) lineCallbackFunc,  
        g_szAppName,  
        &g_dwNumDevs)) == LINEERR_REINIT) 
    { 
        // Bring up the message box if 5 seconds have passed. 
        if (GetTickCount () > 5000 + dwTimeCount) 
        { 
            if (MessageBox (g_hwndMain, szWarning, TEXT("Warning"),  
                MB_OKCANCEL) == IDOK) 
                break; 
             
            // Reset the time counter. 
            dwTimeCount = GetTickCount ();       
        }   
    } 
     
    // If function "lineInitialize" fails, then return. 
    if (dwReturn) 
        return dwReturn; 
     
    // If there is no device, then return. 
    if (g_dwNumDevs == 0) 
    { 
        ErrorBox (TEXT("There are no line devices available.")); 
        return LINEERR_NODEVICE; 
    } 
     
    // Allocate buffer for storing LINEINFO for all the available lines. 
    if (! (g_lpLineInfo = (LPLINEINFO) LocalAlloc ( 
        LPTR,  
        sizeof (LINEINFO) * g_dwNumDevs))) 
    { 
        return LINEERR_NOMEM; 
    } 
     
    // Fill lpLineInfo[] for every line. 
    for (dwLineID = 0; dwLineID < g_dwNumDevs; ++dwLineID) 
    {   
        GetLineInfo (dwLineID, &g_lpLineInfo [dwLineID]); 
    } 
     
    return ERR_NONE; 
} 
 
             
/*********************************************************************** 
             
FUNCTION:  
MakePhoneCall  
 
PURPOSE:    
Demonstrates the use of lineOpen, lineTranslateAddress, lineMakeCall. 
                 
***********************************************************************/ 
VOID MakePhoneCall (LPCTSTR lpszPhoneNum) 
{ 
    DWORD dwReturn, 
    dwSizeOfTransOut = sizeof (LINETRANSLATEOUTPUT), 
    dwSizeOfCallParams = sizeof (LINECALLPARAMS); 
     
    LPLINECALLPARAMS lpCallParams = NULL; 
    LPLINETRANSLATEOUTPUT lpTransOutput = NULL; 
     
    TCHAR szDialablePhoneNum[TAPIMAXDESTADDRESSSIZE + 1] = {'\0'}; 
    int err = 0; 
     
    // Initialize g_MakeCallRequestID. 
    g_MakeCallRequestID = 0; 
     
    // Open the current line. 
    if (dwReturn = lineOpen ( 
        g_hLineApp,                 // Usage handle for TAPI 
        g_dwCurrentLineID,          // Cannot use the LINEMAPPER value 
        &g_CurrentLineInfo.hLine,   // Line handle 
        g_CurrentLineInfo.dwAPIVersion,  
        // API version number 
        0,                          // Must set to zero for Windows CE 
        0,                          // No data passed back  
        LINECALLPRIVILEGE_NONE,     // Can only make an outgoing call 
        0,                          // Media mode  
        NULL))                      // Must set to NULL for Windows CE 
    { 
        goto exit; 
    } 
     
    // Call translate address before dialing. 
    do 
    { 
        // Allocate memory for lpTransOutput. 
        if (!(lpTransOutput = (LPLINETRANSLATEOUTPUT) LocalAlloc ( 
            LPTR,   
            dwSizeOfTransOut))) 
        { 
            goto exit; 
        } 
         
        lpTransOutput->dwTotalSize = dwSizeOfTransOut; 
         
        if (dwReturn = lineTranslateAddress ( 
            g_hLineApp,               // Usage handle for TAPI 
            g_dwCurrentLineID,        // Line device identifier  
            g_CurrentLineInfo.dwAPIVersion,  
            // Highest TAPI version supported  
            lpszPhoneNum,             // Address to be translated 
            0,                        // Must be 0 for Windows CE 
            0,                        // No associated operations  
            lpTransOutput))           // Result of the address translation 
        { 
            goto exit; 
        } 
         
        if (lpTransOutput->dwNeededSize <= lpTransOutput->dwTotalSize) 
            break;  
        else 
        { 
            dwSizeOfTransOut = lpTransOutput->dwNeededSize; 
            LocalFree (lpTransOutput); 
            lpTransOutput = NULL; 
        } 
         
    } while (TRUE); 
     
    dwSizeOfCallParams += lpTransOutput->dwDisplayableStringSize; 
     
    if (!(lpCallParams = (LPLINECALLPARAMS) LocalAlloc ( 
        LPTR,  
        dwSizeOfCallParams))) 
    { 
        goto exit; 
    } 
 
    ZeroMemory(lpCallParams, dwSizeOfCallParams); 
     
    // Set the call parameters. 
    lpCallParams->dwTotalSize      = dwSizeOfCallParams; 
    lpCallParams->dwBearerMode     = LINEBEARERMODE_VOICE; 
    lpCallParams->dwMediaMode      = LINEMEDIAMODE_DATAMODEM;  
    lpCallParams->dwCallParamFlags = LINECALLPARAMFLAGS_IDLE; 
    lpCallParams->dwAddressMode    = LINEADDRESSMODE_ADDRESSID; 
    lpCallParams->dwAddressID      = g_dwCurrentLineAddr; 
    lpCallParams->dwDisplayableAddressSize =  
        lpTransOutput->dwDisplayableStringSize; 
    lpCallParams->dwDisplayableAddressOffset = sizeof (LINECALLPARAMS); 
     
    // Save the translated phone number for dialing. 
    lstrcpy (szDialablePhoneNum,  
        (LPTSTR) ((LPBYTE) lpTransOutput +  
        lpTransOutput->dwDialableStringOffset)); 
    memcpy((LPBYTE) lpCallParams + lpCallParams->dwDisplayableAddressOffset, 
        (LPBYTE) lpTransOutput + lpTransOutput->dwDisplayableStringOffset, 
        lpTransOutput->dwDisplayableStringSize); 
 
    // Make the phone call. lpCallParams should be NULL if the default  
    // call setup parameters are requested. 
    g_MakeCallRequestID = lineMakeCall (g_CurrentLineInfo.hLine,             
        &g_hCall,          
        szDialablePhoneNum,  
        0,  
        lpCallParams);    
     
     
    if (g_MakeCallRequestID > 0)  
    { 
        g_bCurrentLineAvail = FALSE; 
         
        DialogBox (g_hInst,  
            MAKEINTRESOURCE(IDD_DIALING),  
            g_hwndDialerDlg,  
            (DLGPROC) DialingProc); 
    } 
    else  
    { 
        ErrorBox (TEXT("Failed in making the call, ") 
            TEXT("\nfunction lineMakeCall failed.")); 
        CurrentLineClose (); 
    } 
     
exit : 
     
    if (lpCallParams) 
        LocalFree (lpCallParams); 
     
    if (lpTransOutput) 
        LocalFree (lpTransOutput); 
     
    // If the make call did not succeed but the line was opened,  
    // then close it. 
    if ((g_MakeCallRequestID <= 0) && (g_CurrentLineInfo.hLine)) 
        CurrentLineClose (); 
     
    return; 
} 
 
/*********************************************************************** 
 
  FUNCTION:  
  ConnectUsingProc  
   
    PURPOSE:    
    Processes messages sent to IDD_CONNECTUSING dialog box. 
 
***********************************************************************/ 
BOOL CALLBACK ConnectUsingProc( 
    HWND hwnd,  
    UINT uMsg,  
    WPARAM wParam,  
    LPARAM lParam 
    ) 
{ 
    SHINITDLGINFO shidi; 
    SHMENUBARINFO mbi; 
     
    switch (uMsg) 
    { 
    case WM_INITDIALOG: 
        { 
            // Create OK button in navigation bar and size dialog. 
            shidi.dwMask = SHIDIM_FLAGS; 
            shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIZEDLG; 
            shidi.hDlg =  hwnd; 
            SHInitDialog(&shidi); 
             
             
            if (IsSmartphone()) 
            { 
                 
                memset(&mbi, 0, sizeof(SHMENUBARINFO)); 
                mbi.cbSize     = sizeof(SHMENUBARINFO); 
                mbi.hwndParent = hwnd; 
                mbi.nToolBarId = IDR_OKMENU; 
                mbi.hInstRes   = g_hInst; 
                mbi.nBmpId     = 0; 
                mbi.cBmpImages = 0; 
                 
                if (SHCreateMenuBar(&mbi) == 0)  
                    return FALSE; 
            } 
             
            // Get the list of lines into the line list box. 
            InitLineCB (GetDlgItem (hwnd, IDC_LISTLINES),  
                g_dwCurrentLineID,  
                g_dwNumDevs); 
             
            // Get the list of addresses into the address list box. 
            InitAddrCB (GetDlgItem (hwnd, IDC_LISTLINES), 
                GetDlgItem (hwnd, IDC_LISTADDRESSES), 
                g_dwCurrentLineID,  
                g_dwCurrentLineAddr); 
             
            return TRUE; 
        } 
         
    case WM_COMMAND: 
        { 
            switch (LOWORD(wParam)) 
            { 
            case IDC_LISTLINES: 
                 
                if (HIWORD(wParam) == CBN_SELENDOK) 
                { 
                    // Update the address box. 
                    InitAddrCB (GetDlgItem (hwnd, IDC_LISTLINES), 
                        GetDlgItem (hwnd, IDC_LISTADDRESSES), 
                        g_dwCurrentLineID,  
                        g_dwCurrentLineAddr); 
                } 
                break; 
                 
            case IDM_OK: 
            case IDOK: 
                { 
                    long lIndex;  
                     
                    lIndex = SendDlgItemMessage (hwnd,  
                        IDC_LISTLINES,  
                        CB_GETCURSEL, 0, 0); 
                     
                    // Update the current line identifier. 
                    g_dwCurrentLineID = SendDlgItemMessage ( 
                        hwnd,  
                        IDC_LISTLINES,  
                        CB_GETITEMDATA,  
                        (WPARAM) lIndex, 0); 
                     
                    lIndex = SendDlgItemMessage (hwnd,  
                        IDC_LISTADDRESSES,  
                        CB_GETCURSEL, 0, 0); 
                     
                    // Update the current address for the current line. 
                    g_dwCurrentLineAddr = SendDlgItemMessage ( 
                        hwnd,  
                        IDC_LISTADDRESSES,  
                        CB_GETITEMDATA, 
                        (WPARAM) lIndex, 0); 
                     
                    // Assign the g_CurrentLineInfo. 
                    g_CurrentLineInfo = g_lpLineInfo [g_dwCurrentLineID];   
                } 
                 
                EndDialog (hwnd, FALSE); 
                return TRUE; 
            } 
        } 
    } 
    return FALSE; 
} 
       
           
/*********************************************************************** 
       
FUNCTION:  
InitLineCB   
 
PURPOSE:    
Fills line list box on the IDD_CONNECTUSING dialog box. 
           
***********************************************************************/ 
BOOL InitLineCB( 
    HWND hwndLineCB,  
    DWORD dwCurrentLine,  
    DWORD dwNumOfDev 
    ) 
{ 
    DWORD dwItem, 
        dwLineID, 
        dwCurrentItem = (DWORD)-1; 
     
    // Empty the line combo box. 
    SendMessage (hwndLineCB, CB_RESETCONTENT, 0, 0);  
     
    // Add the device name strings. 
    for (dwLineID = 0; dwLineID < dwNumOfDev; ++dwLineID) 
    { 
        // Add the line name string to the list box of the line combo box. 
        dwItem = SendMessage (hwndLineCB, 
            CB_ADDSTRING, 
            0, 
            (LPARAM)(g_lpLineInfo[dwLineID].szLineName)); 
         
        if (dwItem == CB_ERR || dwItem == CB_ERRSPACE) 
            return FALSE;  
         
        // Set the dwLineID associated with the dwItem item. 
        SendMessage (hwndLineCB,  
            CB_SETITEMDATA,  
            (WPARAM)dwItem,  
            (LPARAM)dwLineID); 
         
        if (dwLineID == dwCurrentLine) 
            dwCurrentItem = dwItem; 
        else  
        {   
            // If the item we are putting is before the current item, we  
            // must increment dwCurrentItem to reflect that an item is  
            // being placed before it, due to sorting. 
            if (dwCurrentItem != -1 && dwItem <= dwCurrentItem) 
                ++dwCurrentItem; 
        } 
    } 
     
    if (dwCurrentItem == (DWORD)-1) 
        dwCurrentItem = 0; 
     
    // Select the dwCurrentItem item in the list box of the line   
    // combo box. 
    if (SendMessage (hwndLineCB, CB_GETCOUNT, 0, 0) != 0) 
    { 
        SendMessage (hwndLineCB, CB_SETCURSEL, (WPARAM)dwCurrentItem, 0); 
        return TRUE; 
    } 
     
    return FALSE; 
} 
             
             
/*********************************************************************** 
             
FUNCTION:  
InitAddrCB    
 
PURPOSE:     
Fills address list box on the IDD_CONNECTUSING dialog box. 
                 
***********************************************************************/ 
BOOL InitAddrCB( 
    HWND hwndLineCB,  
    HWND hwndAddrCB,  
    DWORD dwCurrentLine,  
    DWORD dwCurrentAddr 
    ) 
{        
    DWORD dwAddr,  
        dwItem,  
        dwCurrentItem = (DWORD)-1, 
        dwLineCBCurrent; 
     
    TCHAR szAddrName[512]; 
     
    if (SendMessage (hwndLineCB, CB_GETCOUNT, 0, 0) == 0) 
        return FALSE; 
     
    // Empty the address list box. 
    SendMessage (hwndAddrCB, CB_RESETCONTENT, 0, 0);  
     
    // Select the current entry in the line box. 
    dwLineCBCurrent = SendMessage ( 
        hwndLineCB, 
        CB_GETITEMDATA, 
        SendMessage (hwndLineCB, CB_GETCURSEL, 0, 0),  
        0); 
     
    // Get all the addresses for this line. 
    for (dwAddr = 0;  
    dwAddr < g_lpLineInfo [dwLineCBCurrent].dwNumOfAddress; ++dwAddr) 
    { 
        wsprintf (szAddrName, TEXT("Address %d"), dwAddr); 
         
        // Add the address name string to the list box of the address  
        // combo box. 
        dwItem = SendMessage (hwndAddrCB, CB_ADDSTRING, 0,  
            (LPARAM)szAddrName); 
         
        if (dwItem == CB_ERR || dwItem == CB_ERRSPACE) 
            return FALSE;  
         
        // Set the dwAddr associated with the dwItem item. 
        SendMessage (hwndAddrCB, CB_SETITEMDATA, (WPARAM)dwItem,  
            (LPARAM)dwAddr); 
         
        if (dwLineCBCurrent == dwCurrentLine) 
        { 
            if (dwAddr == dwCurrentAddr) 
                dwCurrentItem = dwItem; 
            else  
            { 
                // If the item we are putting is before the current item, we 
                // must increment dwItemCur to reflect that an item is being 
                // placed before it, due to sorting. 
                if (dwCurrentItem != -1 && dwItem <= dwCurrentItem) 
                    ++dwCurrentItem;  
            } 
        } 
    } 
     
    if (dwLineCBCurrent != dwCurrentLine || dwCurrentItem == (DWORD)-1) 
        dwCurrentItem = 0; 
     
    // Select the dwCurrentItem item in the list box of the line  
    // combo box. 
    if (SendMessage (hwndAddrCB, CB_GETCOUNT, 0, 0) != 0) 
    { 
        SendMessage (hwndAddrCB, CB_SETCURSEL, (WPARAM)dwCurrentItem, 0); 
        return TRUE; 
    } 
     
    return FALSE; 
} 
 
             
/*********************************************************************** 
             
FUNCTION:  
MakeCanonicalNum     
 
PURPOSE:    
Convert phone number to canonical address format. 
                 
***********************************************************************/ 
BOOL MakeCanonicalNum (LPTSTR lpszPhoneNum) 
{ 
    int index, 
        iLength = 0, 
        iStartPos = 0; 
     
    TCHAR szCanPhoneNum[TAPIMAXDESTADDRESSSIZE + 1]; 
     
    for (index = 0; index < (int) wcslen (lpszPhoneNum); ++index) 
    { 
        if (iswdigit (lpszPhoneNum[index])) 
        { 
            lpszPhoneNum[iLength] = lpszPhoneNum[index]; 
            iLength += 1; 
        } 
    } 
     
    // Terminate the string with NULL. 
    lpszPhoneNum[iLength] = '\0'; 
     
    // If the phone number length is less than 10, return FALSE. 
    if (iLength < 10) 
    { 
        if (lpszPhoneNum[0] == '1')   
        {                  
            ErrorBox (TEXT("The first digit can not be") 
                TEXT("\n1 for a local phone number.")); 
            return FALSE;       
        } 
         
        ErrorBox (TEXT("Invalid phone number.") 
            TEXT("\nEnter area code for ") 
            TEXT("\na local phone number.")); 
        return FALSE; 
    } 
    else 
    { 
        if (iLength == 10) 
        { 
            //Make the phone number in the format "+1 (xxx) xxx-xxxx" 
            wcscpy (szCanPhoneNum, TEXT("+1 ")); 
            szCanPhoneNum[3]  = '('; 
            szCanPhoneNum[4]  = lpszPhoneNum[iStartPos]; 
            szCanPhoneNum[5]  = lpszPhoneNum[iStartPos + 1]; 
            szCanPhoneNum[6]  = lpszPhoneNum[iStartPos + 2]; 
            szCanPhoneNum[7]  = ')'; 
            szCanPhoneNum[8]  = ' '; 
            szCanPhoneNum[9]  = lpszPhoneNum[iStartPos + 3]; 
            szCanPhoneNum[10] = lpszPhoneNum[iStartPos + 4]; 
            szCanPhoneNum[11] = lpszPhoneNum[iStartPos + 5]; 
            szCanPhoneNum[12] = '-'; 
            szCanPhoneNum[13] = lpszPhoneNum[iStartPos + 6]; 
            szCanPhoneNum[14] = lpszPhoneNum[iStartPos + 7]; 
            szCanPhoneNum[15] = lpszPhoneNum[iStartPos + 8]; 
            szCanPhoneNum[16] = lpszPhoneNum[iStartPos + 9]; 
            szCanPhoneNum[17] = '\0'; 
             
            // Copy the newly created phone number back to lpszPhoneNum. 
            wcscpy (lpszPhoneNum, szCanPhoneNum); 
             
            return TRUE; 
        } 
    } 
     
    if (iLength == 11) 
        if (lpszPhoneNum[0] != '1')  
        {                  
            ErrorBox (TEXT("The first digit must be a") 
                TEXT("\n1 for a long distance number.")); 
            return FALSE;       
        } 
        else 
        { 
            //Make the phone number in the format "+1 (xxx) xxx-xxxx" 
            szCanPhoneNum[0]  = '+'; 
            szCanPhoneNum[1]  = lpszPhoneNum[iStartPos]; 
            szCanPhoneNum[2]  = ' '; 
            szCanPhoneNum[3]  = '('; 
            szCanPhoneNum[4]  = lpszPhoneNum[iStartPos + 1]; 
            szCanPhoneNum[5]  = lpszPhoneNum[iStartPos + 2]; 
            szCanPhoneNum[6]  = lpszPhoneNum[iStartPos + 3]; 
            szCanPhoneNum[7]  = ')'; 
            szCanPhoneNum[8]  = ' '; 
            szCanPhoneNum[9]  = lpszPhoneNum[iStartPos + 4]; 
            szCanPhoneNum[10] = lpszPhoneNum[iStartPos + 5]; 
            szCanPhoneNum[11] = lpszPhoneNum[iStartPos + 6]; 
            szCanPhoneNum[12] = '-'; 
            szCanPhoneNum[13] = lpszPhoneNum[iStartPos + 7]; 
            szCanPhoneNum[14] = lpszPhoneNum[iStartPos + 8]; 
            szCanPhoneNum[15] = lpszPhoneNum[iStartPos + 9]; 
            szCanPhoneNum[16] = lpszPhoneNum[iStartPos + 10]; 
            szCanPhoneNum[17] = '\0'; 
             
            // Copy the newly created phone number back to lpszPhoneNum. 
            wcscpy (lpszPhoneNum, szCanPhoneNum); 
             
            return TRUE; 
        } 
         
        ErrorBox (TEXT("Invalid phone number, please check") 
            TEXT("\nthe number and enter again.")); 
         
        return FALSE; 
} 
// END CEDIALER.C